diff --git a/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm b/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm new file mode 100644 index 0000000000..87f890e0d5 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm @@ -0,0 +1,503 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"c" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/fulltile, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"d" = ( +/turf/closed/wall/r_wall/rust, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"e" = ( +/obj/machinery/defibrillator_mount/loaded, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"f" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/fulltile, +/turf/open/floor/plasteel/airless, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"g" = ( +/obj/structure/table, +/obj/item/device/flashlight/lamp, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"h" = ( +/obj/structure/table, +/obj/item/pen, +/obj/item/paper/fluff/ruins/exp_cloning/log, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"i" = ( +/obj/machinery/dna_scannernew, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"j" = ( +/obj/machinery/computer/prototype_cloning, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/paper/fluff/ruins/exp_cloning/manual, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"k" = ( +/obj/machinery/clonepod/experimental, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"l" = ( +/obj/effect/decal/cleanable/vomit/old, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"m" = ( +/obj/effect/decal/cleanable/cobweb/cobweb2, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"n" = ( +/obj/structure/sign/nanotrasen, +/turf/closed/wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"o" = ( +/obj/machinery/vending/snack/teal, +/turf/open/floor/plasteel/airless/floorgrime, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"p" = ( +/turf/open/floor/plasteel/airless/floorgrime, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"q" = ( +/obj/structure/sign/directions/science{ + dir = 8 + }, +/turf/closed/wall/r_wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"r" = ( +/obj/effect/decal/remains/human, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"s" = ( +/obj/machinery/iv_drip, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"t" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/bed, +/obj/item/bedsheet/medical, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"u" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"v" = ( +/turf/open/floor/plasteel/whiteblue/corner{ + dir = 4 + }, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"w" = ( +/obj/structure/chair/office{ + dir = 1 + }, +/turf/open/floor/plasteel/whiteblue/side{ + dir = 1 + }, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"x" = ( +/turf/open/floor/plasteel/whiteblue/side{ + dir = 1 + }, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"y" = ( +/obj/structure/chair/office{ + dir = 1 + }, +/turf/open/floor/plasteel/whiteblue, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"z" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/plasteel/whiteblue/corner{ + dir = 1 + }, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"A" = ( +/obj/structure/sign/departments/science, +/turf/closed/wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"B" = ( +/turf/open/floor/plasteel/airless, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"C" = ( +/turf/open/floor/plating/airless, +/area/space/nearstation) +"D" = ( +/obj/structure/chair/comfy{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"E" = ( +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"F" = ( +/obj/machinery/door/airlock/research/glass, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"G" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"H" = ( +/obj/machinery/door/airlock/research/glass, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"I" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"J" = ( +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"K" = ( +/obj/machinery/door/airlock/research/glass, +/turf/open/floor/plasteel/airless, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"L" = ( +/turf/open/floor/plating/airless{ + icon_state = "platingdmg1" + }, +/area/space/nearstation) +"M" = ( +/obj/structure/fluff/broken_flooring{ + name = "broken plating"; + icon_state = "plating"; + dir = 8 + }, +/turf/template_noop, +/area/space/nearstation) +"N" = ( +/obj/item/book/random/triple, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"O" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/bookcase/random/fiction, +/turf/open/floor/plasteel, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"P" = ( +/obj/structure/table/glass, +/obj/machinery/light, +/obj/structure/bedsheetbin, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"Q" = ( +/obj/structure/table/glass, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"R" = ( +/obj/structure/table/glass, +/obj/item/storage/firstaid/regular, +/obj/item/device/healthanalyzer{ + desc = "A prototype hand-held body scanner able to distinguish vital signs of the subject."; + name = "prototype health analyzer" + }, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"S" = ( +/obj/structure/table/glass, +/obj/item/storage/box/syringes, +/turf/open/floor/plasteel/white, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"T" = ( +/turf/closed/wall, +/area/ruin/space/has_grav/powered/ancient_shuttle) +"U" = ( +/turf/open/floor/plating/airless{ + icon_state = "platingdmg2" + }, +/area/space/nearstation) +"V" = ( +/turf/closed/wall/r_wall/rust, +/area/space/nearstation) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +c +c +c +c +c +a +a +"} +(4,1,1) = {" +a +a +c +r +D +N +c +a +a +"} +(5,1,1) = {" +a +a +c +s +E +E +c +a +a +"} +(6,1,1) = {" +a +a +d +t +E +O +d +a +a +"} +(7,1,1) = {" +a +a +d +b +F +d +d +a +a +"} +(8,1,1) = {" +a +a +a +b +G +b +a +a +a +"} +(9,1,1) = {" +a +a +d +d +H +b +b +a +a +"} +(10,1,1) = {" +a +b +b +u +I +I +c +a +a +"} +(11,1,1) = {" +a +c +g +v +J +J +c +a +a +"} +(12,1,1) = {" +a +c +h +w +J +J +d +a +a +"} +(13,1,1) = {" +a +d +i +x +J +P +b +a +a +"} +(14,1,1) = {" +a +b +j +y +J +Q +c +a +a +"} +(15,1,1) = {" +a +b +k +x +J +R +c +a +a +"} +(16,1,1) = {" +a +e +l +x +J +S +d +a +a +"} +(17,1,1) = {" +a +d +m +z +J +J +d +a +a +"} +(18,1,1) = {" +a +d +n +A +K +T +b +a +a +"} +(19,1,1) = {" +a +f +o +B +p +C +V +a +a +"} +(20,1,1) = {" +a +f +p +p +C +U +M +a +a +"} +(21,1,1) = {" +a +d +q +C +L +M +a +a +a +"} +(22,1,1) = {" +a +a +b +f +M +a +a +a +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +"} diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 44fcce6253..bb07582dae 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -82,19 +82,18 @@ #define NOBLOOD 6 #define NOTRANSSTING 7 #define MUTCOLORS_PARTSONLY 8 //Used if we want the mutant colour to be only used by mutant bodyparts. Don't combine this with MUTCOLORS, or it will be useless. -#define NOCRITDAMAGE 9 -#define NOZOMBIE 10 -#define DIGITIGRADE 11 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi) -#define NO_UNDERWEAR 12 -#define NOLIVER 13 -#define NOSTOMACH 14 -#define NO_DNA_COPY 15 -#define DRINKSBLOOD 16 -#define SPECIES_ORGANIC 17 -#define SPECIES_INORGANIC 18 -#define SPECIES_UNDEAD 19 -#define SPECIES_ROBOTIC 20 -#define NOEYES 21 +#define NOZOMBIE 9 +#define DIGITIGRADE 10 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi) +#define NO_UNDERWEAR 11 +#define NOLIVER 12 +#define NOSTOMACH 13 +#define NO_DNA_COPY 14 +#define DRINKSBLOOD 15 +#define SPECIES_ORGANIC 16 +#define SPECIES_INORGANIC 17 +#define SPECIES_UNDEAD 18 +#define SPECIES_ROBOTIC 19 +#define NOEYES 20 #define ORGAN_SLOT_BRAIN "brain" #define ORGAN_SLOT_APPENDIX "appendix" diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm index 97935d58b7..897d107939 100644 --- a/code/__DEFINES/radio.dm +++ b/code/__DEFINES/radio.dm @@ -1,55 +1,55 @@ -// Radios use a large variety of predefined frequencies. - -#define MIN_FREE_FREQ 1201 // ------------------------------------------------- -// Frequencies are always odd numbers and range from 1201 to 1599. - -#define FREQ_SYNDICATE 1213 // Nuke op comms frequency, dark brown -#define FREQ_CTF_RED 1215 // CTF red team comms frequency, red -#define FREQ_CTF_BLUE 1217 // CTF blue team comms frequency, blue -#define FREQ_CENTCOM 1337 // CentCom comms frequency, gray -#define FREQ_SUPPLY 1347 // Supply comms frequency, light brown -#define FREQ_SERVICE 1349 // Service comms frequency, green -#define FREQ_SCIENCE 1351 // Science comms frequency, plum -#define FREQ_COMMAND 1353 // Command comms frequency, gold -#define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue -#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange -#define FREQ_SECURITY 1359 // Security comms frequency, red - -#define FREQ_STATUS_DISPLAYS 1435 -#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers -#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers - -#define MIN_FREQ 1441 // ------------------------------------------------------ -// Only the 1441 to 1489 range is freely available for general conversation. -// This represents 1/8th of the available spectrum. - -#define FREQ_ATMOS_STORAGE 1441 -#define FREQ_NAV_BEACON 1445 -#define FREQ_AI_PRIVATE 1447 // AI private comms frequency, magenta -#define FREQ_PRESSURE_PLATE 1447 -#define FREQ_AIRLOCK_CONTROL 1449 -#define FREQ_ELECTROPACK 1449 -#define FREQ_MAGNETS 1449 -#define FREQ_LOCATOR_IMPLANT 1451 -#define FREQ_SIGNALER 1457 // the default for new signalers -#define FREQ_COMMON 1459 // Common comms frequency, dark green - -#define MAX_FREQ 1489 // ------------------------------------------------------ - -#define MAX_FREE_FREQ 1599 // ------------------------------------------------- - -// Transmission types. -#define TRANSMISSION_WIRE 0 // some sort of wired connection, not used -#define TRANSMISSION_RADIO 1 // electromagnetic radiation (default) -#define TRANSMISSION_SUBSPACE 2 // subspace transmission (headsets only) -#define TRANSMISSION_SUPERSPACE 3 // reaches independent (CentCom) radios only - -// Filter types, used as an optimization to avoid unnecessary proc calls. -#define RADIO_TO_AIRALARM "to_airalarm" -#define RADIO_FROM_AIRALARM "from_airalarm" -#define RADIO_SIGNALER "signaler" -#define RADIO_ATMOSIA "atmosia" -#define RADIO_AIRLOCK "airlock" -#define RADIO_MAGNETS "magnets" - -#define DEFAULT_SIGNALER_CODE 30 +// Radios use a large variety of predefined frequencies. + +#define MIN_FREE_FREQ 1201 // ------------------------------------------------- +// Frequencies are always odd numbers and range from 1201 to 1599. + +#define FREQ_SYNDICATE 1213 // Nuke op comms frequency, dark brown +#define FREQ_CTF_RED 1215 // CTF red team comms frequency, red +#define FREQ_CTF_BLUE 1217 // CTF blue team comms frequency, blue +#define FREQ_CENTCOM 1337 // CentCom comms frequency, gray +#define FREQ_SUPPLY 1347 // Supply comms frequency, light brown +#define FREQ_SERVICE 1349 // Service comms frequency, green +#define FREQ_SCIENCE 1351 // Science comms frequency, plum +#define FREQ_COMMAND 1353 // Command comms frequency, gold +#define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue +#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange +#define FREQ_SECURITY 1359 // Security comms frequency, red + +#define FREQ_STATUS_DISPLAYS 1435 +#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers +#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers + +#define MIN_FREQ 1441 // ------------------------------------------------------ +// Only the 1441 to 1489 range is freely available for general conversation. +// This represents 1/8th of the available spectrum. + +#define FREQ_ATMOS_STORAGE 1441 +#define FREQ_NAV_BEACON 1445 +#define FREQ_AI_PRIVATE 1447 // AI private comms frequency, magenta +#define FREQ_PRESSURE_PLATE 1447 +#define FREQ_AIRLOCK_CONTROL 1449 +#define FREQ_ELECTROPACK 1449 +#define FREQ_MAGNETS 1449 +#define FREQ_LOCATOR_IMPLANT 1451 +#define FREQ_SIGNALER 1457 // the default for new signalers +#define FREQ_COMMON 1459 // Common comms frequency, dark green + +#define MAX_FREQ 1489 // ------------------------------------------------------ + +#define MAX_FREE_FREQ 1599 // ------------------------------------------------- + +// Transmission types. +#define TRANSMISSION_WIRE 0 // some sort of wired connection, not used +#define TRANSMISSION_RADIO 1 // electromagnetic radiation (default) +#define TRANSMISSION_SUBSPACE 2 // subspace transmission (headsets only) +#define TRANSMISSION_SUPERSPACE 3 // reaches independent (CentCom) radios only + +// Filter types, used as an optimization to avoid unnecessary proc calls. +#define RADIO_TO_AIRALARM "to_airalarm" +#define RADIO_FROM_AIRALARM "from_airalarm" +#define RADIO_SIGNALER "signaler" +#define RADIO_ATMOSIA "atmosia" +#define RADIO_AIRLOCK "airlock" +#define RADIO_MAGNETS "magnets" + +#define DEFAULT_SIGNALER_CODE 30 diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm index cfce95a65f..e307e8dd69 100644 --- a/code/__DEFINES/sight.dm +++ b/code/__DEFINES/sight.dm @@ -1,30 +1,30 @@ -#define SEE_INVISIBLE_MINIMUM 5 - -#define INVISIBILITY_LIGHTING 20 - -#define SEE_INVISIBLE_LIVING 25 - -//#define SEE_INVISIBLE_LEVEL_ONE 35 //currently unused -//#define INVISIBILITY_LEVEL_ONE 35 //currently unused - -//#define SEE_INVISIBLE_LEVEL_TWO 45 //currently unused -//#define INVISIBILITY_LEVEL_TWO 45 //currently unused - -#define INVISIBILITY_OBSERVER 60 -#define SEE_INVISIBLE_OBSERVER 60 - -#define INVISIBILITY_MAXIMUM 100 //the maximum allowed for "real" objects - -#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects (e.g. spacevine_controller), things that are not really there. - -#define BORGMESON 1 -#define BORGTHERM 2 -#define BORGXRAY 4 -#define BORGMATERIAL 8 - -//for clothing visor toggles, these determine which vars to toggle -#define VISOR_FLASHPROTECT 1 -#define VISOR_TINT 2 -#define VISOR_VISIONFLAGS 4 //all following flags only matter for glasses -#define VISOR_DARKNESSVIEW 8 -#define VISOR_INVISVIEW 16 +#define SEE_INVISIBLE_MINIMUM 5 + +#define INVISIBILITY_LIGHTING 20 + +#define SEE_INVISIBLE_LIVING 25 + +//#define SEE_INVISIBLE_LEVEL_ONE 35 //currently unused +//#define INVISIBILITY_LEVEL_ONE 35 //currently unused + +//#define SEE_INVISIBLE_LEVEL_TWO 45 //currently unused +//#define INVISIBILITY_LEVEL_TWO 45 //currently unused + +#define INVISIBILITY_OBSERVER 60 +#define SEE_INVISIBLE_OBSERVER 60 + +#define INVISIBILITY_MAXIMUM 100 //the maximum allowed for "real" objects + +#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects (e.g. spacevine_controller), things that are not really there. + +#define BORGMESON 1 +#define BORGTHERM 2 +#define BORGXRAY 4 +#define BORGMATERIAL 8 + +//for clothing visor toggles, these determine which vars to toggle +#define VISOR_FLASHPROTECT 1 +#define VISOR_TINT 2 +#define VISOR_VISIONFLAGS 4 //all following flags only matter for glasses +#define VISOR_DARKNESSVIEW 8 +#define VISOR_INVISVIEW 16 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 6bc504d48a..854ea01114 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -21,6 +21,7 @@ #define TRAIT_SLEEPIMMUNE "sleep_immunity" #define TRAIT_PUSHIMMUNE "push_immunity" #define TRAIT_SHOCKIMMUNE "shock_immunity" +#define TRAIT_STABLEHEART "stable_heart" #define TRAIT_RESISTHEAT "resist_heat" #define TRAIT_RESISTCOLD "resist_cold" #define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure" @@ -38,6 +39,7 @@ #define TRAIT_NOBREATH "no_breath" #define TRAIT_ANTIMAGIC "anti_magic" #define TRAIT_HOLY "holy" +#define TRAIT_NOCRITDAMAGE "no_crit" #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" #define TRAIT_AGEUSIA "ageusia" @@ -71,4 +73,4 @@ #define TRAIT_HULK "hulk" #define STASIS_MUTE "stasis" #define GENETICS_SPELL "genetics_spell" -#define EYES_COVERED "eyes_covered" \ No newline at end of file +#define EYES_COVERED "eyes_covered" diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index eed23e0711..eea4088905 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -280,4 +280,10 @@ suffix = "mrow_thats_right.dmm" name = "Feline-Human Combination Den" description = "With heated debates over the legality of the catperson and their status in the workforce, there's always a place for the blackmarket to slip in for some cash. Whether the results \ - are morally sound or not is another issue entirely." \ No newline at end of file + are morally sound or not is another issue entirely." + +/datum/map_template/ruin/space/cloning_facility + id = "cloning_facility" + suffix = "cloning_facility.dmm" + name = "Ancient Cloning Lab" + description = "An experimental cloning lab snapped off from an ancient ship. The cloner model inside lacks many modern functionalities and security measures." \ No newline at end of file diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm index 0f57c0ce3b..13b9905874 100644 --- a/code/game/area/areas/ruins/space.dm +++ b/code/game/area/areas/ruins/space.dm @@ -466,4 +466,8 @@ /area/ruin/space/has_grav/powered/scp_294 name = "Abandoned SCP-294 Containment" + icon_state = "yellow" + +/area/ruin/space/has_grav/powered/ancient_shuttle + name = "Ancient Shuttle" icon_state = "yellow" \ No newline at end of file diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index b46706ce9f..048cac8326 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -29,6 +29,7 @@ var/datum/mind/clonemind var/grab_ghost_when = CLONER_MATURE_CLONE + var/internal_radio = TRUE var/obj/item/device/radio/radio var/radio_key = /obj/item/device/encryptionkey/headset_med var/radio_channel = "Medical" @@ -38,24 +39,17 @@ var/list/unattached_flesh var/flesh_number = 0 - // The "brine" is the reagents that are automatically added in small - // amounts to the occupant. - var/static/list/brine_types = list( - "salbutamol", // anti-oxyloss - "bicaridine", // NOBREATHE species take brute in crit - "corazone", // prevents cardiac arrest and liver failure damage - "mimesbane", // stops them gasping from lack of air. - "mutetoxin") // stops them from killing themselves BY DEATHWHISPERING INSIDE A CLONE POD NICE JOB BREAKING IT HERO /obj/machinery/clonepod/Initialize() . = ..() countdown = new(src) - radio = new(src) - radio.keyslot = new radio_key - radio.subspace_transmission = TRUE - radio.canhear_range = 0 - radio.recalculateChannels() + if(internal_radio) + radio = new(src) + radio.keyslot = new radio_key + radio.subspace_transmission = TRUE + radio.canhear_range = 0 + radio.recalculateChannels() /obj/machinery/clonepod/Destroy() go_out() @@ -116,7 +110,7 @@ /obj/machinery/clonepod/return_air() // We want to simulate the clone not being in contact with // the atmosphere, so we'll put them in a constant pressure - // nitrogen. They'll breathe through the chemicals we pump into them. + // nitrogen. They don't need to breathe while cloning anyway. var/static/datum/gas_mixture/immutable/cloner/GM //global so that there's only one instance made for all cloning pods if(!GM) GM = new @@ -184,7 +178,11 @@ icon_state = "pod_1" //Get the clone body ready maim_clone(H) - check_brine() // put in chemicals NOW to stop death via cardiac arrest + H.add_trait(TRAIT_STABLEHEART, "cloning") + H.add_trait(TRAIT_EMOTEMUTE, "cloning") + H.add_trait(TRAIT_MUTE, "cloning") + H.add_trait(TRAIT_NOBREATH, "cloning") + H.add_trait(TRAIT_NOCRITDAMAGE, "cloning") H.Unconscious(80) clonemind.transfer_to(H) @@ -219,8 +217,9 @@ else if(mob_occupant && (mob_occupant.loc == src)) if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes. connected_message("Clone Rejected: Deceased.") - SPEAK("The cloning of [mob_occupant.real_name] has been \ - aborted due to unrecoverable tissue failure.") + if(internal_radio) + SPEAK("The cloning of [mob_occupant.real_name] has been \ + aborted due to unrecoverable tissue failure.") go_out() mob_occupant.apply_vore_prefs() @@ -248,13 +247,12 @@ //Premature clones may have brain damage. mob_occupant.adjustBrainLoss(-((speed_coeff / 2) * dmg_mult)) - check_brine() - use_power(7500) //This might need tweaking. else if((mob_occupant.cloneloss <= (100 - heal_level))) connected_message("Cloning Process Complete.") - SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.") + if(internal_radio) + SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.") // If the cloner is upgraded to debugging high levels, sometimes // organs and limbs can be missing. @@ -356,6 +354,11 @@ if(!mob_occupant) return + mob_occupant.remove_trait(TRAIT_STABLEHEART, "cloning") + mob_occupant.remove_trait(TRAIT_EMOTEMUTE, "cloning") + mob_occupant.remove_trait(TRAIT_MUTE, "cloning") + mob_occupant.remove_trait(TRAIT_NOCRITDAMAGE, "cloning") + mob_occupant.remove_trait(TRAIT_NOBREATH, "cloning") if(grab_ghost_when == CLONER_MATURE_CLONE) mob_occupant.grab_ghost() @@ -459,15 +462,6 @@ flesh_number = unattached_flesh.len -/obj/machinery/clonepod/proc/check_brine() - // Clones are in a pickled bath of mild chemicals, keeping - // them alive, despite their lack of internal organs - for(var/bt in brine_types) - if(bt == "corazone" && occupant.reagents.get_reagent_amount(bt) < 2) - occupant.reagents.add_reagent(bt, 2)//pump it full of extra corazone as a safety, you can't OD on corazone. - else if(occupant.reagents.get_reagent_amount(bt) < 1) - occupant.reagents.add_reagent(bt, 1) - /* * Manual -- A big ol' manual. */ diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm new file mode 100644 index 0000000000..27618668fa --- /dev/null +++ b/code/game/machinery/exp_cloner.dm @@ -0,0 +1,297 @@ +//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead +/obj/machinery/clonepod/experimental + name = "experimental cloning pod" + desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations." + icon = 'icons/obj/machines/cloning.dmi' + icon_state = "pod_0" + req_access = null + circuit = /obj/item/circuitboard/machine/clonepod/experimental + internal_radio = FALSE + +//Start growing a human clone in the pod! +/obj/machinery/clonepod/experimental/growclone(clonename, ui, se, datum/species/mrace, list/features, factions) + if(panel_open) + return FALSE + if(mess || attempting) + return FALSE + + attempting = TRUE //One at a time!! + countdown.start() + + var/mob/living/carbon/human/H = new /mob/living/carbon/human(src) + + H.hardset_dna(ui, se, H.real_name, null, mrace, features) + + if(efficiency > 2) + var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) + H.dna.remove_mutation_group(unclean_mutations) + if(efficiency > 5 && prob(20)) + H.randmutvg() + if(efficiency < 3 && prob(50)) + var/mob/M = H.randmutb() + if(ismob(M)) + H = M + + H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment. + occupant = H + + if(!clonename) //to prevent null names + clonename = "clone ([rand(0,999)])" + H.real_name = clonename + + icon_state = "pod_1" + //Get the clone body ready + maim_clone(H) + H.add_trait(TRAIT_STABLEHEART, "cloning") + H.add_trait(TRAIT_EMOTEMUTE, "cloning") + H.add_trait(TRAIT_MUTE, "cloning") + H.add_trait(TRAIT_NOBREATH, "cloning") + H.add_trait(TRAIT_NOCRITDAMAGE, "cloning") + H.Unconscious(80) + + var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H) + if(LAZYLEN(candidates)) + var/mob/dead/observer/C = pick(candidates) + H.key = C.key + + if(grab_ghost_when == CLONER_FRESH_CLONE) + H.grab_ghost() + to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?
") + + if(grab_ghost_when == CLONER_MATURE_CLONE) + H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost + to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.") + + if(H) + H.faction |= factions + + H.set_cloned_appearance() + + H.suiciding = FALSE + attempting = FALSE + return TRUE + + +//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks. +/obj/machinery/computer/prototype_cloning + name = "prototype cloning console" + desc = "Used to operate an experimental cloner." + icon_screen = "dna" + icon_keyboard = "med_key" + circuit = /obj/item/circuitboard/computer/prototype_cloning + var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning. + var/list/pods //Linked experimental cloning pods + var/temp = "Inactive" + var/scantemp = "Ready to Scan" + var/loading = FALSE // Nice loading text + + light_color = LIGHT_COLOR_BLUE + +/obj/machinery/computer/prototype_cloning/Initialize() + . = ..() + updatemodules(TRUE) + +/obj/machinery/computer/prototype_cloning/Destroy() + if(pods) + for(var/P in pods) + DetachCloner(P) + pods = null + return ..() + +/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null) + if(pods) + for(var/P in pods) + var/obj/machinery/clonepod/experimental/pod = P + if(pod.is_operational() && !(pod.occupant || pod.mess)) + return pod + +/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner) + scanner = findscanner() + if(findfirstcloner && !LAZYLEN(pods)) + findcloner() + +/obj/machinery/computer/prototype_cloning/proc/findscanner() + var/obj/machinery/dna_scannernew/scannerf = null + + // Loop through every direction + for(var/direction in GLOB.cardinals) + // Try to find a scanner in that direction + scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction)) + // If found and operational, return the scanner + if (!isnull(scannerf) && scannerf.is_operational()) + return scannerf + + // If no scanner was found, it will return null + return null + +/obj/machinery/computer/prototype_cloning/proc/findcloner() + var/obj/machinery/clonepod/experimental/podf = null + for(var/direction in GLOB.cardinals) + podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction)) + if (!isnull(podf) && podf.is_operational()) + AttachCloner(podf) + +/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod) + if(!pod.connected) + pod.connected = src + LAZYADD(pods, pod) + +/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod) + pod.connected = null + LAZYREMOVE(pods, pod) + +/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/device/multitool)) + var/obj/item/device/multitool/P = W + + if(istype(P.buffer, /obj/machinery/clonepod/experimental)) + if(get_area(P.buffer) != get_area(src)) + to_chat(user, "-% Cannot link machines across power zones. Buffer cleared %-") + P.buffer = null + return + to_chat(user, "-% Successfully linked [P.buffer] with [src] %-") + var/obj/machinery/clonepod/experimental/pod = P.buffer + if(pod.connected) + pod.connected.DetachCloner(pod) + AttachCloner(pod) + else + P.buffer = src + to_chat(user, "-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-") + return + else + return ..() + +/obj/machinery/computer/prototype_cloning/attack_hand(mob/user) + if(..()) + return + interact(user) + +/obj/machinery/computer/prototype_cloning/interact(mob/user) + user.set_machine(src) + add_fingerprint(user) + + if(..()) + return + + updatemodules(TRUE) + + var/dat = "" + dat += "Refresh" + + dat += "

Cloning Pod Status

" + dat += "
[temp] 
" + + if (isnull(src.scanner) || !LAZYLEN(pods)) + dat += "

Modules

" + //dat += "Reload Modules" + if (isnull(src.scanner)) + dat += "ERROR: No Scanner detected!
" + if (!LAZYLEN(pods)) + dat += "ERROR: No Pod detected
" + + // Scan-n-Clone + if (!isnull(src.scanner)) + var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant) + + dat += "

Cloning

" + + dat += "
" + if(!scanner_occupant) + dat += "Scanner Unoccupied" + else if(loading) + dat += "[scanner_occupant] => Scanning..." + else + scantemp = "Ready to Clone" + dat += "[scanner_occupant] => [scantemp]" + dat += "
" + + if(scanner_occupant) + dat += "Clone" + dat += "
[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]" + else + dat += "Clone" + + var/datum/browser/popup = new(user, "cloning", "Prototype Cloning System Control") + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + +/obj/machinery/computer/prototype_cloning/Topic(href, href_list) + if(..()) + return + + if(loading) + return + + else if ((href_list["clone"]) && !isnull(scanner) && scanner.is_operational()) + scantemp = "" + + loading = TRUE + updateUsrDialog() + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) + say("Initiating scan...") + + spawn(20) + clone_occupant(scanner.occupant) + loading = FALSE + updateUsrDialog() + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + + //No locking an open scanner. + else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational()) + if ((!scanner.locked) && (scanner.occupant)) + scanner.locked = TRUE + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + else + scanner.locked = FALSE + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + + else if (href_list["refresh"]) + updateUsrDialog() + playsound(src, "terminal_type", 25, 0) + + add_fingerprint(usr) + updateUsrDialog() + return + +/obj/machinery/computer/prototype_cloning/proc/clone_occupant(occupant) + var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) + var/datum/dna/dna + if(ishuman(mob_occupant)) + var/mob/living/carbon/C = mob_occupant + dna = C.has_dna() + if(isbrain(mob_occupant)) + var/mob/living/brain/B = mob_occupant + dna = B.stored_dna + + if(!istype(dna)) + scantemp = "Unable to locate valid genetic data." + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + return + if((mob_occupant.has_trait(TRAIT_NOCLONE)) && (src.scanner.scan_level < 2)) + scantemp = "Subject no longer contains the fundamental materials required to create a living clone." + playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0) + return + + var/clone_species + if(dna.species) + clone_species = dna.species + else + var/datum/species/rando_race = pick(GLOB.roundstart_races) + clone_species = rando_race.type + + var/obj/machinery/clonepod/pod = GetAvailablePod() + //Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs. + if(!LAZYLEN(pods)) + temp = "No Clonepods detected." + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + else if(!pod) + temp = "No Clonepods available." + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + else if(pod.occupant) + temp = "Cloning cycle already in progress." + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + else + pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.struc_enzymes, clone_species, dna.features, mob_occupant.faction) + temp = "[mob_occupant.real_name] => Cloning data sent to pod." + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 24038d9c69..f3c047715e 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -111,6 +111,10 @@ name = "Cloning (Computer Board)" build_path = /obj/machinery/computer/cloning +/obj/item/circuitboard/computer/prototype_cloning + name = "Prototype Cloning (Computer Board)" + build_path = /obj/machinery/computer/prototype_cloning + /obj/item/circuitboard/computer/arcade/battle name = "Arcade Battle (Computer Board)" build_path = /obj/machinery/computer/arcade/battle diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index bb0357b4b1..5fc4bf7068 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -31,6 +31,10 @@ /obj/item/stock_parts/manipulator = 2, /obj/item/stack/sheet/glass = 1) +/obj/item/circuitboard/machine/clonepod/experimental + name = "Experimental Clone Pod (Machine Board)" + build_path = /obj/machinery/clonepod/experimental + /obj/item/circuitboard/machine/abductor name = "alien board (Report This)" icon_state = "abductor_mod" diff --git a/code/game/objects/structures/crates_lockers/closets/fitness.dm b/code/game/objects/structures/crates_lockers/closets/fitness.dm index e4dd78a8d6..2a17e0038c 100644 --- a/code/game/objects/structures/crates_lockers/closets/fitness.dm +++ b/code/game/objects/structures/crates_lockers/closets/fitness.dm @@ -1,65 +1,65 @@ -/obj/structure/closet/athletic_mixed - name = "athletic wardrobe" - desc = "It's a storage unit for athletic wear." - icon_door = "mixed" - -/obj/structure/closet/athletic_mixed/PopulateContents() - ..() - new /obj/item/clothing/under/shorts/purple(src) - new /obj/item/clothing/under/shorts/grey(src) - new /obj/item/clothing/under/shorts/black(src) - new /obj/item/clothing/under/shorts/red(src) - new /obj/item/clothing/under/shorts/blue(src) - new /obj/item/clothing/under/shorts/green(src) - new /obj/item/clothing/under/jabroni(src) - - -/obj/structure/closet/boxinggloves - name = "boxing gloves" - desc = "It's a storage unit for gloves for use in the boxing ring." - -/obj/structure/closet/boxinggloves/PopulateContents() - ..() - new /obj/item/clothing/gloves/boxing/blue(src) - new /obj/item/clothing/gloves/boxing/green(src) - new /obj/item/clothing/gloves/boxing/yellow(src) - new /obj/item/clothing/gloves/boxing(src) - - -/obj/structure/closet/masks - name = "mask closet" - desc = "IT'S A STORAGE UNIT FOR FIGHTER MASKS OLE!" - -/obj/structure/closet/masks/PopulateContents() - ..() - new /obj/item/clothing/mask/luchador(src) - new /obj/item/clothing/mask/luchador/rudos(src) - new /obj/item/clothing/mask/luchador/tecnicos(src) - - -/obj/structure/closet/lasertag/red - name = "red laser tag equipment" - desc = "It's a storage unit for laser tag equipment." - icon_door = "red" - -/obj/structure/closet/lasertag/red/PopulateContents() - ..() - for(var/i in 1 to 3) - new /obj/item/gun/energy/laser/redtag(src) - for(var/i in 1 to 3) - new /obj/item/clothing/suit/redtag(src) - new /obj/item/clothing/head/helmet/redtaghelm(src) - - -/obj/structure/closet/lasertag/blue - name = "blue laser tag equipment" - desc = "It's a storage unit for laser tag equipment." - icon_door = "blue" - -/obj/structure/closet/lasertag/blue/PopulateContents() - ..() - for(var/i in 1 to 3) - new /obj/item/gun/energy/laser/bluetag(src) - for(var/i in 1 to 3) - new /obj/item/clothing/suit/bluetag(src) +/obj/structure/closet/athletic_mixed + name = "athletic wardrobe" + desc = "It's a storage unit for athletic wear." + icon_door = "mixed" + +/obj/structure/closet/athletic_mixed/PopulateContents() + ..() + new /obj/item/clothing/under/shorts/purple(src) + new /obj/item/clothing/under/shorts/grey(src) + new /obj/item/clothing/under/shorts/black(src) + new /obj/item/clothing/under/shorts/red(src) + new /obj/item/clothing/under/shorts/blue(src) + new /obj/item/clothing/under/shorts/green(src) + new /obj/item/clothing/under/jabroni(src) + + +/obj/structure/closet/boxinggloves + name = "boxing gloves" + desc = "It's a storage unit for gloves for use in the boxing ring." + +/obj/structure/closet/boxinggloves/PopulateContents() + ..() + new /obj/item/clothing/gloves/boxing/blue(src) + new /obj/item/clothing/gloves/boxing/green(src) + new /obj/item/clothing/gloves/boxing/yellow(src) + new /obj/item/clothing/gloves/boxing(src) + + +/obj/structure/closet/masks + name = "mask closet" + desc = "IT'S A STORAGE UNIT FOR FIGHTER MASKS OLE!" + +/obj/structure/closet/masks/PopulateContents() + ..() + new /obj/item/clothing/mask/luchador(src) + new /obj/item/clothing/mask/luchador/rudos(src) + new /obj/item/clothing/mask/luchador/tecnicos(src) + + +/obj/structure/closet/lasertag/red + name = "red laser tag equipment" + desc = "It's a storage unit for laser tag equipment." + icon_door = "red" + +/obj/structure/closet/lasertag/red/PopulateContents() + ..() + for(var/i in 1 to 3) + new /obj/item/gun/energy/laser/redtag(src) + for(var/i in 1 to 3) + new /obj/item/clothing/suit/redtag(src) + new /obj/item/clothing/head/helmet/redtaghelm(src) + + +/obj/structure/closet/lasertag/blue + name = "blue laser tag equipment" + desc = "It's a storage unit for laser tag equipment." + icon_door = "blue" + +/obj/structure/closet/lasertag/blue/PopulateContents() + ..() + for(var/i in 1 to 3) + new /obj/item/gun/energy/laser/bluetag(src) + for(var/i in 1 to 3) + new /obj/item/clothing/suit/bluetag(src) new /obj/item/clothing/head/helmet/bluetaghelm(src) \ No newline at end of file diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 5e06851e58..2ffe64f327 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -1,142 +1,142 @@ -/obj/item/device/assembly/mousetrap - name = "mousetrap" - desc = "A handy little spring-loaded trap for catching pesty rodents." - icon_state = "mousetrap" - materials = list(MAT_METAL=100) - attachable = 1 - var/armed = 0 - - -/obj/item/device/assembly/mousetrap/examine(mob/user) - ..() - if(armed) - to_chat(user, "The mousetrap is armed!") - else - to_chat(user, "The mousetrap is not armed.") - -/obj/item/device/assembly/mousetrap/activate() - if(..()) - armed = !armed - if(!armed) - if(ishuman(usr)) - var/mob/living/carbon/human/user = usr - if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) - to_chat(user, "Your hand slips, setting off the trigger!") - pulse(0) - update_icon() - if(usr) - playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) - -/obj/item/device/assembly/mousetrap/describe() - return "The pressure switch is [armed?"primed":"safe"]." - -/obj/item/device/assembly/mousetrap/update_icon() - if(armed) - icon_state = "mousetraparmed" - else - icon_state = "mousetrap" - if(holder) - holder.update_icon() - -/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet") - if(!armed) - return - var/obj/item/bodypart/affecting = null - if(ishuman(target)) - var/mob/living/carbon/human/H = target - if(H.has_trait(TRAIT_PIERCEIMMUNE)) - playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) - armed = 0 - update_icon() - pulse(0) - return 0 - switch(type) - if("feet") - if(!H.shoes) - affecting = H.get_bodypart(pick("l_leg", "r_leg")) - H.Knockdown(60) - if("l_hand", "r_hand") - if(!H.gloves) - affecting = H.get_bodypart(type) - H.Stun(60) - if(affecting) - if(affecting.receive_damage(1, 0)) - H.update_damage_overlays() - else if(ismouse(target)) - var/mob/living/simple_animal/mouse/M = target - visible_message("SPLAT!") - M.splat() - playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) - armed = 0 - update_icon() - pulse(0) - - -/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user) - if(!armed) - to_chat(user, "You arm [src].") - else - if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) - var/which_hand = "l_hand" - if(!(user.active_hand_index % 2)) - which_hand = "r_hand" - triggered(user, which_hand) - user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ - "You accidentally trigger [src]!") - return - to_chat(user, "You disarm [src].") - armed = !armed - update_icon() - playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) - - -/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user) - if(armed) - if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) - var/which_hand = "l_hand" - if(!(user.active_hand_index % 2)) - which_hand = "r_hand" - triggered(user, which_hand) - user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ - "You accidentally trigger [src]!") - return - ..() - - -/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj) - if(armed) - if(ismob(AM)) - var/mob/MM = AM - if(!(MM.movement_type & FLYING)) - if(ishuman(AM)) - var/mob/living/carbon/H = AM - if(H.m_intent == MOVE_INTENT_RUN) - triggered(H) - H.visible_message("[H] accidentally steps on [src].", \ - "You accidentally step on [src]") - else if(ismouse(MM)) - triggered(MM) - else if(AM.density) // For mousetrap grenades, set off by anything heavy - triggered(AM) - ..() - - -/obj/item/device/assembly/mousetrap/on_found(mob/finder) - if(armed) - finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \ - "You accidentally trigger [src]!") - triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand") - return 1 //end the search! - return 0 - - -/obj/item/device/assembly/mousetrap/hitby(A as mob|obj) - if(!armed) - return ..() - visible_message("[src] is triggered by [A].") - triggered(null) - - -/obj/item/device/assembly/mousetrap/armed - icon_state = "mousetraparmed" - armed = 1 +/obj/item/device/assembly/mousetrap + name = "mousetrap" + desc = "A handy little spring-loaded trap for catching pesty rodents." + icon_state = "mousetrap" + materials = list(MAT_METAL=100) + attachable = 1 + var/armed = 0 + + +/obj/item/device/assembly/mousetrap/examine(mob/user) + ..() + if(armed) + to_chat(user, "The mousetrap is armed!") + else + to_chat(user, "The mousetrap is not armed.") + +/obj/item/device/assembly/mousetrap/activate() + if(..()) + armed = !armed + if(!armed) + if(ishuman(usr)) + var/mob/living/carbon/human/user = usr + if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) + to_chat(user, "Your hand slips, setting off the trigger!") + pulse(0) + update_icon() + if(usr) + playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) + +/obj/item/device/assembly/mousetrap/describe() + return "The pressure switch is [armed?"primed":"safe"]." + +/obj/item/device/assembly/mousetrap/update_icon() + if(armed) + icon_state = "mousetraparmed" + else + icon_state = "mousetrap" + if(holder) + holder.update_icon() + +/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet") + if(!armed) + return + var/obj/item/bodypart/affecting = null + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.has_trait(TRAIT_PIERCEIMMUNE)) + playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) + armed = 0 + update_icon() + pulse(0) + return 0 + switch(type) + if("feet") + if(!H.shoes) + affecting = H.get_bodypart(pick("l_leg", "r_leg")) + H.Knockdown(60) + if("l_hand", "r_hand") + if(!H.gloves) + affecting = H.get_bodypart(type) + H.Stun(60) + if(affecting) + if(affecting.receive_damage(1, 0)) + H.update_damage_overlays() + else if(ismouse(target)) + var/mob/living/simple_animal/mouse/M = target + visible_message("SPLAT!") + M.splat() + playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) + armed = 0 + update_icon() + pulse(0) + + +/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user) + if(!armed) + to_chat(user, "You arm [src].") + else + if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) + var/which_hand = "l_hand" + if(!(user.active_hand_index % 2)) + which_hand = "r_hand" + triggered(user, which_hand) + user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + return + to_chat(user, "You disarm [src].") + armed = !armed + update_icon() + playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) + + +/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user) + if(armed) + if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50)) + var/which_hand = "l_hand" + if(!(user.active_hand_index % 2)) + which_hand = "r_hand" + triggered(user, which_hand) + user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + return + ..() + + +/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj) + if(armed) + if(ismob(AM)) + var/mob/MM = AM + if(!(MM.movement_type & FLYING)) + if(ishuman(AM)) + var/mob/living/carbon/H = AM + if(H.m_intent == MOVE_INTENT_RUN) + triggered(H) + H.visible_message("[H] accidentally steps on [src].", \ + "You accidentally step on [src]") + else if(ismouse(MM)) + triggered(MM) + else if(AM.density) // For mousetrap grenades, set off by anything heavy + triggered(AM) + ..() + + +/obj/item/device/assembly/mousetrap/on_found(mob/finder) + if(armed) + finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \ + "You accidentally trigger [src]!") + triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand") + return 1 //end the search! + return 0 + + +/obj/item/device/assembly/mousetrap/hitby(A as mob|obj) + if(!armed) + return ..() + visible_message("[src] is triggered by [A].") + triggered(null) + + +/obj/item/device/assembly/mousetrap/armed + icon_state = "mousetraparmed" + armed = 1 diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 5e4db79e89..030501066e 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -97,7 +97,7 @@ if(!L) if(health >= HEALTH_THRESHOLD_CRIT) adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) - else if(!(NOCRITDAMAGE in dna.species.species_traits)) + else if(!has_trait(TRAIT_NOCRITDAMAGE)) adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) failed_last_breath = 1 @@ -337,8 +337,8 @@ if(!undergoing_cardiac_arrest()) return - // Cardiac arrest, unless corazone - if(reagents.get_reagent_amount("corazone")) + // Cardiac arrest, unless heart is stabilized + if(has_trait(TRAIT_STABLEHEART)) return if(we_breath) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 0c5f68d9ba..14e301a692 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -866,7 +866,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.setOxyLoss(0) H.losebreath = 0 - var/takes_crit_damage = (!(NOCRITDAMAGE in species_traits)) + var/takes_crit_damage = (!H.has_trait(TRAIT_NOCRITDAMAGE)) if((H.health < HEALTH_THRESHOLD_CRIT) && takes_crit_damage) H.adjustBruteLoss(1) diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm index 7c4143ec6a..552e413f4d 100644 --- a/code/modules/mob/living/carbon/human/species_types/corporate.dm +++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm @@ -1,20 +1,20 @@ -/datum/species/corporate - name = "Corporate Agent" - id = "agent" - hair_alpha = 0 - say_mod = "declares" - speedmod = -2//Fast - brutemod = 0.7//Tough against firearms - burnmod = 0.65//Tough against lasers - coldmod = 0 - heatmod = 0.5//it's a little tough to burn them to death not as hard though. - punchdamagelow = 20 - punchdamagehigh = 30//they are inhumanly strong - punchstunthreshold = 25 - attack_verb = "smash" - attack_sound = 'sound/weapons/resonator_blast.ogg' - blacklisted = 1 - use_skintones = 0 - species_traits = list(SPECIES_ORGANIC,NOBLOOD,EYECOLOR) - inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) - sexes = 0 +/datum/species/corporate + name = "Corporate Agent" + id = "agent" + hair_alpha = 0 + say_mod = "declares" + speedmod = -2//Fast + brutemod = 0.7//Tough against firearms + burnmod = 0.65//Tough against lasers + coldmod = 0 + heatmod = 0.5//it's a little tough to burn them to death not as hard though. + punchdamagelow = 20 + punchdamagehigh = 30//they are inhumanly strong + punchstunthreshold = 25 + attack_verb = "smash" + attack_sound = 'sound/weapons/resonator_blast.ogg' + blacklisted = 1 + use_skintones = 0 + species_traits = list(SPECIES_ORGANIC,NOBLOOD,EYECOLOR) + inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) + sexes = 0 diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 5e5c77ee33..0cf7190420 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -436,10 +436,10 @@ L.damage += d /mob/living/carbon/proc/liver_failure() - if(reagents.get_reagent_amount("corazone"))//corazone is processed here an not in the liver because a failing liver can't metabolize reagents - reagents.remove_reagent("corazone", 0.4) //corazone slowly deletes itself. + reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE) + if(has_trait(TRAIT_STABLEHEART)) return - adjustToxLoss(8, TRUE, TRUE) + adjustToxLoss(8, TRUE, TRUE) if(prob(30)) to_chat(src, "You feel confused and nauseous...")//actual symptoms of liver failure diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 0f3ac0e1bc..5735463af2 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -251,7 +251,7 @@ R.handle_reactions() return amount -/datum/reagents/proc/metabolize(mob/living/carbon/C, can_overdose = 0) +/datum/reagents/proc/metabolize(mob/living/carbon/C, can_overdose = FALSE, liverless = FALSE) var/list/cached_reagents = reagent_list var/list/cached_addictions = addiction_list if(C) @@ -261,6 +261,8 @@ var/datum/reagent/R = reagent if(QDELETED(R.holder)) continue + if(liverless && !R.self_consuming) //need to be metabolized + continue if(!C) C = R.holder.my_atom if(C && R) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 4ca1efa4e7..70bb594c8b 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -31,6 +31,7 @@ var/addiction_threshold = 0 var/addiction_stage = 0 var/overdosed = 0 // You fucked up and this is now triggering its overdose effects, purge that shit quick. + var/self_consuming = FALSE /datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references . = ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 2552bb7c8d..a3726897b3 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -1192,6 +1192,7 @@ id = "corazone" description = "A medication used to treat pain, fever, and inflammation, along with heart attacks." color = "#F5F5F5" + self_consuming = TRUE /datum/reagent/medicine/muscle_stimulant name = "Muscle Stimulant" diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 2eed6c33d5..e77d87c5b6 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -808,6 +808,7 @@ toxpwr = 1 var/acidpwr = 10 //the amount of protection removed from the armour taste_description = "acid" + self_consuming = TRUE /datum/reagent/toxin/acid/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume) if(!istype(C)) diff --git a/code/modules/ruins/spaceruin_code/cloning_lab.dm b/code/modules/ruins/spaceruin_code/cloning_lab.dm new file mode 100644 index 0000000000..1e372f1fa4 --- /dev/null +++ b/code/modules/ruins/spaceruin_code/cloning_lab.dm @@ -0,0 +1,35 @@ +/obj/item/paper/fluff/ruins/exp_cloning/manual + name = "paper - 'H-11 Cloning Apparatus Manual" + info = {"

Getting Started

+ Congratulations, you are testing the H-11 experimental cloning device!
+ Using the H-11 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the clone option to initiate cloning!
+ That's all there is to it!
+ Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.
+

The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times are roughly 90 seconds. + The cloning pod may be unlocked early after initial maturation is complete.


+ Please note that resulting clones will have a DEVELOPMENTAL DEFECT as a result of genetic drift. We hope to reduce this through further testing.
+ Clones may also experience memory loss and radical changes in personality as a result of the cloning process.

+
+ This technology produced under license from Thinktronic Systems, LTD."} + +/obj/item/paper/fluff/ruins/exp_cloning/log + name = "experiment log" + info = {"

Day 1

+ We are very excited to be part of the first crew of the SC Irmanda!
+ This ship is made to test an innovative FTL technology. I had some concerns at first, \ + but the engineers assure me that it is safe and there is absolutely no risk of the external wings breaking off from the acceleration.
+ We've been tasked with testing the latest model of the Thinktronic Cloning Pod. We'll stay in dock for a week before launching, but we're going to get started right away. \ + If the engine is as fast as they say, we might not have the time to run all the routine tests on the cloned subject!
+
+

Day 2

+ We cloned an unknown corpse that was given to us by the medical crew. The genetic replication is good enough to let the subject survive outside of the pod, \ + but the cellular damage remains a concern for his long-term survival. For safety we will be keeping him in quarantine.
+ We left him some books, but clearly we were too optimistic about his mental faculties. His brain seems to suffer from the same cloning decay that was caused by \ + the previous models. We will run further tests to see if there are improvements.
+

Day 4

+ It seems we'll be launching even sooner than expected! Apparently the press is starting to lose interest, so we have to cut short the pre-flight checks \ + and give them something to talk about. Hopefully this will end up with increased funding...
+ The crew has all been invited to the main hall, where we have seats for the initial FTL acceleration. Unfortunately the clone cannot leave the quarantine room \ + without risking infection, so we will strap him into the bed and hope for the best. We can grow another clone if anything goes wrong, anyway. +
+ Professor Galen Linkovich"} \ No newline at end of file diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 1aff20b81a..737ffbe6e8 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -68,17 +68,15 @@ /obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H) if((H.status_flags & GODMODE)) return - - var/species_traits = list() - if(H && H.dna && H.dna.species && H.dna.species.species_traits) - species_traits = H.dna.species.species_traits + if(H.has_trait(TRAIT_NOBREATH)) + return if(!breath || (breath.total_moles() == 0)) if(H.reagents.has_reagent(crit_stabilizing_reagent)) return if(H.health >= HEALTH_THRESHOLD_CRIT) H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) - else if(!(NOCRITDAMAGE in species_traits)) + else if(!H.has_trait(TRAIT_NOCRITDAMAGE)) H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) H.failed_last_breath = TRUE diff --git a/tgstation.dme b/tgstation.dme index f6f772f8c8..70fc644736 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -542,6 +542,7 @@ #include "code\game\machinery\dna_scanner.dm" #include "code\game\machinery\doppler_array.dm" #include "code\game\machinery\droneDispenser.dm" +#include "code\game\machinery\exp_cloner.dm" #include "code\game\machinery\firealarm.dm" #include "code\game\machinery\flasher.dm" #include "code\game\machinery\gulag_item_reclaimer.dm" @@ -2408,6 +2409,7 @@ #include "code\modules\ruins\spaceruin_code\asteroid4.dm" #include "code\modules\ruins\spaceruin_code\bigderelict1.dm" #include "code\modules\ruins\spaceruin_code\caravanambush.dm" +#include "code\modules\ruins\spaceruin_code\cloning_lab.dm" #include "code\modules\ruins\spaceruin_code\crashedclownship.dm" #include "code\modules\ruins\spaceruin_code\crashedship.dm" #include "code\modules\ruins\spaceruin_code\deepstorage.dm"