diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
index 6893a41517..1ea3f19c62 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
@@ -167,7 +167,7 @@
/area/ruin/unpowered/xenonest)
"aM" = (
/obj/structure/alien/weeds,
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"aQ" = (
@@ -260,7 +260,7 @@
/obj/structure/stone_tile/cracked{
dir = 1
},
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/indestructible/boss/air,
/area/ruin/unpowered/xenonest)
"be" = (
@@ -381,7 +381,7 @@
/obj/structure/stone_tile{
dir = 1
},
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/indestructible/boss/air,
/area/ruin/unpowered/xenonest)
"bs" = (
@@ -439,7 +439,7 @@
/obj/structure/stone_tile{
dir = 8
},
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/indestructible/boss/air,
/area/ruin/unpowered/xenonest)
"by" = (
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
index 945ea515c7..fec70b215e 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
@@ -279,6 +279,7 @@
},
/turf/open/floor/plasteel/freezer,
/area/ruin/powered/seedvault)
+
(1,1,1) = {"
a
a
diff --git a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
index f1a3005ce1..9c273f4d75 100644
--- a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
+++ b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
@@ -1288,7 +1288,7 @@
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/derelictoutpost/cargobay)
"cV" = (
-/obj/effect/decal/cleanable/xenoblood/xsplatter,
+/obj/effect/decal/cleanable/blood/splatter/xeno,
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/derelictoutpost/cargobay)
"cW" = (
@@ -1525,7 +1525,7 @@
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/derelictoutpost/cargobay)
"dq" = (
-/obj/effect/decal/cleanable/xenoblood/xsplatter,
+/obj/effect/decal/cleanable/blood/splatter/xeno,
/obj/structure/alien/weeds{
color = "#4BAE56";
desc = "A thick gelatinous surface covers the floor. Someone get the golashes.";
diff --git a/_maps/RandomZLevels/Academy.dmm b/_maps/RandomZLevels/Academy.dmm
index 29bd7d0526..2f08d9a29e 100644
--- a/_maps/RandomZLevels/Academy.dmm
+++ b/_maps/RandomZLevels/Academy.dmm
@@ -3830,7 +3830,7 @@
/turf/open/floor/engine/cult,
/area/awaymission/academy/academycellar)
"kY" = (
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/floor/engine/cult,
/area/awaymission/academy/academycellar)
"kZ" = (
diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm
index a25808d933..d50480c381 100644
--- a/_maps/RandomZLevels/caves.dmm
+++ b/_maps/RandomZLevels/caves.dmm
@@ -873,7 +873,7 @@
/obj/structure/window/reinforced{
dir = 4
},
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/floor/plating{
initial_gas_mix = "n2=23;o2=14"
},
@@ -945,7 +945,7 @@
/area/awaymission/caves/research)
"cN" = (
/obj/machinery/door/window/eastleft,
-/obj/effect/decal/cleanable/xenoblood/xgibs,
+/obj/effect/decal/cleanable/blood/gibs/xeno,
/turf/open/floor/plating{
initial_gas_mix = "n2=23;o2=14"
},
@@ -1015,7 +1015,7 @@
},
/area/awaymission/caves/BMP_asteroid/level_two)
"cV" = (
-/obj/effect/decal/cleanable/xenoblood/xgibs,
+/obj/effect/decal/cleanable/blood/gibs/xeno,
/turf/open/floor/plating{
initial_gas_mix = "n2=23;o2=14"
},
diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm
index 7edc7b4518..c251a338a5 100644
--- a/_maps/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/RandomZLevels/moonoutpost19.dmm
@@ -5597,8 +5597,8 @@
},
/area/awaymission/moonoutpost19/arrivals)
"kK" = (
-/obj/effect/decal/cleanable/xenoblood,
-/obj/effect/decal/cleanable/xenoblood/xgibs,
+/obj/effect/decal/cleanable/blood/xeno,
+/obj/effect/decal/cleanable/blood/gibs/xeno,
/obj/effect/turf_decal/tile/bar,
/obj/effect/turf_decal/tile/bar{
dir = 1
@@ -5608,7 +5608,7 @@
},
/area/awaymission/moonoutpost19/arrivals)
"kL" = (
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/obj/effect/decal/remains/xeno{
desc = "They look like the remains of something... alien. The front of skull appears to have been completely obliterated."
},
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 9c944ee1b7..125da46b81 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -34753,12 +34753,7 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bCO" = (
-/obj/structure/table,
-/obj/item/storage/box/bodybags{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/storage/box/rxglasses,
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bCP" = (
@@ -36538,6 +36533,11 @@
"bGR" = (
/obj/structure/table,
/obj/item/hand_labeler,
+/obj/item/storage/box/rxglasses,
+/obj/item/storage/box/bodybags{
+ pixel_x = 3;
+ pixel_y = 3
+ },
/obj/item/gun/syringe,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index aed08f5d8d..79b7561ebb 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -89232,7 +89232,7 @@
/area/maintenance/port)
"cTz" = (
/obj/effect/decal/remains/xeno,
-/obj/effect/decal/cleanable/xenoblood,
+/obj/effect/decal/cleanable/blood/xeno,
/turf/open/floor/circuit/green,
/area/science/xenobiology)
"cTA" = (
@@ -93013,10 +93013,10 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"cZK" = (
-/obj/item/twohanded/required/kirbyplants/random,
/obj/effect/turf_decal/tile/blue{
dir = 4
},
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"cZL" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 43c8b1155b..522d9801ca 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -56605,11 +56605,6 @@
/turf/open/floor/plasteel/dark,
/area/medical/sleeper)
"cfK" = (
-/obj/structure/table,
-/obj/item/paper_bin{
- pixel_x = -2;
- pixel_y = 4
- },
/obj/machinery/light_switch{
pixel_x = 11;
pixel_y = 23
@@ -56624,6 +56619,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/dark,
/area/medical/sleeper)
"cfL" = (
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 24a5cd834a..a87c17836c 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -30073,10 +30073,8 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone3)
"bbs" = (
-/obj/item/twohanded/required/kirbyplants{
- icon_state = "plant-21"
- },
/obj/effect/turf_decal/tile/blue,
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone3)
"bbt" = (
@@ -43077,7 +43075,7 @@
/turf/open/floor/plasteel,
/area/engine/atmos)
"vsf" = (
-/obj/effect/decal/cleanable/xenoblood/xgibs,
+/obj/effect/decal/cleanable/blood/gibs/xeno,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index e900a4597c..698eb6cd5a 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -31871,14 +31871,11 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
-/obj/item/twohanded/required/kirbyplants{
- icon_state = "plant-21";
- pixel_y = 3
- },
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bwG" = (
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index d966c73d23..3301def4a1 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -93,12 +93,6 @@
#define isgenital(A) (istype(A, /obj/item/organ/genital))
#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
-#define isipcperson(A) (is_species(A, /datum/species/ipc))
-#define ismammal(A) (is_species(A, /datum/species/mammal))
-#define isavian(A) (is_species(A, /datum/species/avian))
-#define isaquatic(A) (is_species(A, /datum/species/aquatic))
-#define isinsect(A) (is_species(A, /datum/species/insect))
-#define isxenoperson(A) (is_species(A, /datum/species/xeno))
#define CITADEL_MENTOR_OOC_COLOUR "#224724"
diff --git a/code/__DEFINES/cleaning.dm b/code/__DEFINES/cleaning.dm
index c4db590e90..6049fd7918 100644
--- a/code/__DEFINES/cleaning.dm
+++ b/code/__DEFINES/cleaning.dm
@@ -5,8 +5,3 @@
#define CLEAN_STRONG 4 // Industrial strength
#define CLEAN_IMPRESSIVE 5 // Cleaning strong enough your granny would be proud
#define CLEAN_GOD 6 // Cleans things spotless down to the atomic structure
-
-//How strong things have to be to wipe forensic evidence...
-#define CLEAN_STRENGTH_FINGERPRINTS CLEAN_IMPRESSIVE
-#define CLEAN_STRENGTH_BLOOD CLEAN_WEAK
-#define CLEAN_STRENGTH_FIBERS CLEAN_IMPRESSIVE
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index c2482f6fbf..4e03ab3ebf 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -7,6 +7,7 @@
#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src)
#define COMPONENT_INCOMPATIBLE 1
+#define COMPONENT_NOTRANSFER 2
// How multiple components of the exact same type are handled in the same datum
@@ -225,6 +226,8 @@
#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
#define COMSIG_COMPONENT_CLEAN_ACT "clean_act" //called on an object to clean it of cleanables. Usualy with soap: (num/strength)
+//Blood color
+#define COMSIG_BLOOD_COLOR "blood_DNA_to_color" //RGB blood stuff
//Food
#define COMSIG_FOOD_EATEN "food_eaten" //from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm
index ef96b83cc8..16d763606b 100644
--- a/code/__DEFINES/footsteps.dm
+++ b/code/__DEFINES/footsteps.dm
@@ -15,6 +15,15 @@
//misc footstep sounds
#define FOOTSTEP_GENERIC_HEAVY "heavy"
+#define FOOTPRINT_SHOE "shoe"
+#define FOOTPRINT_FOOT "foot"
+#define FOOTPRINT_PAW "paw"
+#define FOOTPRINT_CLAW "claw"
+#define FOOTPRINT_WHEEL "wheels"
+#define FOOTPRINT_TRAIL "trails_"
+#define FOOTPRINT_SNAKE "snake"
+#define FOOTPRINT_DRAG "drag"
+
/*
id = list(
diff --git a/code/__DEFINES/forensics.dm b/code/__DEFINES/forensics.dm
deleted file mode 100644
index bb512edcde..0000000000
--- a/code/__DEFINES/forensics.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-#define IF_HAS_BLOOD_DNA(__thing) GET_COMPONENT_FROM(__FR##__thing, /datum/component/forensics, __thing); if(__FR##__thing && length(__FR##__thing.blood_DNA))
-#define IF_HAS_BLOOD_DNA_AND(__thing, __conditions...) GET_COMPONENT_FROM(__FR##__thing, /datum/component/forensics, __thing); if(__FR##__thing && length(__FR##__thing.blood_DNA) && (##__conditions))
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 1709714904..9f69da0154 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -61,6 +61,15 @@
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
#define isdwarf(A) (is_species(A, /datum/species/dwarf))
+// Citadel specific species
+#define isipcperson(A) (is_species(A, /datum/species/ipc))
+#define ismammal(A) (is_species(A, /datum/species/mammal))
+#define isavian(A) (is_species(A, /datum/species/avian))
+#define isaquatic(A) (is_species(A, /datum/species/aquatic))
+#define isinsect(A) (is_species(A, /datum/species/insect))
+#define isxenoperson(A) (is_species(A, /datum/species/xeno))
+#define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime))
+
//more carbon mobs
#define ismonkey(A) (istype(A, /mob/living/carbon/monkey))
@@ -176,6 +185,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
#define iscameramob(A) (istype(A, /mob/camera))
+#define isaicamera(A) (istype(A, /mob/camera/aiEye))
+
#define iseminence(A) (istype(A, /mob/camera/eminence))
//Footstep helpers
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index bccf1f28dd..94a189ff07 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -171,12 +171,22 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
#define BLOOD_LOSS_IN_SPREAD 20
//Bloody shoe blood states
-#define BLOOD_STATE_HUMAN "blood"
-#define BLOOD_STATE_XENO "xeno"
+#define BLOOD_STATE_BLOOD "blood"
#define BLOOD_STATE_OIL "oil"
#define BLOOD_STATE_NOT_BLOODY "no blood whatsoever"
#define BLOOD_AMOUNT_PER_DECAL 20
+//Blood Decal Colors
+#define BLOOD_COLOR_HUMAN "#dc0000"
+#define BLOOD_COLOR_XENO "#94a83c"
+#define BLOOD_COLOR_OIL "#301d02"
+#define BLOOD_COLOR_SYNTHETIC "#3f48aa"
+#define BLOOD_COLOR_SLIME "#00ff90"
+#define BLOOD_COLOR_LIZARD "#db004D"
+#define BLOOD_COLOR_UNIVERSAL "#db3300"
+#define BLOOD_COLOR_BUG "#a37c0f"
+
+
//suit sensors: sensor_mode defines
#define SENSOR_OFF 0
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 3c8d62ce3a..80c9b0c2dd 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -756,7 +756,6 @@ Turf and target are separate in case you want to teleport some distance from a t
loc = loc.loc
return null
-
//For objects that should embed, but make no sense being is_sharp or is_pointed()
//e.g: rods
GLOBAL_LIST_INIT(can_embed_types, typecacheof(list(
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index c883254afe..8b5657a6f6 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -58,3 +58,64 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito
for(var/i in GLOB.mob_list)
var/mob/M = i
M.update_config_movespeed()
+
+GLOBAL_LIST_INIT(noodle_taurs, list(
+ "Naga",
+ "Tentacle"
+ ))
+
+GLOBAL_LIST_INIT(paw_taurs, list(
+ "Fox",
+ "Wolf",
+ "Otie",
+ "Drake",
+ "Lab",
+ "Shepherd",
+ "Husky",
+ "Eevee",
+ "Panther",
+ "Horse",
+ "Cow",
+ "Tiger"
+ ))
+
+ //blood types
+GLOBAL_LIST_INIT(regular_bloods,list(
+ "O-",
+ "O+",
+ "A-",
+ "A+",
+ "B-",
+ "B+",
+ "AB-",
+ "AB+"
+ ))
+
+GLOBAL_LIST_INIT(all_types_bloods,list(
+ "O-",
+ "O+",
+ "A-",
+ "A+",
+ "B-",
+ "B+",
+ "AB-",
+ "AB+",
+ "SY",
+ "X*",
+ "HF",
+ "L",
+ "U",
+ "GEL",
+ "BUG"
+ ))
+
+GLOBAL_LIST_INIT(blood_types, list(
+ "blood",
+ "jellyblood"
+ ))
+
+GLOBAL_LIST_INIT(blood_id_types, list(
+ "blood" = /datum/reagent/blood,
+ "jellyblood" = /datum/reagent/blood/jellyblood
+ ))
+
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index b3d3b46434..e41755b6c2 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -2,6 +2,10 @@
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/datum/parent
+ //only set to true if you are able to properly transfer this component
+ //At a minimum RegisterWithParent and UnregisterFromParent should be used
+ //Make sure you also implement PostTransfer for any post transfer handling
+ var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
@@ -154,7 +158,7 @@
return
/datum/component/proc/PostTransfer()
- return
+ return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
@@ -285,10 +289,12 @@
if(target.parent)
target.RemoveComponent()
target.parent = src
- if(target.PostTransfer() == COMPONENT_INCOMPATIBLE)
- var/c_type = target.type
- qdel(target)
- CRASH("Incompatible [c_type] transfer attempt to a [type]!")
+ var/result = target.PostTransfer()
+ switch(result)
+ if(COMPONENT_INCOMPATIBLE)
+ var/c_type = target.type
+ qdel(target)
+ CRASH("Incompatible [c_type] transfer attempt to a [type]!")
if(target == AddComponent(target))
target._JoinParent()
@@ -298,10 +304,13 @@
return
var/comps = dc[/datum/component]
if(islist(comps))
- for(var/I in comps)
- target.TakeComponent(I)
+ for(var/datum/component/I in comps)
+ if(I.can_transfer)
+ target.TakeComponent(I)
else
- target.TakeComponent(comps)
+ var/datum/component/C = comps
+ if(C.can_transfer)
+ target.TakeComponent(comps)
/datum/component/ui_host()
return parent
diff --git a/code/datums/components/cleaning.dm b/code/datums/components/cleaning.dm
index 05c26efcc1..5324a87fee 100644
--- a/code/datums/components/cleaning.dm
+++ b/code/datums/components/cleaning.dm
@@ -8,32 +8,39 @@
/datum/component/cleaning/proc/Clean()
var/atom/movable/AM = parent
- var/turf/tile = AM.loc
- if(!isturf(tile))
- return
-
- SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- for(var/A in tile)
+ var/turf/T = AM.loc
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ for(var/A in T)
if(is_cleanable(A))
qdel(A)
- else if(istype(A, /obj/item))
- var/obj/item/I = A
- SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- if(ismob(I.loc))
- var/mob/M = I.loc
+ else if(isitem(A))
+ var/obj/item/cleaned_item = A
+ SEND_SIGNAL(cleaned_item, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_item.clean_blood()
+ if(ismob(cleaned_item.loc))
+ var/mob/M = cleaned_item.loc
M.regenerate_icons()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
- SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.head.clean_blood()
+ cleaned_human.update_inv_head()
if(cleaned_human.wear_suit)
- SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.wear_suit.clean_blood()
+ cleaned_human.update_inv_wear_suit()
else if(cleaned_human.w_uniform)
- SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_uniform.clean_blood()
+ cleaned_human.update_inv_w_uniform()
if(cleaned_human.shoes)
- SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.shoes.clean_blood()
+ cleaned_human.update_inv_shoes()
+ SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.clean_blood()
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
- to_chat(cleaned_human, "[AM] cleans your face!")
+ to_chat(cleaned_human, "[src] cleans your face!")
\ No newline at end of file
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index e5547ee0ec..bdc1d3a2f6 100644
--- a/code/datums/components/decal.dm
+++ b/code/datums/components/decal.dm
@@ -1,6 +1,6 @@
/datum/component/decal
dupe_mode = COMPONENT_DUPE_ALLOWED
-
+ can_transfer = TRUE
var/cleanable
var/description
var/mutable_appearance/pic
diff --git a/code/datums/components/decals/blood.dm b/code/datums/components/decals/blood.dm
index 7fae975678..c8be6251b5 100644
--- a/code/datums/components/decals/blood.dm
+++ b/code/datums/components/decals/blood.dm
@@ -1,39 +1,13 @@
-/datum/component/decal/blood
- dupe_mode = COMPONENT_DUPE_UNIQUE
-
-/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_STRENGTH_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
- if(!isitem(parent))
- return COMPONENT_INCOMPATIBLE
- . = ..()
- RegisterSignal(parent, COMSIG_ATOM_GET_EXAMINE_NAME, .proc/get_examine_name)
-
-/datum/component/decal/blood/generate_appearance(_icon, _icon_state, _dir, _layer, _color)
- var/obj/item/I = parent
- if(!_icon)
- _icon = 'icons/effects/blood.dmi'
- if(!_icon_state)
- _icon_state = "itemblood"
- var/icon = initial(I.icon)
- var/icon_state = initial(I.icon_state)
- if(!icon || !icon_state)
- // It's something which takes on the look of other items, probably
- icon = I.icon
- icon_state = I.icon_state
- var/static/list/blood_splatter_appearances = list()
- //try to find a pre-processed blood-splatter. otherwise, make a new one
- var/index = "[REF(icon)]-[icon_state]"
- pic = blood_splatter_appearances[index]
-
- if(!pic)
- var/icon/blood_splatter_icon = icon(initial(I.icon), initial(I.icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object
- blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
- blood_splatter_icon.Blend(icon(_icon, _icon_state), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
- pic = mutable_appearance(blood_splatter_icon, initial(I.icon_state))
- blood_splatter_appearances[index] = pic
- return TRUE
-
-/datum/component/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
- var/atom/A = parent
- override[EXAMINE_POSITION_ARTICLE] = A.gender == PLURAL? "some" : "a"
- override[EXAMINE_POSITION_BEFORE] = " blood-stained "
- return COMPONENT_EXNAME_CHANGED
+/datum/component/decal/blood
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+
+/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_STRENGTH_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+ . = ..()
+ RegisterSignal(parent, COMSIG_ATOM_GET_EXAMINE_NAME, .proc/get_examine_name)
+
+/datum/component/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
+ var/atom/A = parent
+
+ return COMPONENT_EXNAME_CHANGED
diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm
deleted file mode 100644
index c7a1f7eba5..0000000000
--- a/code/datums/components/forensics.dm
+++ /dev/null
@@ -1,159 +0,0 @@
-/datum/component/forensics
- dupe_mode = COMPONENT_DUPE_UNIQUE
- var/list/fingerprints //assoc print = print
- var/list/hiddenprints //assoc ckey = realname/gloves/ckey
- var/list/blood_DNA //assoc dna = bloodtype
- var/list/fibers //assoc print = print
-
-/datum/component/forensics/InheritComponent(datum/component/forensics/F, original) //Use of | and |= being different here is INTENTIONAL.
- fingerprints = fingerprints | F.fingerprints
- hiddenprints = hiddenprints | F.hiddenprints
- blood_DNA = blood_DNA | F.blood_DNA
- fibers = fibers | F.fibers
- check_blood()
- return ..()
-
-/datum/component/forensics/Initialize(new_fingerprints, new_hiddenprints, new_blood_DNA, new_fibers)
- if(!isatom(parent))
- return COMPONENT_INCOMPATIBLE
- fingerprints = new_fingerprints
- hiddenprints = new_hiddenprints
- blood_DNA = new_blood_DNA
- fibers = new_fibers
- check_blood()
- RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_act)
-
-/datum/component/forensics/proc/wipe_fingerprints()
- fingerprints = null
- return TRUE
-
-/datum/component/forensics/proc/wipe_hiddenprints()
- return //no.
-
-/datum/component/forensics/proc/wipe_blood_DNA()
- blood_DNA = null
- if(isitem(parent))
- qdel(parent.GetComponent(/datum/component/decal/blood))
- return TRUE
-
-/datum/component/forensics/proc/wipe_fibers()
- fibers = null
- return TRUE
-
-/datum/component/forensics/proc/clean_act(datum/source, strength)
- if(strength >= CLEAN_STRENGTH_FINGERPRINTS)
- wipe_fingerprints()
- if(strength >= CLEAN_STRENGTH_BLOOD)
- wipe_blood_DNA()
- if(strength >= CLEAN_STRENGTH_FIBERS)
- wipe_fibers()
-
-/datum/component/forensics/proc/add_fingerprint_list(list/_fingerprints) //list(text)
- if(!length(_fingerprints))
- return
- LAZYINITLIST(fingerprints)
- for(var/i in _fingerprints) //We use an associative list, make sure we don't just merge a non-associative list into ours.
- fingerprints[i] = i
- return TRUE
-
-/datum/component/forensics/proc/add_fingerprint(mob/living/M, ignoregloves = FALSE)
- if(!M)
- return
- add_hiddenprint(M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- add_fibers(H)
- if(H.gloves) //Check if the gloves (if any) hide fingerprints
- var/obj/item/clothing/gloves/G = H.gloves
- if(G.transfer_prints)
- ignoregloves = TRUE
- if(!ignoregloves)
- H.gloves.add_fingerprint(H, TRUE) //ignoregloves = 1 to avoid infinite loop.
- return
- var/full_print = md5(H.dna.uni_identity)
- LAZYSET(fingerprints, full_print, full_print)
- return TRUE
-
-/datum/component/forensics/proc/add_fiber_list(list/_fibertext) //list(text)
- if(!length(_fibertext))
- return
- LAZYINITLIST(fibers)
- for(var/i in _fibertext) //We use an associative list, make sure we don't just merge a non-associative list into ours.
- fibers[i] = i
- return TRUE
-
-/datum/component/forensics/proc/add_fibers(mob/living/carbon/human/M)
- var/fibertext
- var/item_multiplier = isitem(src)?1.2:1
- if(M.wear_suit)
- fibertext = "Material from \a [M.wear_suit]."
- if(prob(10*item_multiplier) && !LAZYACCESS(fibers, fibertext))
- LAZYSET(fibers, fibertext, fibertext)
- if(!(M.wear_suit.body_parts_covered & CHEST))
- if(M.w_uniform)
- fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(12*item_multiplier) && !LAZYACCESS(fibers, fibertext)) //Wearing a suit means less of the uniform exposed.
- LAZYSET(fibers, fibertext, fibertext)
- if(!(M.wear_suit.body_parts_covered & HANDS))
- if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
- LAZYSET(fibers, fibertext, fibertext)
- else if(M.w_uniform)
- fibertext = "Fibers from \a [M.w_uniform]."
- if(prob(15*item_multiplier) && !LAZYACCESS(fibers, fibertext))
- // "Added fibertext: [fibertext]"
- LAZYSET(fibers, fibertext, fibertext)
- if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
- LAZYSET(fibers, fibertext, fibertext)
- else if(M.gloves)
- fibertext = "Material from a pair of [M.gloves.name]."
- if(prob(20*item_multiplier) && !LAZYACCESS(fibers, fibertext))
- LAZYSET(fibers, fibertext, fibertext)
- return TRUE
-
-/datum/component/forensics/proc/add_hiddenprint_list(list/_hiddenprints) //list(ckey = text)
- if(!length(_hiddenprints))
- return
- LAZYINITLIST(hiddenprints)
- for(var/i in _hiddenprints) //We use an associative list, make sure we don't just merge a non-associative list into ours.
- hiddenprints[i] = _hiddenprints[i]
- return TRUE
-
-/datum/component/forensics/proc/add_hiddenprint(mob/living/M)
- if(!M || !M.key)
- return
- var/hasgloves = ""
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.gloves)
- hasgloves = "(gloves)"
- var/current_time = TIME_STAMP("hh:mm:ss", FALSE)
- if(!LAZYACCESS(hiddenprints, M.key))
- LAZYSET(hiddenprints, M.key, "First: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]")
- else
- var/laststamppos = findtext(LAZYACCESS(hiddenprints, M.key), " Last: ")
- if(laststamppos)
- LAZYSET(hiddenprints, M.key, copytext(hiddenprints[M.key], 1, laststamppos))
- hiddenprints[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]" //made sure to be existing by if(!LAZYACCESS);else
- var/atom/A = parent
- A.fingerprintslast = M.ckey
- return TRUE
-
-/datum/component/forensics/proc/add_blood_DNA(list/dna) //list(dna_enzymes = type)
- if(!length(dna))
- return
- LAZYINITLIST(blood_DNA)
- for(var/i in dna)
- blood_DNA[i] = dna[i]
- check_blood()
- return TRUE
-
-/datum/component/forensics/proc/check_blood()
- if(!isitem(parent))
- return
- if(!length(blood_DNA))
- return
- parent.LoadComponent(/datum/component/decal/blood)
diff --git a/code/datums/components/lockon_aiming.dm b/code/datums/components/lockon_aiming.dm
index cc41e793ed..38b707ac19 100644
--- a/code/datums/components/lockon_aiming.dm
+++ b/code/datums/components/lockon_aiming.dm
@@ -237,6 +237,3 @@
LOCKON_RANGING_BREAK_CHECK
cd++
CHECK_TICK
-
-/datum/component/lockon_aiming/PostTransfer(datum/new_parent)
- return COMPONENT_INCOMPATIBLE
diff --git a/code/datums/components/mirage_border.dm b/code/datums/components/mirage_border.dm
index 2e6f8f79f6..20e3b317ec 100644
--- a/code/datums/components/mirage_border.dm
+++ b/code/datums/components/mirage_border.dm
@@ -1,4 +1,5 @@
/datum/component/mirage_border
+ can_transfer = TRUE
var/obj/effect/abstract/mirage_holder/holder
/datum/component/mirage_border/Initialize(turf/target, direction, range=world.view)
diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm
index ff424dc02e..eef3873e6e 100644
--- a/code/datums/components/rotation.dm
+++ b/code/datums/components/rotation.dm
@@ -44,19 +44,21 @@
if(src.rotation_flags & ROTATION_CLOCKWISE)
default_rotation_direction = ROTATION_CLOCKWISE
- if(src.rotation_flags & ROTATION_ALTCLICK)
+/datum/component/simple_rotation/proc/add_signals()
+ if(rotation_flags & ROTATION_ALTCLICK)
RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/HandRot)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/ExamineMessage)
- if(src.rotation_flags & ROTATION_WRENCH)
+ if(rotation_flags & ROTATION_WRENCH)
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/WrenchRot)
- if(src.rotation_flags & ROTATION_VERBS)
+/datum/component/simple_rotation/proc/add_verbs()
+ if(rotation_flags & ROTATION_VERBS)
var/atom/movable/AM = parent
- if(src.rotation_flags & ROTATION_FLIP)
+ if(rotation_flags & ROTATION_FLIP)
AM.verbs += /atom/movable/proc/simple_rotate_flip
- if(src.rotation_flags & ROTATION_CLOCKWISE)
+ if(rotation_flags & ROTATION_CLOCKWISE)
AM.verbs += /atom/movable/proc/simple_rotate_clockwise
- if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE)
+ if(rotation_flags & ROTATION_COUNTERCLOCKWISE)
AM.verbs += /atom/movable/proc/simple_rotate_counterclockwise
/datum/component/simple_rotation/proc/remove_verbs()
@@ -66,11 +68,30 @@
AM.verbs -= /atom/movable/proc/simple_rotate_clockwise
AM.verbs -= /atom/movable/proc/simple_rotate_counterclockwise
-/datum/component/simple_rotation/Destroy()
+/datum/component/simple_rotation/proc/remove_signals()
+ UnregisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_PARENT_EXAMINE, COMSIG_PARENT_ATTACKBY))
+
+/datum/component/simple_rotation/RegisterWithParent()
+ add_verbs()
+ add_signals()
+ . = ..()
+
+/datum/component/simple_rotation/PostTransfer()
+ //Because of the callbacks which we don't track cleanly we can't transfer this
+ //item cleanly, better to let the new of the new item create a new rotation datum
+ //instead (there's no real state worth transferring)
+ return COMPONENT_NOTRANSFER
+
+/datum/component/simple_rotation/UnregisterFromParent()
remove_verbs()
+ remove_signals()
+ . = ..()
+
+/datum/component/simple_rotation/Destroy()
QDEL_NULL(can_user_rotate)
QDEL_NULL(can_be_rotated)
QDEL_NULL(after_rotation)
+ //Signals + verbs removed via UnRegister
. = ..()
/datum/component/simple_rotation/RemoveComponent()
diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm
index 0b78605869..f7ca711421 100644
--- a/code/datums/components/storage/concrete/_concrete.dm
+++ b/code/datums/components/storage/concrete/_concrete.dm
@@ -4,6 +4,7 @@
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
/datum/component/storage/concrete
+ can_transfer = TRUE
var/drop_all_on_deconstruct = TRUE
var/drop_all_on_destroy = FALSE
var/drop_all_on_break = FALSE
diff --git a/code/datums/components/wet_floor.dm b/code/datums/components/wet_floor.dm
index 6d504cefd4..dc124750e4 100644
--- a/code/datums/components/wet_floor.dm
+++ b/code/datums/components/wet_floor.dm
@@ -1,5 +1,6 @@
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ can_transfer = TRUE
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
@@ -26,14 +27,20 @@
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
add_wet(strength, duration_minimum, duration_add, duration_maximum)
- RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
- RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
permanent = _permanent
if(!permanent)
START_PROCESSING(SSwet_floors, src)
addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization.
last_process = world.time
+/datum/component/wet_floor/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
+ RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
+
+/datum/component/wet_floor/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
+
+
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
@@ -138,12 +145,19 @@
/datum/component/wet_floor/PreTransfer()
var/turf/O = parent
O.cut_overlay(current_overlay)
+ //That turf is no longer slippery, we're out of here
+ //Slippery components don't transfer due to callbacks
+ qdel(O.GetComponent(/datum/component/slippery))
/datum/component/wet_floor/PostTransfer()
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
var/turf/T = parent
T.add_overlay(current_overlay)
+ //Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent)
+ update_flags()
+
+ //NB it's possible we get deleted after this, due to inherit
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST)
diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm
index 1b095c555d..31023b3fc7 100644
--- a/code/datums/mutable_appearance.dm
+++ b/code/datums/mutable_appearance.dm
@@ -10,10 +10,11 @@
// And yes this does have to be in the constructor, BYOND ignores it if you set it as a normal var
// Helper similar to image()
-/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE)
+/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, color = "#FFFFFF")
var/mutable_appearance/MA = new()
MA.icon = icon
MA.icon_state = icon_state
MA.layer = layer
MA.plane = plane
+ MA.color = color
return MA
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 7c9dc3f4fe..4869874501 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -36,6 +36,12 @@
var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
var/rad_insulation = RAD_NO_INSULATION
+ var/icon/blood_splatter_icon
+ var/list/fingerprints
+ var/list/fingerprintshidden
+ var/list/blood_DNA
+ var/list/suit_fibers
+
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -220,7 +226,7 @@
return FALSE
/atom/proc/CheckExit()
- return 1
+ return TRUE
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
@@ -254,14 +260,27 @@
if(article)
. = "[article] [src]"
override[EXAMINE_POSITION_ARTICLE] = article
+
if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
. = override.Join("")
+///Generate the full examine string of this atom (including icon for goonchat)
/atom/proc/get_examine_string(mob/user, thats = FALSE)
. = "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
/atom/proc/examine(mob/user)
- to_chat(user, get_examine_string(user, TRUE))
+ //This reformat names to get a/an properly working on item descriptions when they are bloody
+ var/f_name = "\a [src]."
+ if(src.blood_DNA && !istype(src, /obj/effect/decal))
+ if(gender == PLURAL)
+ f_name = "some "
+ else
+ f_name = "a "
+ f_name += "blood-stained [name]!"
+
+ to_chat(user, "[icon2html(src, user)] That's [f_name]")
+
+// to_chat(user, "[get_examine_string(user, TRUE)].")
if(desc)
to_chat(user, desc)
@@ -326,12 +345,14 @@
//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
/mob/living/proc/get_blood_dna_list()
- if(get_blood_id() != "blood")
+ var/blood_id = get_blood_id()
+ if(!(blood_id =="blood" || blood_id == "jellyblood"))
return
return list("ANIMAL DNA" = "Y-")
/mob/living/carbon/get_blood_dna_list()
- if(get_blood_id() != "blood")
+ var/blood_id = get_blood_id()
+ if(!(blood_id =="blood" || blood_id == "jellyblood"))
return
var/list/blood_dna = list()
if(dna)
@@ -349,18 +370,116 @@
var/new_blood_dna = L.get_blood_dna_list()
if(!new_blood_dna)
return FALSE
- var/old_length = blood_DNA_length()
- add_blood_DNA(new_blood_dna)
- if(blood_DNA_length() == old_length)
+ LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
+ var/old_length = blood_DNA.len
+ blood_DNA |= new_blood_dna
+ if(blood_DNA.len == old_length)
return FALSE
return TRUE
+//to add blood dna info to the object's blood_DNA list
+/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases)
+ LAZYINITLIST(blood_DNA)
+ var/old_length = blood_DNA.len
+ blood_DNA |= blood_dna
+ if(blood_DNA.len > old_length)
+ return TRUE
+ //some new blood DNA was added
+
//to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
var/list/blood_dna = M.get_blood_dna_list()
if(!blood_dna)
return FALSE
- return add_blood_DNA(blood_dna)
+ return add_blood_DNA(blood_dna, M.diseases)
+
+//to add blood onto something, with blood dna info to include.
+/atom/proc/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ return FALSE
+
+/obj/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ return transfer_blood_dna(blood_dna, diseases)
+
+/obj/item/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ . = ..()
+ if(!.)
+ return
+ add_blood_overlay()
+
+/obj/item/proc/add_blood_overlay()
+ if(!blood_DNA.len)
+ return
+ if(initial(icon) && initial(icon_state))
+ blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object
+ blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
+ blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
+ blood_splatter_icon.Blend(blood_DNA_to_color(), ICON_MULTIPLY)
+ add_overlay(blood_splatter_icon)
+
+/obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ . = ..()
+ transfer_blood = rand(2, 4)
+
+/turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src
+ if(!B)
+ B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases)
+ B.transfer_blood_dna(blood_dna, diseases) //give blood info to the blood decal.
+ return TRUE //we bloodied the floor
+
+/mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
+ if(head)
+ head.add_blood_DNA(blood_dna, diseases)
+ update_inv_head()
+ else if(wear_mask)
+ wear_mask.add_blood_DNA(blood_dna, diseases)
+ update_inv_wear_mask()
+ if(wear_neck)
+ wear_neck.add_blood_DNA(blood_dna, diseases)
+ update_inv_neck()
+ if(wear_suit)
+ wear_suit.add_blood_DNA(blood_dna, diseases)
+ update_inv_wear_suit()
+ else if(w_uniform)
+ w_uniform.add_blood_DNA(blood_dna, diseases)
+ update_inv_w_uniform()
+ if(gloves)
+ var/obj/item/clothing/gloves/G = gloves
+ G.add_blood_DNA(blood_dna, diseases)
+ else
+ transfer_blood_dna(blood_dna, diseases)
+ bloody_hands = rand(2, 4)
+ update_inv_gloves() //handles bloody hands overlays and updating
+ return TRUE
+
+/atom/proc/blood_DNA_to_color()
+ var/list/colors = list()//first we make a list of all bloodtypes present
+ for(var/bloop in blood_DNA)
+ if(colors[blood_DNA[bloop]])
+ colors[blood_DNA[bloop]]++
+ else
+ colors[blood_DNA[bloop]] = 1
+
+ var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up
+
+ if(colors.len)
+ var/sum = 0 //this is all shitcode, but it works; trust me
+ final_rgb = bloodtype_to_color(colors[1])
+ sum = colors[colors[1]]
+ if(colors.len > 1)
+ var/i = 2
+ while(i <= colors.len)
+ var/tmp = colors[colors[i]]
+ final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum))
+ sum += tmp
+ i++
+
+ return final_rgb
+
+/atom/proc/clean_blood()
+ if(islist(blood_DNA))
+ blood_DNA = null
+ return TRUE
/atom/proc/wash_cream()
return TRUE
@@ -714,4 +833,4 @@ Proc for attack log creation, because really why not
if(filter_data[name])
filter_data -= name
update_filters()
- return TRUE
+ return TRUE
\ No newline at end of file
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 426d23b4ab..58f551c648 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -317,7 +317,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/meaty/xeno/ram_turf(turf/T)
if(!isspaceturf(T))
- new /obj/effect/decal/cleanable/xenoblood(T)
+ new /obj/effect/decal/cleanable/blood/xeno(T)
//Station buster Tunguska
/obj/effect/meteor/tunguska
diff --git a/code/game/machinery/bloodbankgen.dm b/code/game/machinery/bloodbankgen.dm
new file mode 100644
index 0000000000..c489f6c9c9
--- /dev/null
+++ b/code/game/machinery/bloodbankgen.dm
@@ -0,0 +1,361 @@
+/obj/machinery/bloodbankgen
+ name = "blood bank generator"
+ desc = "Generates universally applicable synthetics for all blood types. Add regular blood to convert."
+ icon = 'icons/obj/bloodbank.dmi'
+ icon_state = "bloodbank-off"
+ density = TRUE
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 80
+ circuit = /obj/item/circuitboard/machine/bloodbankgen
+ interaction_flags_machine = INTERACT_MACHINE_OPEN | INTERACT_MACHINE_ALLOW_SILICON
+ var/draining = FALSE
+ var/filling = FALSE
+ var/obj/item/reagent_containers/blood/bag = null
+ var/obj/item/reagent_containers/blood/outbag = null
+ var/bloodstored = 0
+ var/maxbloodstored = 1000
+ var/menustat = "menu"
+ var/efficiency = 0
+ var/productivity = 0
+
+/obj/machinery/bloodbankgen/Initialize()
+ . = ..()
+ create_reagents(1000)
+ update_icon()
+
+/obj/machinery/bloodbankgen/Destroy()
+ QDEL_NULL(bag)
+ QDEL_NULL(outbag)
+ return ..()
+
+/obj/machinery/bloodbankgen/contents_explosion(severity, target)
+ ..()
+ if(bag)
+ bag.ex_act(severity, target)
+ if(outbag)
+ outbag.ex_act(severity, target)
+
+/obj/machinery/bloodbankgen/handle_atom_del(atom/A)
+ ..()
+ if(A == bag)
+ bag = null
+ update_icon()
+ updateUsrDialog()
+ if(A == outbag)
+ outbag = null
+ update_icon()
+ updateUsrDialog()
+
+/obj/machinery/bloodbankgen/RefreshParts()
+ var/E = 0
+ var/P = 0
+ for(var/obj/item/stock_parts/manipulator/M in component_parts)
+ E += M.rating
+ efficiency = E
+ productivity = P
+
+/obj/machinery/bloodbankgen/update_icon()
+ cut_overlays()
+ if(is_operational())
+ icon_state = "bloodbank-on"
+
+ if(panel_open)
+ add_overlay("bloodbank-panel")
+
+ if(src.bag)
+ add_overlay("bloodbag-input")
+ if(bag.reagents.total_volume)
+ var/mutable_appearance/filling_overlay = mutable_appearance(icon, "input-reagent")
+
+ var/percent = round((bag.reagents.total_volume / bag.volume) * 100)
+ switch(percent)
+ if(0 to 9)
+ filling_overlay.icon_state = "input-reagent0"
+ if(10 to 24)
+ filling_overlay.icon_state = "input-reagent10"
+ if(25 to 49)
+ filling_overlay.icon_state = "input-reagent25"
+ if(50 to 74)
+ filling_overlay.icon_state = "input-reagent50"
+ if(75 to 79)
+ filling_overlay.icon_state = "input-reagent75"
+ if(80 to 90)
+ filling_overlay.icon_state = "input-reagent80"
+ if(91 to INFINITY)
+ filling_overlay.icon_state = "input-reagent100"
+
+ filling_overlay.color = list(mix_color_from_reagents(bag.reagents.reagent_list))
+ add_overlay(filling_overlay)
+
+ if(src.outbag)
+ add_overlay("bloodbag-output")
+ if(outbag.reagents.total_volume)
+ var/mutable_appearance/filling_overlay = mutable_appearance(icon, "output-reagent")
+
+ var/percent = round((outbag.reagents.total_volume / outbag.volume) * 100)
+ switch(percent)
+ if(0 to 9)
+ filling_overlay.icon_state = "output-reagent0"
+ if(10 to 24)
+ filling_overlay.icon_state = "output-reagent10"
+ if(25 to 49)
+ filling_overlay.icon_state = "output-reagent25"
+ if(50 to 74)
+ filling_overlay.icon_state = "output-reagent50"
+ if(75 to 79)
+ filling_overlay.icon_state = "output-reagent75"
+ if(80 to 90)
+ filling_overlay.icon_state = "output-reagent80"
+ if(91 to INFINITY)
+ filling_overlay.icon_state = "output-reagent100"
+
+ filling_overlay.color = list(mix_color_from_reagents(outbag.reagents.reagent_list))
+ add_overlay(filling_overlay)
+ return
+
+/obj/machinery/bloodbankgen/process()
+ if(!is_operational())
+ return PROCESS_KILL
+
+ bloodstored = reagents.total_volume
+
+ var/transfer_amount = 20
+
+ if(draining)
+ if(reagents.total_volume >= reagents.maximum_volume)
+ draining = FALSE
+ return
+
+ if(bag)
+ if(bag.reagents.total_volume)
+ var/datum/reagent/blood/B = bag.reagents.has_reagent("blood")
+ if(B)
+ var/amount = reagents.maximum_volume - reagents.total_volume //monitor the machine's internal storage
+ amount = min(amount, transfer_amount)
+ if(!amount)
+ draining = FALSE
+ updateUsrDialog()
+ visible_message("[src] beeps loudly.")
+ playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
+ return
+
+ if(bag.blood_type == "SY") //no infinite loops using synthetics.
+ reagents.add_reagent("syntheticblood", amount)
+ else
+ reagents.add_reagent("syntheticblood", (amount+(5*efficiency)))
+
+ if(bag.reagents.total_volume >= amount)
+ bag.reagents.remove_reagent("blood", amount)
+ else
+ visible_message("[src] beeps loudly.")
+ playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
+ draining = FALSE
+
+ bag.update_icon()
+ update_icon()
+ updateUsrDialog()
+ else
+ draining = FALSE
+ updateUsrDialog()
+ return
+
+ if(filling)
+ if(!reagents || !reagents.total_volume)
+ filling = FALSE //there ain't anything in the machine yo.
+ return
+ if(outbag && outbag.reagents.total_volume < outbag.reagents.maximum_volume)
+ var/amount = outbag.reagents.maximum_volume - outbag.reagents.total_volume //monitor the output bag's internal storage
+ amount = min(amount, transfer_amount)
+ if(!amount)
+ filling = FALSE
+ visible_message("[src] pings.")
+ playsound(loc, 'sound/machines/beep.ogg', 50, 1)
+ updateUsrDialog()
+ return
+
+ reagents.trans_to(outbag, amount)
+ outbag.update_icon()
+ update_icon()
+ updateUsrDialog()
+ else
+ visible_message("[src] pings.")
+ playsound(loc, 'sound/machines/beep.ogg', 50, 1)
+ filling = FALSE
+ updateUsrDialog()
+ return
+
+/obj/machinery/bloodbankgen/attackby(obj/item/O, mob/user, params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+
+ if(default_deconstruction_screwdriver(user, "bloodbank-off", "bloodbank-off", O))
+ if(bag)
+ var/obj/item/reagent_containers/blood/B = bag
+ B.forceMove(drop_location())
+ bag = null
+ if(outbag)
+ var/obj/item/reagent_containers/blood/B = outbag
+ B.forceMove(drop_location())
+ outbag = null
+ update_icon()
+ return
+
+ if(default_deconstruction_crowbar(O))
+ return
+
+ if(istype(O, /obj/item/reagent_containers/blood))
+ . = 1 //no afterattack
+ if(!panel_open)
+ if(bag && outbag)
+ to_chat(user, "This machine already has bags attached.")
+
+ if(!bag && !outbag)
+ var/choice = alert(user, "Choose where to place [O]", "", "Input", "Cancel", "Output")
+ switch(choice)
+ if("Cancel")
+ return FALSE
+ if("Input")
+ attachinput(O, user)
+ if("Output")
+ attachoutput(O, user)
+ else if(!bag)
+ attachinput(O, user)
+ else if(!outbag)
+ attachoutput(O, user)
+ else
+ to_chat(user, "Close the maintenance panel first.")
+ return
+
+ else
+ to_chat(user, "You cannot put this in [src]!")
+
+/obj/machinery/bloodbankgen/ui_interact(mob/user)
+ . = ..()
+
+ if(!is_operational())
+ return
+
+ var/dat
+ switch(menustat)
+ if("noblood")
+ dat += "
You do not have enough blood product to create synthetics.
"
+ menustat = "menu"
+ if("complete")
+ dat += "Operation complete.
"
+ menustat = "menu"
+ if("nobagspace")
+ dat += "Not enough space left in container. Please replace receptical.
"
+ menustat = "menu"
+
+ dat+= "
Current Synthetics stockpile: [reagents.total_volume] units.
"
+
+ dat += "
Supply Bag
"
+ if(bag)
+ dat += "
Current Capacity: [bag.reagents.total_volume] of [bag.reagents.maximum_volume]"
+ if(bag.reagents && bag.reagents.total_volume)
+ dat += "
Drain"
+
+ dat += "
Detach"
+
+
+ dat += "
Synthetics Bag
"
+ if(outbag)
+ dat += "
Current Capacity:[outbag.reagents.total_volume] of [outbag.reagents.maximum_volume]"
+ if(!(outbag.reagents.total_volume >= outbag.reagents.maximum_volume))
+ dat += "
Fill"
+ dat += "
Detach"
+
+ if(!bag && !outbag)
+ dat += "No containers inside, please insert container.
"
+
+ var/datum/browser/popup = new(user, "bloodbankgen", name, 350, 520)
+ popup.set_content(dat)
+ popup.open()
+
+/obj/machinery/bloodbankgen/proc/activateinput()
+ if(bag)
+ draining = TRUE
+ update_icon()
+ else
+ to_chat(usr, "There is no blood bag in the input slot.")
+ return
+
+/obj/machinery/bloodbankgen/proc/activateoutput()
+ if(outbag)
+ filling = TRUE
+ update_icon()
+ else
+ to_chat(usr, "There is no blood bag in the output slot.")
+ return
+
+/obj/machinery/bloodbankgen/proc/check_container_volume(list/reagents, multiplier = 1)
+ var/sum_reagents = 0
+ for(var/R in reagents)
+ sum_reagents += reagents[R]
+ sum_reagents *= multiplier
+
+ if(outbag.reagents.total_volume + sum_reagents > outbag.reagents.maximum_volume)
+ menustat = "nobagspace"
+ return FALSE
+
+ return TRUE
+
+/obj/machinery/bloodbankgen/proc/detachinput()
+ if(bag)
+ bag.forceMove(drop_location())
+ if(usr && Adjacent(usr) && !issiliconoradminghost(usr))
+ usr.put_in_hands(bag)
+ bag = null
+ update_icon()
+
+/obj/machinery/bloodbankgen/proc/detachoutput()
+ if(outbag)
+ outbag.forceMove(drop_location())
+ if(usr && Adjacent(usr) && !issiliconoradminghost(usr))
+ usr.put_in_hands(outbag)
+ outbag = null
+ update_icon()
+
+/obj/machinery/bloodbankgen/proc/attachinput(obj/item/O, mob/user)
+ if(!bag)
+ if(!user.transferItemToLoc(O, src))
+ return
+ bag = O
+ to_chat(user, "You add [O] to the machine's input slot.")
+ update_icon()
+ updateUsrDialog()
+ else
+ to_chat(user, "There is already something in this slot!")
+
+/obj/machinery/bloodbankgen/proc/attachoutput(obj/item/O, mob/user)
+ if(!outbag)
+ if(!user.transferItemToLoc(O, src))
+ return
+ outbag = O
+ to_chat(user, "You add [O] to the machine's output slot.")
+ update_icon()
+ updateUsrDialog()
+ else
+ to_chat(user, "There is already something in this slot!")
+
+/obj/machinery/bloodbankgen/Topic(href, href_list)
+ if(..() || panel_open)
+ return
+
+ usr.set_machine(src)
+
+ if(href_list["activateinput"])
+ activateinput()
+ updateUsrDialog()
+
+ else if(href_list["detachinput"])
+ detachinput()
+ updateUsrDialog()
+
+ else if(href_list["activateoutput"])
+ activateoutput()
+ updateUsrDialog()
+
+ else if(href_list["detachoutput"])
+ detachoutput()
+ updateUsrDialog()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index a2da7de29a..3ac386e1fb 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -326,7 +326,7 @@
else //for simple_animals & borgs
L.adjustBruteLoss(DOOR_CRUSH_DAMAGE)
var/turf/location = get_turf(src)
- //add_blood doesn't work for borgs/xenos, but add_blood_floor does.
+ //add_blood_DNA doesn't work for borgs/xenos, but add_blood_floor does.
if(iscarbon(L))
var/mob/living/carbon/C = L
C.bleed(DOOR_CRUSH_DAMAGE)
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index b217c14e53..621ca266bb 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -8,14 +8,14 @@
icon_state = "iv_drip"
anchored = FALSE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
- var/mob/living/carbon/attached = null
+ var/mob/living/carbon/attached
var/mode = IV_INJECTING
- var/obj/item/reagent_containers/beaker = null
+ var/obj/item/reagent_containers/beaker
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
/obj/item/reagent_containers/food,
/obj/item/reagent_containers/glass))
-/obj/machinery/iv_drip/Initialize()
+/obj/machinery/iv_drip/Initialize(mapload)
. = ..()
update_icon()
@@ -84,6 +84,8 @@
if(Adjacent(target) && usr.Adjacent(target))
if(beaker)
usr.visible_message("[usr] attaches [src] to [target].", "You attach [src] to [target].")
+ log_combat(usr, target, "attached", src, "containing: [beaker.name] - ([beaker.reagents.log_list()])")
+ add_fingerprint(usr)
attached = target
START_PROCESSING(SSmachines, src)
update_icon()
@@ -100,6 +102,8 @@
return
beaker = W
to_chat(user, "You attach [W] to [src].")
+ user.log_message("attached a [W] to [src] at [AREACOORD(src)] containing ([beaker.reagents.log_list()])", LOG_ATTACK)
+ add_fingerprint(user)
update_icon()
return
else
@@ -142,10 +146,11 @@
if(!amount)
if(prob(5))
visible_message("[src] pings.")
+ playsound(loc, 'sound/machines/beep.ogg', 50, 1)
return
// If the human is losing too much blood, beep.
- if(attached.blood_volume < ( (BLOOD_VOLUME_SAFE*attached.blood_ratio) && prob(5) ) )
+ if(attached.blood_volume < ((BLOOD_VOLUME_SAFE*attached.blood_ratio) && prob(5) && ishuman(attached))) //really couldn't care less about monkeys
visible_message("[src] beeps loudly.")
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
attached.transfer_blood_to(beaker, amount)
@@ -178,9 +183,10 @@
if(usr.incapacitated())
return
-
if(beaker)
- beaker.forceMove(drop_location())
+ if(usr && Adjacent(usr) && !issiliconoradminghost(usr))
+ if(!usr.put_in_hands(beaker))
+ beaker.forceMove(drop_location())
beaker = null
update_icon()
@@ -195,27 +201,27 @@
if(usr.incapacitated())
return
-
mode = !mode
to_chat(usr, "The IV drip is now [mode ? "injecting" : "taking blood"].")
update_icon()
/obj/machinery/iv_drip/examine(mob/user)
- ..()
+ . = ..()
if(get_dist(user, src) > 2)
return
- to_chat(user, "The IV drip is [mode ? "injecting" : "taking blood"].")
+ . += "[src] is [mode ? "injecting" : "taking blood"].\n"
if(beaker)
if(beaker.reagents && beaker.reagents.reagent_list.len)
- to_chat(user, "Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.")
+ . += "\tAttached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.\n"
else
- to_chat(user, "Attached is an empty [beaker.name].")
+ . += "\tAttached is an empty [beaker.name].\n"
else
- to_chat(user, "No chemicals are attached.")
+ . += "\tNo chemicals are attached.\n"
- to_chat(user, "[attached ? attached : "No one"] is attached.")
+ . += "\t[attached ? attached : "No one"] is attached."
+ to_chat(user,.)
#undef IV_TAKING
-#undef IV_INJECTING
+#undef IV_INJECTING
\ No newline at end of file
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index d308d180d0..f35caf514c 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -265,6 +265,8 @@
things_to_clear += occupant.GetAllContents()
for(var/atom/movable/AM in things_to_clear) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG)
+ AM.clean_blood()
+ AM.fingerprints = list()
var/datum/component/radioactive/contamination = AM.GetComponent(/datum/component/radioactive)
if(contamination)
qdel(contamination)
@@ -435,4 +437,4 @@
if(I)
I.forceMove(loc)
. = TRUE
- update_icon()
+ update_icon()
\ No newline at end of file
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index 5e8515d3d5..8be079656b 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -11,10 +11,6 @@
var/obj/item/color_source
var/max_wash_capacity = 5
-/obj/machinery/washing_machine/ComponentInitialize()
- . = ..()
- AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
-
/obj/machinery/washing_machine/examine(mob/user)
..()
to_chat(user, "Alt-click it to start a wash cycle.")
@@ -59,7 +55,8 @@
M.Translate(rand(-3, 3), rand(-1, 3))
animate(src, transform=M, time=2)
-/obj/machinery/washing_machine/proc/clean_blood()
+/obj/machinery/washing_machine/clean_blood()
+ ..()
if(!busy)
bloody_mess = FALSE
update_icon()
@@ -67,7 +64,8 @@
/obj/machinery/washing_machine/proc/wash_cycle()
for(var/X in contents)
var/atom/movable/AM = X
- SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ AM.clean_blood()
AM.machine_wash(src)
busy = FALSE
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index d5aff99f32..2eb4a6aa0c 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -8,6 +8,7 @@
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
. = ..()
+ LAZYINITLIST(blood_DNA) //Kinda needed
if (random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
icon_state = pick(random_icon_states)
create_reagents(300)
@@ -27,7 +28,7 @@
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
- return TRUE
+ qdel(C)
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food/drinks))
@@ -81,7 +82,9 @@
add_blood = bloodiness
bloodiness -= add_blood
S.bloody_shoes[blood_state] = min(MAX_SHOE_BLOODINESS,S.bloody_shoes[blood_state]+add_blood)
- S.add_blood_DNA(return_blood_DNA())
+ if(blood_DNA && blood_DNA.len)
+ S.add_blood_DNA(blood_DNA)
+ S.add_blood_overlay()
S.blood_state = blood_state
update_icon()
H.update_inv_shoes()
@@ -90,4 +93,4 @@
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
return bloodiness
else
- return 0
+ return FALSE
diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm
index ca2a8ccaff..988011c492 100644
--- a/code/game/objects/effects/decals/cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/cleanable/aliens.dm
@@ -1,71 +1,72 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-/obj/effect/decal/cleanable/xenoblood
+/obj/effect/decal/cleanable/blood/xeno
name = "xeno blood"
desc = "It's green and acidic. It looks like... blood?"
- icon = 'icons/effects/blood.dmi'
- icon_state = "xfloor1"
- random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
- bloodiness = BLOOD_AMOUNT_PER_DECAL
- blood_state = BLOOD_STATE_XENO
+ color = BLOOD_COLOR_XENO
-/obj/effect/decal/cleanable/xenoblood/Initialize()
+/obj/effect/decal/cleanable/blood/splatter/xeno
+ color = BLOOD_COLOR_XENO
+
+/obj/effect/decal/cleanable/blood/gibs/xeno
+ color = BLOOD_COLOR_XENO
+ gibs_reagent_id = "liquidxenogibs"
+ gibs_bloodtype = "X*"
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/Initialize(mapload, list/datum/disease/diseases)
. = ..()
- add_blood_DNA(list("UNKNOWN DNA" = "X*"))
+ update_icon()
-/obj/effect/decal/cleanable/xenoblood/xsplatter
- random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5")
+/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
+ add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
+ cut_overlays()
+ var/mutable_appearance/flesh = mutable_appearance(icon, "[icon_state]x_flesh")
+ flesh.appearance_flags = RESET_COLOR
+ flesh.color = body_colors
+ add_overlay(flesh)
-/obj/effect/decal/cleanable/xenoblood/xgibs
- name = "xeno gibs"
- desc = "Gnarly..."
- icon = 'icons/effects/blood.dmi'
- icon_state = "xgib1"
- layer = LOW_OBJ_LAYER
- random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
- mergeable_decal = FALSE
-
-/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions)
+/obj/effect/decal/cleanable/blood/gibs/xeno/streak(list/directions)
set waitfor = 0
var/direction = pick(directions)
for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
sleep(2)
if(i > 0)
- new /obj/effect/decal/cleanable/xenoblood/xsplatter(loc)
+ var/list/datum/disease/diseases
+ GET_COMPONENT(infective, /datum/component/infective)
+ if(infective)
+ diseases = infective.diseases
+ var/obj/effect/decal/cleanable/blood/splatter/xeno/splat = new /obj/effect/decal/cleanable/blood/splatter/xeno(loc, diseases)
+ splat.transfer_blood_dna(blood_DNA, diseases)
if(!step_to(src, get_step(src, direction), 0))
break
-/obj/effect/decal/cleanable/xenoblood/xgibs/ex_act()
- return
+/obj/effect/decal/cleanable/blood/gibs/xeno/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
-/obj/effect/decal/cleanable/xenoblood/xgibs/up
- random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1")
+/obj/effect/decal/cleanable/blood/gibs/xeno/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
-/obj/effect/decal/cleanable/xenoblood/xgibs/down
- random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1")
+/obj/effect/decal/cleanable/blood/gibs/xeno/body
+ random_icon_states = list("gibhead", "gibtorso")
-/obj/effect/decal/cleanable/xenoblood/xgibs/body
- random_icon_states = list("xgibhead", "xgibtorso")
+/obj/effect/decal/cleanable/blood/gibs/xeno/torso
+ random_icon_states = list("gibtorso")
-/obj/effect/decal/cleanable/xenoblood/xgibs/torso
- random_icon_states = list("xgibtorso")
+/obj/effect/decal/cleanable/blood/gibs/xeno/limb
+ random_icon_states = list("gibleg", "gibarm")
-/obj/effect/decal/cleanable/xenoblood/xgibs/limb
- random_icon_states = list("xgibleg", "xgibarm")
+/obj/effect/decal/cleanable/blood/gibs/xeno/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
-/obj/effect/decal/cleanable/xenoblood/xgibs/core
- random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3")
-
-/obj/effect/decal/cleanable/xenoblood/xgibs/larva
+/obj/effect/decal/cleanable/blood/gibs/xeno/larva
random_icon_states = list("xgiblarva1", "xgiblarva2")
-/obj/effect/decal/cleanable/xenoblood/xgibs/larva/body
+/obj/effect/decal/cleanable/blood/gibs/xeno/larva/body
random_icon_states = list("xgiblarvahead", "xgiblarvatorso")
/obj/effect/decal/cleanable/blood/xtracks
- icon_state = "xtracks"
+ icon_state = "tracks"
random_icon_states = null
/obj/effect/decal/cleanable/blood/xtracks/Initialize()
- . = ..()
- add_blood_DNA(list("Unknown DNA" = "X*"))
+ add_blood_DNA(list("UNKNOWN DNA" = "X*"))
+ . = ..()
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/cleanable/gibs.dm b/code/game/objects/effects/decals/cleanable/gibs.dm
new file mode 100644
index 0000000000..e5d38d3ef6
--- /dev/null
+++ b/code/game/objects/effects/decals/cleanable/gibs.dm
@@ -0,0 +1,233 @@
+/obj/effect/decal/cleanable/blood/gibs
+ name = "gibs"
+ desc = "They look bloody and gruesome."
+ icon_state = "gibbl5"
+ layer = LOW_OBJ_LAYER
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
+ mergeable_decal = FALSE
+ var/body_colors = "#e3ba84" //a default color just in case.
+ var/gibs_reagent_id = "liquidgibs"
+ var/gibs_bloodtype = "A+"
+
+/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ if(random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
+ icon_state = pick(random_icon_states)
+ if(gibs_reagent_id)
+ reagents.add_reagent(gibs_reagent_id, 5)
+ if(gibs_bloodtype)
+ add_blood_DNA(list("Non-human DNA" = gibs_bloodtype, diseases))
+ update_icon()
+
+
+/obj/effect/decal/cleanable/blood/gibs/update_icon()
+ add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
+ cut_overlays()
+ var/mutable_appearance/guts = mutable_appearance(icon, "[icon_state]_guts")
+ guts.appearance_flags = RESET_COLOR
+ add_overlay(guts)
+ var/mutable_appearance/flesh = mutable_appearance(icon, "[icon_state]_flesh")
+ flesh.appearance_flags = RESET_COLOR
+ flesh.color = body_colors
+ add_overlay(flesh)
+
+/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
+ return
+
+/obj/effect/decal/cleanable/blood/gibs/Crossed(mob/living/L)
+ if(istype(L) && has_gravity(loc))
+ playsound(loc, 'sound/effects/gib_step.ogg', !HAS_TRAIT(L,TRAIT_LIGHT_STEP) ? 20 : 50, 1)
+ . = ..()
+
+/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions)
+ set waitfor = 0
+ var/direction = pick(directions)
+ for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
+ sleep(2)
+ if(i > 0)
+ var/list/datum/disease/diseases
+ GET_COMPONENT(infective, /datum/component/infective)
+ if(infective)
+ diseases = infective.diseases
+ var/obj/effect/decal/cleanable/blood/splatter/splat = new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
+ splat.transfer_blood_dna(blood_DNA, diseases)
+ if(!step_to(src, get_step(src, direction), 0))
+ break
+
+/obj/effect/decal/cleanable/blood/gibs/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
+
+/obj/effect/decal/cleanable/blood/gibs/old
+ name = "old rotting gibs"
+ desc = "Space Jesus, why didn't anyone clean this up? It smells terrible."
+ bloodiness = 0
+
+/obj/effect/decal/cleanable/blood/gibs/old/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ setDir(pick(GLOB.cardinals))
+ icon_state += "-old"
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/drip
+ name = "drips of blood"
+ desc = "It's gooey."
+ icon_state = "1"
+ random_icon_states = list("drip1","drip2","drip3","drip4","drip5")
+ bloodiness = 0
+ var/drips = 1
+
+/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in()
+ return TRUE
+
+/obj/effect/decal/cleanable/blood/gibs/human
+
+/obj/effect/decal/cleanable/blood/gibs/human/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/gibs/human/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/human/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/human/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/human/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/human/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/human/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
+
+
+//Lizards
+/obj/effect/decal/cleanable/blood/gibs/human/lizard
+ body_colors = "117720"
+ gibs_reagent_id = "liquidgibs"
+ gibs_bloodtype = "L"
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/human/lizard/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
+
+// Slime Gibs
+/obj/effect/decal/cleanable/blood/gibs/slime
+ desc = "They look gooey and gruesome."
+ gibs_reagent_id = "liquidslimegibs"
+ gibs_bloodtype = "GEL"
+
+/obj/effect/decal/cleanable/blood/gibs/slime/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/gibs/slime/update_icon()
+ add_atom_colour(body_colors, FIXED_COLOUR_PRIORITY)
+ cut_overlays()
+ var/mutable_appearance/guts = mutable_appearance(icon, "[icon_state]s_guts")
+ guts.appearance_flags = RESET_COLOR
+ guts.color = body_colors
+ add_overlay(guts)
+ var/mutable_appearance/flesh = mutable_appearance(icon, "[icon_state]_flesh")
+ flesh.appearance_flags = RESET_COLOR
+ flesh.color = body_colors
+ add_overlay(flesh)
+
+/obj/effect/decal/cleanable/blood/gibs/slime/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/slime/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/slime/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/slime/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/slime/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/slime/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
+
+/obj/effect/decal/cleanable/blood/gibs/synth
+ desc = "They look sludgy and disgusting."
+ gibs_reagent_id = "liquidsyntheticgibs"
+ gibs_bloodtype = "SY"
+
+/obj/effect/decal/cleanable/blood/gibs/synth/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+//IPCs
+/obj/effect/decal/cleanable/blood/gibs/ipc
+ desc = "They look sharp yet oozing."
+ body_colors = "00ff00"
+ gibs_reagent_id = "liquidoilgibs"
+ gibs_bloodtype = "HF"
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/update_icon()
+ add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
+ cut_overlays()
+ var/mutable_appearance/guts = mutable_appearance(icon, "[icon_state]r-overlay")
+ guts.appearance_flags = RESET_COLOR
+ add_overlay(guts)
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/ipc/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index 35f06c2768..842b230b53 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -1,31 +1,45 @@
/obj/effect/decal/cleanable/blood
name = "blood"
- desc = "It's red and gooey. Perhaps it's the chef's cooking?"
+ desc = "It's gooey. Perhaps it's the chef's cooking?"
icon = 'icons/effects/blood.dmi'
icon_state = "floor1"
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
- blood_state = BLOOD_STATE_HUMAN
- bloodiness = BLOOD_AMOUNT_PER_DECAL
+ blood_state = BLOOD_STATE_BLOOD
+ bloodiness = MAX_SHOE_BLOODINESS
+ color = BLOOD_COLOR_HUMAN //default so we don't have white splotches everywhere.
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
- C.add_blood_DNA(return_blood_DNA())
- if (bloodiness)
- if (C.bloodiness < MAX_SHOE_BLOODINESS)
- C.bloodiness += bloodiness
- return ..()
+ if (C.blood_DNA)
+ blood_DNA |= C.blood_DNA.Copy()
+ update_icon()
+ ..()
+
+/obj/effect/decal/cleanable/blood/transfer_blood_dna()
+ ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/transfer_mob_blood_dna()
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/update_icon()
+ color = blood_DNA_to_color()
/obj/effect/decal/cleanable/blood/old
name = "dried blood"
- desc = "Looks like it's been here a while. Eew."
+ desc = "Looks like it's been here a while. Eew."
bloodiness = 0
/obj/effect/decal/cleanable/blood/old/Initialize(mapload, list/datum/disease/diseases)
- icon_state += "-old" //This IS necessary because the parent /blood type uses icon randomization.
- add_blood_DNA(list("Non-human DNA" = "A+")) // Needs to happen before ..()
- return ..()
+ ..()
+ icon_state += "-old"
+ add_blood_DNA(list("Non-human DNA" = "A+"))
+
+/obj/effect/decal/cleanable/blood/splats
+ random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
/obj/effect/decal/cleanable/blood/splatter
- random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
+ random_icon_states = list("splatter1", "splatter2", "splatter3", "splatter4", "splatter5")
/obj/effect/decal/cleanable/blood/tracks
icon_state = "tracks"
@@ -39,84 +53,23 @@
random_icon_states = null
var/list/existing_dirs = list()
+/obj/effect/decal/cleanable/trail_holder/update_icon()
+ color = blood_DNA_to_color()
+
+/obj/effect/cleanable/trail_holder/Initialize()
+ . = ..()
+ update_icon()
+
/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
return TRUE
-/obj/effect/decal/cleanable/blood/gibs
- name = "gibs"
- desc = "They look bloody and gruesome."
- icon = 'icons/effects/blood.dmi'
- icon_state = "gibbl5"
- layer = LOW_OBJ_LAYER
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
- mergeable_decal = FALSE
+/obj/effect/decal/cleanable/trail_holder/transfer_blood_dna()
+ ..()
+ update_icon()
-/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
+/obj/effect/decal/cleanable/trail_holder/transfer_mob_blood_dna()
. = ..()
- reagents.add_reagent("liquidgibs", 5)
-
-/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
- return
-
-/obj/effect/decal/cleanable/blood/gibs/Crossed(mob/living/L)
- if(istype(L) && has_gravity(loc))
- playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1)
- . = ..()
-
-/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions)
- set waitfor = 0
- var/direction = pick(directions)
- for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
- sleep(2)
- if(i > 0)
- var/list/datum/disease/diseases
- GET_COMPONENT(infective, /datum/component/infective)
- if(infective)
- diseases = infective.diseases
- new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
- if(!step_to(src, get_step(src, direction), 0))
- break
-
-/obj/effect/decal/cleanable/blood/gibs/up
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
-
-/obj/effect/decal/cleanable/blood/gibs/down
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
-
-/obj/effect/decal/cleanable/blood/gibs/body
- random_icon_states = list("gibhead", "gibtorso")
-
-/obj/effect/decal/cleanable/blood/gibs/torso
- random_icon_states = list("gibtorso")
-
-/obj/effect/decal/cleanable/blood/gibs/limb
- random_icon_states = list("gibleg", "gibarm")
-
-/obj/effect/decal/cleanable/blood/gibs/core
- random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
-
-/obj/effect/decal/cleanable/blood/gibs/old
- name = "old rotting gibs"
- desc = "Space Jesus, why didn't anyone clean this up? It smells terrible."
- bloodiness = 0
-
-/obj/effect/decal/cleanable/blood/gibs/old/Initialize(mapload, list/datum/disease/diseases)
- . = ..()
- setDir(pick(1,2,4,8))
- icon_state += "-old"
- add_blood_DNA(list("Non-human DNA" = "A+"))
-
-/obj/effect/decal/cleanable/blood/drip
- name = "drips of blood"
- desc = "It's red."
- icon_state = "1"
- random_icon_states = list("drip1","drip2","drip3","drip4","drip5")
- bloodiness = 0
- var/drips = 1
-
-/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in()
- return TRUE
-
+ update_icon()
//BLOODY FOOTPRINTS
/obj/effect/decal/cleanable/blood/footprints
@@ -127,15 +80,16 @@
random_icon_states = null
var/entered_dirs = 0
var/exited_dirs = 0
- blood_state = BLOOD_STATE_HUMAN //the icon state to load images from
+ blood_state = BLOOD_STATE_BLOOD //the icon state to load images from
var/list/shoe_types = list()
/obj/effect/decal/cleanable/blood/footprints/Crossed(atom/movable/O)
- ..()
if(ishuman(O))
var/mob/living/carbon/human/H = O
var/obj/item/clothing/shoes/S = H.shoes
if(S && S.bloody_shoes[blood_state])
+ if(color != bloodtype_to_color(S.last_bloodtype))
+ return
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
shoe_types |= S.type
if (!(entered_dirs & H.dir))
@@ -143,21 +97,21 @@
update_icon()
/obj/effect/decal/cleanable/blood/footprints/Uncrossed(atom/movable/O)
- ..()
if(ishuman(O))
var/mob/living/carbon/human/H = O
var/obj/item/clothing/shoes/S = H.shoes
if(S && S.bloody_shoes[blood_state])
+ if(color != bloodtype_to_color(S.last_bloodtype))//last entry - we check its color
+ return
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
shoe_types |= S.type
if (!(exited_dirs & H.dir))
exited_dirs |= H.dir
update_icon()
-
/obj/effect/decal/cleanable/blood/footprints/update_icon()
+ ..()
cut_overlays()
-
for(var/Ddir in GLOB.cardinals)
if(entered_dirs & Ddir)
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[blood_state]-[Ddir]"]
@@ -170,7 +124,7 @@
GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]2", dir = Ddir)
add_overlay(bloodstep_overlay)
- alpha = BLOODY_FOOTPRINT_BASE_ALPHA+bloodiness
+ alpha = BLOODY_FOOTPRINT_BASE_ALPHA + bloodiness
/obj/effect/decal/cleanable/blood/footprints/examine(mob/user)
@@ -179,16 +133,62 @@
. += "You recognise the footprints as belonging to:\n"
for(var/shoe in shoe_types)
var/obj/item/clothing/shoes/S = shoe
- . += "[icon2html(initial(S.icon), user)] Some [initial(S.name)].\n"
+ . += "some [initial(S.name)] [icon2html(initial(S.icon), user)]\n"
to_chat(user, .)
/obj/effect/decal/cleanable/blood/footprints/replace_decal(obj/effect/decal/cleanable/C)
if(blood_state != C.blood_state) //We only replace footprints of the same type as us
return
+ if(color != C.color)
+ return
..()
/obj/effect/decal/cleanable/blood/footprints/can_bloodcrawl_in()
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
- return 1
- return 0
+ return TRUE
+ return FALSE
+
+/* Eventually TODO: make snowflake trails like baycode's
+/obj/effect/decal/cleanable/blood/footprints/tracks/shoe
+ name = "footprints"
+ desc = "They look like tracks left by footwear."
+ icon_state = FOOTPRINT_SHOE
+ print_state = FOOTPRINT_SHOE
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/foot
+ name = "footprints"
+ desc = "They look like tracks left by a bare foot."
+ icon_state = FOOTPRINT_FOOT
+ print_state = FOOTPRINT_FOOT
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/snake
+ name = "tracks"
+ desc = "They look like tracks left by a giant snake."
+ icon_state = FOOTPRINT_SNAKE
+ print_state = FOOTPRINT_SNAKE
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/paw
+ name = "footprints"
+ desc = "They look like tracks left by paws."
+ icon_state = FOOTPRINT_PAW
+ print_state = FOOTPRINT_PAW
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/claw
+ name = "footprints"
+ desc = "They look like tracks left by claws."
+ icon_state = FOOTPRINT_CLAW
+ print_state = FOOTPRINT_CLAW
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/wheels
+ name = "tracks"
+ desc = "They look like tracks left by wheels."
+ gender = PLURAL
+ icon_state = FOOTPRINT_WHEEL
+ print_state = FOOTPRINT_WHEEL
+
+/obj/effect/decal/cleanable/blood/footprints/tracks/body
+ name = "trails"
+ desc = "A trail left by something being dragged."
+ icon_state = FOOTPRINT_DRAG
+ print_state = FOOTPRINT_DRAG */
diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm
index 484e0438e2..02bf51bdd9 100644
--- a/code/game/objects/effects/decals/cleanable/robots.dm
+++ b/code/game/objects/effects/decals/cleanable/robots.dm
@@ -11,6 +11,10 @@
bloodiness = BLOOD_AMOUNT_PER_DECAL
mergeable_decal = FALSE
+/obj/effect/decal/cleanable/robot_debris/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ reagents.add_reagent("liquidoilgibs", 5)
+
/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
set waitfor = 0
var/direction = pick(directions)
@@ -50,6 +54,7 @@
/obj/effect/decal/cleanable/oil/Initialize()
. = ..()
reagents.add_reagent("oil", 30)
+ reagents.add_reagent("liquidoilgibs", 5)
/obj/effect/decal/cleanable/oil/streak
random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm
index e99a2fcbc6..dd39bc567a 100644
--- a/code/game/objects/effects/spawners/gibspawner.dm
+++ b/code/game/objects/effects/spawners/gibspawner.dm
@@ -1,25 +1,69 @@
/obj/effect/gibspawner
- var/sparks = 0 //whether sparks spread
+ var/sparks = FALSE //whether sparks spread
var/virusProb = 20 //the chance for viruses to spread on the gibs
+ var/gib_mob_type //generate a fake mob to transfer DNA from if we weren't passed a mob.
+ var/gib_mob_species //We'll want to nip-pick their species for blood type stuff
+ var/sound_to_play = 'sound/effects/blobattack.ogg'
+ var/sound_vol = 60
var/list/gibtypes = list() //typepaths of the gib decals to spawn
var/list/gibamounts = list() //amount to spawn for each gib decal type we'll spawn.
var/list/gibdirections = list() //of lists of possible directions to spread each gib decal type towards.
-/obj/effect/gibspawner/Initialize(mapload, datum/dna/MobDNA, list/datum/disease/diseases)
+/obj/effect/gibspawner/Initialize(mapload, mob/living/source_mob, list/datum/disease/diseases)
. = ..()
-
- if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len)
- to_chat(world, "Gib list length mismatch!")
+ if(gibtypes.len != gibamounts.len)
+ stack_trace("Gib list amount length mismatch!")
+ return
+ if(gibamounts.len != gibdirections.len)
+ stack_trace("Gib list dir length mismatch!")
return
var/obj/effect/decal/cleanable/blood/gibs/gib = null
+ if(sound_to_play && isnum(sound_vol))
+ playsound(src, sound_to_play, sound_vol, TRUE)
+
if(sparks)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(2, 1, loc)
s.start()
+ var/list/dna_to_add //find the dna to pass to the spawned gibs. do note this can be null if the mob doesn't have blood. add_blood_DNA() has built in null handling.
+ var/body_coloring = ""
+ if(source_mob)
+ dna_to_add = source_mob.get_blood_dna_list() //ez pz
+ if(ishuman(source_mob))
+ var/mob/living/carbon/human/H = source_mob
+ if(H.dna.species.use_skintones)
+ body_coloring = "#[skintone2hex(H.skin_tone)]"
+ else
+ body_coloring = "#[H.dna.features["mcolor"]]"
+
+ else if(gib_mob_type)
+ var/mob/living/temp_mob = new gib_mob_type(src) //generate a fake mob so that we pull the right type of DNA for the gibs.
+ if(gib_mob_species)
+ if(ishuman(temp_mob))
+ var/mob/living/carbon/human/H = temp_mob
+ H.set_species(gib_mob_species)
+ dna_to_add = temp_mob.get_blood_dna_list()
+ if(H.dna.species.use_skintones)
+ body_coloring = "#[skintone2hex(H.skin_tone)]"
+ else
+ body_coloring = "#[H.dna.features["mcolor"]]"
+ qdel(H)
+ else
+ dna_to_add = temp_mob.get_blood_dna_list()
+ qdel(temp_mob)
+ else if(!issilicon(temp_mob))
+ dna_to_add = temp_mob.get_blood_dna_list()
+ qdel(temp_mob)
+ else
+ qdel(temp_mob)
+ else
+ dna_to_add = list("Non-human DNA" = random_blood_type()) //else, generate a random bloodtype for it.
+
+
for(var/i = 1, i<= gibtypes.len, i++)
if(gibamounts[i])
for(var/j = 1, j<= gibamounts[i], j++)
@@ -29,10 +73,11 @@
var/mob/living/carbon/digester = loc
digester.stomach_contents += gib
- if(MobDNA)
+ if(dna_to_add && dna_to_add.len)
+ gib.add_blood_DNA(dna_to_add)
+ gib.body_colors = body_coloring
+ gib.update_icon()
- else if(istype(src, /obj/effect/gibspawner/generic)) // Probably a monkey
- gib.add_blood_DNA(list("Non-human DNA" = "A+"))
var/list/directions = gibdirections[i]
if(isturf(loc))
if(directions.len)
@@ -41,80 +86,158 @@
return INITIALIZE_HINT_QDEL
-
/obj/effect/gibspawner/generic
gibtypes = list(/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core)
- gibamounts = list(2,2,1)
+ gibamounts = list(2, 2, 1)
+ sound_vol = 40
/obj/effect/gibspawner/generic/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 40, 1)
- gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list())
- . = ..()
+ if(!gibdirections.len)
+ gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list())
+ return ..()
+
+/obj/effect/gibspawner/generic/animal
+ gib_mob_type = /mob/living/simple_animal/pet
/obj/effect/gibspawner/human
- gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/up, /obj/effect/decal/cleanable/blood/gibs/down, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/body, /obj/effect/decal/cleanable/blood/gibs/limb, /obj/effect/decal/cleanable/blood/gibs/core)
- gibamounts = list(1,1,1,1,1,1,1)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/human/up, /obj/effect/decal/cleanable/blood/gibs/human/down, /obj/effect/decal/cleanable/blood/gibs/human, /obj/effect/decal/cleanable/blood/gibs/human, /obj/effect/decal/cleanable/blood/gibs/human/body, /obj/effect/decal/cleanable/blood/gibs/human/limb, /obj/effect/decal/cleanable/blood/gibs/human/core)
+ gibamounts = list(1, 1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/human
+ gib_mob_species = /datum/species/human
+ sound_vol = 50
/obj/effect/gibspawner/human/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 50, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
- . = ..()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
+ return ..()
-
-/obj/effect/gibspawner/humanbodypartless //only the gibs that don't look like actual full bodyparts (except torso).
- gibtypes = list(/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/torso)
+/obj/effect/gibspawner/human/bodypartless //only the gibs that don't look like actual full bodyparts (except torso).
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/human, /obj/effect/decal/cleanable/blood/gibs/human/core, /obj/effect/decal/cleanable/blood/gibs/human, /obj/effect/decal/cleanable/blood/gibs/human/core, /obj/effect/decal/cleanable/blood/gibs/human, /obj/effect/decal/cleanable/blood/gibs/human/torso)
gibamounts = list(1, 1, 1, 1, 1, 1)
-/obj/effect/gibspawner/humanbodypartless/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 50, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
- . = ..()
+/obj/effect/gibspawner/human/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
+ return ..()
+/obj/effect/gibspawner/lizard
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/human/lizard/up, /obj/effect/decal/cleanable/blood/gibs/human/lizard/down, /obj/effect/decal/cleanable/blood/gibs/human/lizard, /obj/effect/decal/cleanable/blood/gibs/human/lizard, /obj/effect/decal/cleanable/blood/gibs/human/lizard/body, /obj/effect/decal/cleanable/blood/gibs/human/lizard/limb, /obj/effect/decal/cleanable/blood/gibs/human/lizard/core)
+ gibamounts = list(1, 1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/human/species/lizard
+ gib_mob_species = /datum/species/lizard
+ sound_vol = 50
+
+/obj/effect/gibspawner/lizard/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
+ return ..()
+
+/obj/effect/gibspawner/lizard/bodypartless
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/human/lizard, /obj/effect/decal/cleanable/blood/gibs/human/lizard/core, /obj/effect/decal/cleanable/blood/gibs/human/lizard, /obj/effect/decal/cleanable/blood/gibs/human/lizard/core, /obj/effect/decal/cleanable/blood/gibs/human/lizard, /obj/effect/decal/cleanable/blood/gibs/human/lizard/torso)
+ gibamounts = list(1, 1, 1, 1, 1, 1)
+
+/obj/effect/gibspawner/lizard/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
+ return ..()
+
+/obj/effect/gibspawner/slime
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/slime/up, /obj/effect/decal/cleanable/blood/gibs/slime/down, /obj/effect/decal/cleanable/blood/gibs/slime, /obj/effect/decal/cleanable/blood/gibs/slime, /obj/effect/decal/cleanable/blood/gibs/slime/body, /obj/effect/decal/cleanable/blood/gibs/slime/limb, /obj/effect/decal/cleanable/blood/gibs/slime/core)
+ gibamounts = list(1, 1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/human/species/roundstartslime
+ gib_mob_species = /datum/species/jelly/roundstartslime
+ sound_vol = 50
+
+/obj/effect/gibspawner/slime/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
+ return ..()
+
+/obj/effect/gibspawner/slime/bodypartless //only the gibs that don't look like actual full bodyparts (except torso).
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/slime, /obj/effect/decal/cleanable/blood/gibs/slime/core, /obj/effect/decal/cleanable/blood/gibs/slime, /obj/effect/decal/cleanable/blood/gibs/slime/core, /obj/effect/decal/cleanable/blood/gibs/slime, /obj/effect/decal/cleanable/blood/gibs/slime/torso)
+ gibamounts = list(1, 1, 1, 1, 1, 1)
+
+/obj/effect/gibspawner/slime/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
+ return ..()
+
+/obj/effect/gibspawner/ipc
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/ipc/up, /obj/effect/decal/cleanable/blood/gibs/ipc/down, /obj/effect/decal/cleanable/blood/gibs/ipc, /obj/effect/decal/cleanable/blood/gibs/ipc, /obj/effect/decal/cleanable/blood/gibs/ipc/body, /obj/effect/decal/cleanable/blood/gibs/ipc/limb, /obj/effect/decal/cleanable/blood/gibs/ipc/core)
+ gibamounts = list(1, 1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/human/species/ipc
+ gib_mob_species = /datum/species/ipc
+ sound_vol = 50
+ sparks = TRUE
+ sound_to_play = 'sound/effects/bang.ogg'
+
+/obj/effect/gibspawner/ipc/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
+ return ..()
+
+/obj/effect/gibspawner/ipc/bodypartless //only the gibs that don't look like actual full bodyparts (except torso).
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/ipc, /obj/effect/decal/cleanable/blood/gibs/ipc/core, /obj/effect/decal/cleanable/blood/gibs/ipc, /obj/effect/decal/cleanable/blood/gibs/ipc/core, /obj/effect/decal/cleanable/blood/gibs/ipc, /obj/effect/decal/cleanable/blood/gibs/ipc/torso)
+ gibamounts = list(1, 1, 1, 1, 1, 1)
+
+/obj/effect/gibspawner/ipc/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
+ return ..()
/obj/effect/gibspawner/xeno
- gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up, /obj/effect/decal/cleanable/xenoblood/xgibs/down, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/body, /obj/effect/decal/cleanable/xenoblood/xgibs/limb, /obj/effect/decal/cleanable/xenoblood/xgibs/core)
- gibamounts = list(1,1,1,1,1,1,1)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/up, /obj/effect/decal/cleanable/blood/gibs/xeno/down, /obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/xeno/body, /obj/effect/decal/cleanable/blood/gibs/xeno/limb, /obj/effect/decal/cleanable/blood/gibs/xeno/core)
+ gibamounts = list(1, 1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/alien
/obj/effect/gibspawner/xeno/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
- . = ..()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
+ return ..()
-
-/obj/effect/gibspawner/xenobodypartless //only the gibs that don't look like actual full bodyparts (except torso).
- gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/torso)
+/obj/effect/gibspawner/xeno/bodypartless //only the gibs that don't look like actual full bodyparts (except torso).
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/xeno/core, /obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/xeno/core, /obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/xeno/torso)
gibamounts = list(1, 1, 1, 1, 1, 1)
+/obj/effect/gibspawner/xeno/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
+ return ..()
-/obj/effect/gibspawner/xenobodypartless/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
- . = ..()
+/obj/effect/gibspawner/xeno/xenoperson
+ gib_mob_type = /mob/living/carbon/human/species/xeno
+ gib_mob_species = /datum/species/xeno
+
+/obj/effect/gibspawner/xeno/xenoperson/bodypartless
/obj/effect/gibspawner/larva
- gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/larva, /obj/effect/decal/cleanable/blood/gibs/xeno/larva, /obj/effect/decal/cleanable/blood/gibs/xeno/larva/body, /obj/effect/decal/cleanable/blood/gibs/xeno/larva/body)
gibamounts = list(1, 1, 1, 1)
+ gib_mob_type = /mob/living/carbon/alien/larva
/obj/effect/gibspawner/larva/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list(), GLOB.alldirs)
- . = ..()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list(), GLOB.alldirs)
+ return ..()
-/obj/effect/gibspawner/larvabodypartless
- gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva)
+/obj/effect/gibspawner/larva/bodypartless
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/larva, /obj/effect/decal/cleanable/blood/gibs/xeno/larva, /obj/effect/decal/cleanable/blood/gibs/xeno/larva)
gibamounts = list(1, 1, 1)
-/obj/effect/gibspawner/larvabodypartless/Initialize()
- playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list())
- . = ..()
+/obj/effect/gibspawner/larva/bodypartless/Initialize()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list())
+ return ..()
/obj/effect/gibspawner/robot
- sparks = 1
+ sparks = TRUE
gibtypes = list(/obj/effect/decal/cleanable/robot_debris/up, /obj/effect/decal/cleanable/robot_debris/down, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris/limb)
- gibamounts = list(1,1,1,1,1,1)
+ gibamounts = list(1, 1, 1, 1, 1, 1)
+ gib_mob_type = /mob/living/silicon/robot
/obj/effect/gibspawner/robot/Initialize()
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs)
- gibamounts[6] = pick(0,1,2)
- . = ..()
+ if(!gibdirections.len)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs)
+ gibamounts[6] = pick(0, 1, 2)
+ return ..()
+
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 7d02d9d383..fbad000098 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -6,7 +6,9 @@
layer = BELOW_MOB_LAYER
var/splatter_type = "splatter"
-/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir)
+/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir, new_color)
+ if(new_color)
+ color = new_color
if(set_dir in GLOB.diagonals)
icon_state = "[splatter_type][pick(1, 2, 6)]"
else
@@ -41,7 +43,7 @@
animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
/obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter
- splatter_type = "xsplatter"
+ color = BLOOD_COLOR_XENO
/obj/effect/temp_visual/dir_setting/speedbike_trail
name = "speedbike trails"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 6a706fede9..92fb2531b8 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -111,7 +111,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
-
/obj/item/Initialize()
materials = typelist("materials", materials)
@@ -537,6 +536,17 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.become_blind(EYE_DAMAGE)
to_chat(M, "You go blind!")
+/obj/item/clean_blood()
+ . = ..()
+ if(.)
+ if(blood_splatter_icon)
+ cut_overlay(blood_splatter_icon)
+
+/obj/item/clothing/gloves/clean_blood()
+ . = ..()
+ if(.)
+ transfer_blood = 0
+
/obj/item/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_FOUR)
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 639d570462..1059a310eb 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -31,6 +31,15 @@
/obj/item/stock_parts/manipulator = 1,
/obj/item/stack/sheet/glass = 1)
+/obj/item/circuitboard/machine/bloodbankgen
+ name = "Blood Bank Generator (Machine Board)"
+ build_path = /obj/machinery/bloodbankgen
+ req_components = list(
+ /obj/item/stock_parts/matter_bin = 1,
+ /obj/item/stock_parts/manipulator = 1,
+ /obj/item/stack/cable_coil = 5,
+ /obj/item/stack/sheet/glass = 1)
+
/obj/item/circuitboard/machine/clonepod
name = "Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 7655654f78..d644e0637e 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -410,7 +410,7 @@ SLIME SCANNER
msg += "Subject is bleeding!\n"
var/blood_percent = round((C.blood_volume / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
var/blood_type = C.dna.blood_type
- if(blood_id != "blood")//special blood substance
+ if(blood_id != ("blood" || "jellyblood"))//special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
if(R)
blood_type = R.name
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 7524fc9007..3f7fe7ee8d 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -27,6 +27,7 @@
/obj/item/mop/proc/clean(turf/A)
if(reagents.has_reagent("water", 1) || reagents.has_reagent("holywater", 1) || reagents.has_reagent("vodka", 1) || reagents.has_reagent("cleaner", 1))
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
+ A.clean_blood()
for(var/obj/effect/O in A)
if(is_cleanable(O))
qdel(O)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 5610cbad9a..886997eab9 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -17,7 +17,6 @@
var/self_delay = 50
/obj/item/stack/medical/attack(mob/living/M, mob/user)
-
if(M.stat == DEAD && !stop_bleeding)
var/t_him = "it"
if(M.gender == MALE)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 155d1f1643..7654199cf5 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -390,9 +390,9 @@
. = ..()
/obj/item/stack/proc/copy_evidences(obj/item/stack/from)
- add_blood_DNA(from.return_blood_DNA())
- add_fingerprint_list(from.return_fingerprints())
- add_hiddenprint_list(from.return_hiddenprints())
+ blood_DNA = from.blood_DNA
+ fingerprints = from.fingerprints
+ fingerprintshidden = from.fingerprintshidden
fingerprintslast = from.fingerprintslast
//TODO bloody overlay
@@ -437,4 +437,4 @@
/datum/stack_recipe_list/New(title, recipes)
src.title = title
- src.recipes = recipes
+ src.recipes = recipes
\ No newline at end of file
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index d18212be42..1861947832 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -35,6 +35,8 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
/obj/item/storage/toolbox/update_icon()
..()
cut_overlays()
+ if(blood_DNA && blood_DNA.len)
+ add_blood_overlay()
if(has_latches)
var/icon/I = icon('icons/obj/storage.dmi', latches)
add_overlay(I)
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index b1c2c36585..dda704e1bf 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -346,7 +346,8 @@
icon_state = "dualsaber[item_color][wielded]"
else
icon_state = "dualsaber0"
- SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+
+ clean_blood()
/obj/item/twohanded/dualsaber/attack(mob/target, mob/living/carbon/human/user)
if(user.has_dna())
@@ -891,4 +892,4 @@
var/client/C = user.client
C.change_view(CONFIG_GET(string/default_view))
user.client.pixel_x = 0
- user.client.pixel_y = 0
+ user.client.pixel_y = 0
\ No newline at end of file
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 46db567b10..76c8f7f11f 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -318,6 +318,7 @@
/obj/machinery/shower/proc/wash_obj(obj/O)
. = SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ . = O.clean_blood()
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
if(isitem(O))
var/obj/item/I = O
@@ -328,8 +329,9 @@
/obj/machinery/shower/proc/wash_turf()
if(isturf(loc))
var/turf/tile = loc
- SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
tile.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ tile.clean_blood()
+ SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
for(var/obj/effect/E in tile)
if(is_cleanable(E))
qdel(E)
@@ -381,7 +383,8 @@
else if(H.w_uniform && wash_obj(H.w_uniform))
H.update_inv_w_uniform()
if(washgloves)
- SEND_SIGNAL(H, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ H.clean_blood()
+ SEND_SIGNAL(H, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
if(H.shoes && washshoes && wash_obj(H.shoes))
H.update_inv_shoes()
if(H.wear_mask && washmask && wash_obj(H.wear_mask))
@@ -398,9 +401,11 @@
else
if(M.wear_mask && wash_obj(M.wear_mask))
M.update_inv_wear_mask(0)
- SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ M.clean_blood()
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
else
- SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ L.clean_blood()
+ SEND_SIGNAL(L, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
/obj/machinery/shower/proc/contamination_cleanse(atom/movable/thing)
var/datum/component/radioactive/healthy_green_glow = thing.GetComponent(/datum/component/radioactive)
@@ -498,7 +503,8 @@
H.regenerate_icons()
user.drowsyness = max(user.drowsyness - rand(2,3), 0) //Washing your face wakes you up if you're falling asleep
else
- SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ user.clean_blood()
/obj/structure/sink/attackby(obj/item/O, mob/living/user, params)
if(busy)
@@ -554,7 +560,8 @@
busy = FALSE
return 1
busy = FALSE
- SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ O.clean_blood()
O.acid_level = 0
create_reagents(5)
reagents.add_reagent(dispensedreagent, 5)
@@ -675,4 +682,4 @@
else
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
if(BURN)
- playsound(loc, 'sound/items/welder.ogg', 80, 1)
+ playsound(loc, 'sound/items/welder.ogg', 80, 1)
\ No newline at end of file
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index f6d234b346..bd24e0ff93 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -251,6 +251,7 @@
M.apply_water()
SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ clean_blood()
for(var/obj/effect/O in src)
if(is_cleanable(O))
qdel(O)
diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
index 2018067b77..8000be87e6 100644
--- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
@@ -366,6 +366,8 @@
break
if(!GLOB.ratvar_awakens)
+ if(GLOB.clockwork_vitality <= 0)
+ break
GLOB.clockwork_vitality -= vitality_used
sleep(2)
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 57488a6722..6ea2dd1ce9 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -324,14 +324,11 @@
cooldown = world.time + cooldown_time
/obj/item/voodoo/proc/update_targets()
- possible = list()
+ LAZYINITLIST(possible)
if(!voodoo_link)
return
- var/list/prints = voodoo_link.return_fingerprints()
- if(!length(prints))
- return FALSE
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- if(prints[md5(H.dna.uni_identity)])
+ if(md5(H.dna.uni_identity) in voodoo_link.fingerprints)
possible |= H
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index c9e9c37f6c..89c463f3e3 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -35,4 +35,4 @@
A.flags_1 |= ADMIN_SPAWNED_1
else
for(var/item in contains)
- new item(C)
\ No newline at end of file
+ new item(C)
diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm
index e1d27c5022..656474cc1d 100644
--- a/code/modules/cargo/packs/medical.dm
+++ b/code/modules/cargo/packs/medical.dm
@@ -30,17 +30,31 @@
/datum/supply_pack/medical/bloodpacks
name = "Blood Pack Variety Crate"
- desc = "Contains eight different blood packs for reintroducing blood to patients."
+ desc = "Contains ten different blood packs for reintroducing blood to patients."
cost = 3000
- contains = list(/obj/item/reagent_containers/blood,
- /obj/item/reagent_containers/blood,
+ contains = list(/obj/item/reagent_containers/blood/random,
+ /obj/item/reagent_containers/blood/random,
/obj/item/reagent_containers/blood/APlus,
/obj/item/reagent_containers/blood/AMinus,
/obj/item/reagent_containers/blood/BPlus,
/obj/item/reagent_containers/blood/BMinus,
/obj/item/reagent_containers/blood/OPlus,
/obj/item/reagent_containers/blood/OMinus,
- /obj/item/reagent_containers/blood/lizard)
+ /obj/item/reagent_containers/blood/lizard,
+ /obj/item/reagent_containers/blood/jellyblood,
+ /obj/item/reagent_containers/blood/insect)
+ crate_name = "blood freezer"
+ crate_type = /obj/structure/closet/crate/freezer
+
+/datum/supply_pack/medical/bloodpackssynth
+ name = "Synthetics Blood Pack Crate"
+ desc = "Contains five synthetics blood packs for reintroducing blood to patients."
+ cost = 3000
+ contains = list(/obj/item/reagent_containers/blood/synthetics,
+ /obj/item/reagent_containers/blood/synthetics,
+ /obj/item/reagent_containers/blood/synthetics,
+ /obj/item/reagent_containers/blood/synthetics,
+ /obj/item/reagent_containers/blood/synthetics)
crate_name = "blood freezer"
crate_type = /obj/structure/closet/crate/freezer
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index f0c1eeb833..9d75fc6ce4 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -14,11 +14,10 @@
/obj/item/clothing/gloves/ComponentInitialize()
. = ..()
- AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/gloves/clean_blood)))
-/obj/item/clothing/gloves/proc/clean_blood(datum/source, strength)
- if(strength < CLEAN_STRENGTH_BLOOD)
- return
+/obj/item/clothing/gloves/clean_blood(datum/source, strength)
+ . = ..()
transfer_blood = 0
/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user)
@@ -30,8 +29,8 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
- IF_HAS_BLOOD_DNA(src)
- . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands")
+ if(blood_DNA)
+ . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE)
..()
@@ -41,4 +40,4 @@
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity)
- return 0 // return 1 to cancel attack_hand()
\ No newline at end of file
+ return FALSE // return TRUE to cancel attack_hand()
\ No newline at end of file
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index 8bd7065c1f..ccc167dcbc 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -46,8 +46,8 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
- IF_HAS_BLOOD_DNA(src)
- . += mutable_appearance('icons/effects/blood.dmi', "helmetblood")
+ if(blood_DNA)
+ . += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color())
/obj/item/clothing/head/update_clothes_damaged_state(damaging = TRUE)
..()
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 9ee2ebcd54..c00e6f72e0 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -59,8 +59,8 @@
if(body_parts_covered & HEAD)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
- IF_HAS_BLOOD_DNA(src)
- . += mutable_appearance('icons/effects/blood.dmi', "maskblood")
+ if(blood_DNA)
+ . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
/obj/item/clothing/mask/update_clothes_damaged_state(damaging = TRUE)
..()
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 330f69ddaf..2356bb16eb 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -12,8 +12,8 @@
if(body_parts_covered & HEAD)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
- IF_HAS_BLOOD_DNA(src)
- . += mutable_appearance('icons/effects/blood.dmi', "maskblood")
+ if(blood_DNA)
+ . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
/obj/item/clothing/neck/tie
name = "tie"
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index 00cb2678cd..488f59bb88 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -11,17 +11,19 @@
permeability_coefficient = 0.5
slowdown = SHOES_SLOWDOWN
var/blood_state = BLOOD_STATE_NOT_BLOODY
- var/list/bloody_shoes = list(BLOOD_STATE_HUMAN = 0,BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
+ var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
var/offset = 0
var/equipped_before_drop = FALSE
//CITADEL EDIT Enables digitigrade shoe styles
var/adjusted = NORMAL_STYLE
mutantrace_variation = MUTANTRACE_VARIATION
+ var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
+ var/last_blood_DNA = "" //same as last one
/obj/item/clothing/shoes/ComponentInitialize()
. = ..()
- AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/shoes/clean_blood)))
/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user)
if(rand(2)>1)
@@ -42,22 +44,29 @@
playsound(user, 'sound/weapons/genhit2.ogg', 50, 1)
return(BRUTELOSS)
+
+/obj/item/clothing/shoes/transfer_blood_dna(list/blood_dna, diseases)
+ ..()
+ if(blood_dna.len)
+ last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
+ last_blood_DNA = blood_dna[blood_dna.len]
+
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE)
. = list()
if(!isinhands)
var/bloody = FALSE
- IF_HAS_BLOOD_DNA(src)
+ if(blood_DNA)
bloody = TRUE
else
- bloody = bloody_shoes[BLOOD_STATE_HUMAN]
+ bloody = bloody_shoes[BLOOD_STATE_BLOOD]
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
if(bloody)
if(adjusted == NORMAL_STYLE)
- . += mutable_appearance('icons/effects/blood.dmi', "shoeblood")
+ . += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color())
else
- . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood")
+ . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color())
/obj/item/clothing/shoes/equipped(mob/user, slot)
. = ..()
@@ -93,14 +102,13 @@
var/mob/M = loc
M.update_inv_shoes()
-/obj/item/clothing/shoes/proc/clean_blood(datum/source, strength)
- if(strength < CLEAN_STRENGTH_BLOOD)
- return
- bloody_shoes = list(BLOOD_STATE_HUMAN = 0,BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
+/obj/item/clothing/shoes/clean_blood(datum/source, strength)
+ . = ..()
+ bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
if(ismob(loc))
var/mob/M = loc
M.update_inv_shoes()
/obj/item/proc/negates_gravity()
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 342429e480..6e469faaa4 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -1,74 +1,74 @@
-/obj/item/clothing/suit
- icon = 'icons/obj/clothing/suits.dmi'
- name = "suit"
- var/fire_resist = T0C+100
- allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
- slot_flags = ITEM_SLOT_OCLOTHING
- body_parts_covered = CHEST
- var/blood_overlay_type = "suit"
- var/togglename = null
- var/suittoggled = FALSE
-
- var/adjusted = NORMAL_STYLE
- mutantrace_variation = MUTANTRACE_VARIATION
- var/tauric = FALSE //Citadel Add for tauric hardsuits
- var/taurmode = NOT_TAURIC
- var/dimension_x = 32
- var/dimension_y = 32
- var/center = FALSE //Should we center the sprite?
-
-/obj/item/clothing/suit/equipped(mob/user, slot)
- ..()
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
-
- if(mutantrace_variation)
- if(DIGITIGRADE in H.dna.species.species_traits)
- adjusted = ALT_STYLE
- H.update_inv_wear_suit()
- else if(adjusted == ALT_STYLE)
- adjusted = NORMAL_STYLE
-
- if(("taur" in H.dna.species.mutant_bodyparts) && (H.dna.features["taur"] != "None"))
- if(H.dna.features["taur"] in list("Naga", "Tentacle"))
- taurmode = SNEK_TAURIC
- if(tauric == TRUE)
- center = TRUE
- dimension_x = 64
- else if(H.dna.features["taur"] in list("Fox","Wolf","Otie","Drake","Lab","Shepherd","Husky","Eevee","Panther","Horse","Cow","Tiger","Deer"))
- taurmode = PAW_TAURIC
- if(tauric == TRUE)
- center = TRUE
- dimension_x = 64
- else
- taurmode = NOT_TAURIC
- if(tauric == TRUE)
- center = FALSE
- dimension_x = 32
- H.update_inv_wear_suit()
-
-
-/obj/item/clothing/suit/worn_overlays(isinhands = FALSE)
- . = list()
- if(!isinhands)
- if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
- IF_HAS_BLOOD_DNA(src)
- if(tauric)
- . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood")
- else
- . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood")
- var/mob/living/carbon/human/M = loc
- if(ishuman(M) && M.w_uniform)
- var/obj/item/clothing/under/U = M.w_uniform
- if(istype(U) && U.attached_accessory)
- var/obj/item/clothing/accessory/A = U.attached_accessory
- if(A.above_suit)
- . += U.accessory_overlay
-
-/obj/item/clothing/suit/update_clothes_damaged_state(damaging = TRUE)
- ..()
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_wear_suit()
+/obj/item/clothing/suit
+ icon = 'icons/obj/clothing/suits.dmi'
+ name = "suit"
+ var/fire_resist = T0C+100
+ allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+ slot_flags = ITEM_SLOT_OCLOTHING
+ body_parts_covered = CHEST
+ var/blood_overlay_type = "suit"
+ var/togglename = null
+ var/suittoggled = FALSE
+
+ var/adjusted = NORMAL_STYLE
+ mutantrace_variation = MUTANTRACE_VARIATION
+ var/tauric = FALSE //Citadel Add for tauric hardsuits
+ var/taurmode = NOT_TAURIC
+ var/dimension_x = 32
+ var/dimension_y = 32
+ var/center = FALSE //Should we center the sprite?
+
+/obj/item/clothing/suit/equipped(mob/user, slot)
+ ..()
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+
+ if(mutantrace_variation)
+ if(DIGITIGRADE in H.dna.species.species_traits)
+ adjusted = ALT_STYLE
+ H.update_inv_wear_suit()
+ else if(adjusted == ALT_STYLE)
+ adjusted = NORMAL_STYLE
+
+ if(("taur" in H.dna.species.mutant_bodyparts) && (H.dna.features["taur"] != "None"))
+ if(H.dna.features["taur"] in GLOB.noodle_taurs)
+ taurmode = SNEK_TAURIC
+ if(tauric == TRUE)
+ center = TRUE
+ dimension_x = 64
+ else if(H.dna.features["taur"] in GLOB.paw_taurs)
+ taurmode = PAW_TAURIC
+ if(tauric == TRUE)
+ center = TRUE
+ dimension_x = 64
+ else
+ taurmode = NOT_TAURIC
+ if(tauric == TRUE)
+ center = FALSE
+ dimension_x = 32
+ H.update_inv_wear_suit()
+
+
+/obj/item/clothing/suit/worn_overlays(isinhands = FALSE)
+ . = list()
+ if(!isinhands)
+ if(damaged_clothes)
+ . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
+ if(blood_DNA)
+ if(tauric)
+ . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color())
+ else
+ . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood", color = blood_DNA_to_color())
+ var/mob/living/carbon/human/M = loc
+ if(ishuman(M) && M.w_uniform)
+ var/obj/item/clothing/under/U = M.w_uniform
+ if(istype(U) && U.attached_accessory)
+ var/obj/item/clothing/accessory/A = U.attached_accessory
+ if(A.above_suit)
+ . += U.accessory_overlay
+
+/obj/item/clothing/suit/update_clothes_damaged_state(damaging = TRUE)
+ ..()
+ if(ismob(loc))
+ var/mob/M = loc
+ M.update_inv_wear_suit()
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index c2c3f19b9d..eda0e31e93 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -22,8 +22,8 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
- IF_HAS_BLOOD_DNA(src)
- . += mutable_appearance('icons/effects/blood.dmi', "uniformblood")
+ if(blood_DNA)
+ . += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color())
if(accessory_overlay)
. += accessory_overlay
diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm
index c892bfeffc..1a2405b9c4 100644
--- a/code/modules/detectivework/detective_work.dm
+++ b/code/modules/detectivework/detective_work.dm
@@ -1,111 +1,107 @@
//CONTAINS: Suit fibers and Detective's Scanning Computer
-/atom/proc/return_fingerprints()
- GET_COMPONENT(D, /datum/component/forensics)
- if(D)
- . = D.fingerprints
+/atom/proc/add_fibers(mob/living/carbon/human/M)
+ if(M.gloves && istype(M.gloves, /obj/item/clothing/))
+ var/obj/item/clothing/gloves/G = M.gloves
+ if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects
+ if(add_blood_DNA(G.blood_DNA)) //only reduces the bloodiness of our gloves if the item wasn't already bloody
+ G.transfer_blood--
+ else if(M.bloody_hands > 1)
+ if(add_blood_DNA(M.blood_DNA, M.diseases))
+ M.bloody_hands--
+ if(!suit_fibers)
+ suit_fibers = list()
+ var/fibertext
+ var/item_multiplier = isitem(src)?1.2:1
+ if(M.wear_suit)
+ fibertext = "Material from \a [M.wear_suit]."
+ if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
+ suit_fibers += fibertext
+ if(!(M.wear_suit.body_parts_covered & CHEST))
+ if(M.w_uniform)
+ fibertext = "Fibers from \a [M.w_uniform]."
+ if(prob(12*item_multiplier) && !(fibertext in suit_fibers)) //Wearing a suit means less of the uniform exposed.
+ suit_fibers += fibertext
+ if(!(M.wear_suit.body_parts_covered & HANDS))
+ if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ suit_fibers += fibertext
+ else if(M.w_uniform)
+ fibertext = "Fibers from \a [M.w_uniform]."
+ if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
+ // "Added fibertext: [fibertext]"
+ suit_fibers += fibertext
+ if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ suit_fibers += "Material from a pair of [M.gloves.name]."
+ else if(M.gloves)
+ fibertext = "Material from a pair of [M.gloves.name]."
+ if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
+ suit_fibers += "Material from a pair of [M.gloves.name]."
-/atom/proc/return_hiddenprints()
- GET_COMPONENT(D, /datum/component/forensics)
- if(D)
- . = D.hiddenprints
-/atom/proc/return_blood_DNA()
- GET_COMPONENT(D, /datum/component/forensics)
- if(D)
- . = D.blood_DNA
+/atom/proc/add_hiddenprint(mob/living/M)
+ if(!M || !M.key)
+ return
-/atom/proc/blood_DNA_length()
- GET_COMPONENT(D, /datum/component/forensics)
- if(D)
- . = length(D.blood_DNA)
+ if(!fingerprintshidden) //Add the list if it does not exist
+ fingerprintshidden = list()
-/atom/proc/return_fibers()
- GET_COMPONENT(D, /datum/component/forensics)
- if(D)
- . = D.fibers
+ var/hasgloves = ""
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.gloves)
+ hasgloves = "(gloves)"
+
+ var/current_time = TIME_STAMP("hh:mm:ss", FALSE)
+ if(!fingerprintshidden[M.key])
+ fingerprintshidden[M.key] = "First: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
+ else
+ var/laststamppos = findtext(fingerprintshidden[M.key], " Last: ")
+ if(laststamppos)
+ fingerprintshidden[M.key] = copytext(fingerprintshidden[M.key], 1, laststamppos)
+ fingerprintshidden[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
+
+ fingerprintslast = M.ckey
-/atom/proc/add_fingerprint_list(list/fingerprints) //ASSOC LIST FINGERPRINT = FINGERPRINT
- if(length(fingerprints))
- . = AddComponent(/datum/component/forensics, fingerprints)
//Set ignoregloves to add prints irrespective of the mob having gloves on.
/atom/proc/add_fingerprint(mob/living/M, ignoregloves = FALSE)
- var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
- . = D.add_fingerprint(M, ignoregloves)
+ if(!M || !M.key)
+ return
-/atom/proc/add_fiber_list(list/fibertext) //ASSOC LIST FIBERTEXT = FIBERTEXT
- if(length(fibertext))
- . = AddComponent(/datum/component/forensics, null, null, null, fibertext)
+ add_hiddenprint(M)
-/atom/proc/add_fibers(mob/living/carbon/human/M)
- var/old = 0
- if(M.gloves && istype(M.gloves, /obj/item/clothing))
- var/obj/item/clothing/gloves/G = M.gloves
- old = length(G.return_blood_DNA())
- if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects
- if(add_blood_DNA(G.return_blood_DNA()) && length(G.return_blood_DNA()) > old) //only reduces the bloodiness of our gloves if the item wasn't already bloody
- G.transfer_blood--
- else if(M.bloody_hands > 1)
- old = length(M.return_blood_DNA())
- if(add_blood_DNA(M.return_blood_DNA()) && length(M.return_blood_DNA()) > old)
- M.bloody_hands--
- var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
- . = D.add_fibers(M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
-/atom/proc/add_hiddenprint_list(list/hiddenprints) //NOTE: THIS IS FOR ADMINISTRATION FINGERPRINTS, YOU MUST CUSTOM SET THIS TO INCLUDE CKEY/REAL NAMES! CHECK FORENSICS.DM
- if(length(hiddenprints))
- . = AddComponent(/datum/component/forensics, null, hiddenprints)
+ add_fibers(H)
-/atom/proc/add_hiddenprint(mob/living/M)
- var/datum/component/forensics/D = AddComponent(/datum/component/forensics)
- . = D.add_hiddenprint(M)
+ if(H.gloves) //Check if the gloves (if any) hide fingerprints
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.transfer_prints)
+ ignoregloves = TRUE
-/atom/proc/add_blood_DNA(list/dna) //ASSOC LIST DNA = BLOODTYPE
- return FALSE
+ if(!ignoregloves)
+ H.gloves.add_fingerprint(H, TRUE) //ignoregloves = TRUE to avoid infinite loop.
+ return
-/obj/add_blood_DNA(list/dna)
- . = ..()
- if(length(dna))
- . = AddComponent(/datum/component/forensics, null, null, dna)
-
-/obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
- . = ..()
- transfer_blood = rand(2, 4)
-
-/turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
- var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src
- if(!B)
- B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases)
- B.add_blood_DNA(blood_dna) //give blood info to the blood decal.
- return TRUE //we bloodied the floor
-
-/mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
- if(wear_suit)
- wear_suit.add_blood_DNA(blood_dna)
- update_inv_wear_suit()
- else if(w_uniform)
- w_uniform.add_blood_DNA(blood_dna)
- update_inv_w_uniform()
- if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- G.add_blood_DNA(blood_dna)
- else if(length(blood_dna))
- AddComponent(/datum/component/forensics, null, null, blood_dna)
- bloody_hands = rand(2, 4)
- if(head)
- head.add_blood_DNA(blood_dna)
- update_inv_head()
- else if(wear_mask)
- wear_mask.add_blood_DNA(blood_dna)
- update_inv_wear_mask()
- if(wear_neck)
- wear_neck.add_blood_DNA(blood_dna)
- update_inv_neck()
- update_inv_gloves() //handles bloody hands overlays and updating
- return TRUE
+ LAZYINITLIST(fingerprints) //Add the list if it does not exist
+ var/full_print = md5(H.dna.uni_identity)
+ fingerprints[full_print] = full_print
/atom/proc/transfer_fingerprints_to(atom/A)
- A.add_fingerprint_list(return_fingerprints())
- A.add_hiddenprint_list(return_hiddenprints())
- A.fingerprintslast = fingerprintslast
+ // Make sure everything are lists.
+ LAZYINITLIST(A.fingerprints)
+ LAZYINITLIST(A.fingerprintshidden)
+ LAZYINITLIST(fingerprints)
+ LAZYINITLIST(fingerprintshidden)
+
+ // Transfer
+ if(fingerprints)
+ A.fingerprints |= fingerprints.Copy() //detective
+ if(fingerprintshidden)
+ A.fingerprintshidden |= fingerprintshidden.Copy() //admin
+ A.fingerprintslast = fingerprintslast
\ No newline at end of file
diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm
index a3b17a4c1f..5b4a75a36c 100644
--- a/code/modules/detectivework/evidence.dm
+++ b/code/modules/detectivework/evidence.dm
@@ -16,7 +16,7 @@
/obj/item/evidencebag/attackby(obj/item/I, mob/user, params)
if(evidencebagEquip(I, user))
- return 1
+ return TRUE
/obj/item/evidencebag/handle_atom_del(atom/A)
cut_overlays()
@@ -25,12 +25,12 @@
desc = initial(desc)
/obj/item/evidencebag/proc/evidencebagEquip(obj/item/I, mob/user)
- if(!istype(I) || I.anchored == 1)
+ if(!istype(I) || I.anchored == TRUE)
return
if(istype(I, /obj/item/evidencebag))
to_chat(user, "You find putting an evidence bag in another evidence bag to be slightly absurd.")
- return 1 //now this is podracing
+ return TRUE //now this is podracing
if(I.w_class > WEIGHT_CLASS_NORMAL)
to_chat(user, "[I] won't fit in [src].")
@@ -62,7 +62,7 @@
desc = "An evidence bag containing [I]. [I.desc]"
I.forceMove(src)
w_class = I.w_class
- return 1
+ return TRUE
/obj/item/evidencebag/attack_self(mob/user)
if(contents.len)
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index fd7591db81..c578d5b4d4 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -14,7 +14,7 @@
flags_1 = CONDUCT_1
item_flags = NOBLUDGEON
slot_flags = ITEM_SLOT_BELT
- var/scanning = 0
+ var/scanning = FALSE
var/list/log = list()
var/range = 8
var/view_check = TRUE
@@ -30,7 +30,7 @@
/obj/item/detective_scanner/attack_self(mob/user)
if(log.len && !scanning)
- scanning = 1
+ scanning = TRUE
to_chat(user, "Printing report, please wait...")
addtimer(CALLBACK(src, .proc/PrintReport), 100)
else
@@ -56,7 +56,7 @@
// Clear the logs
log = list()
- scanning = 0
+ scanning = FALSE
/obj/item/detective_scanner/afterattack(atom/A, mob/user, params)
. = ..()
@@ -70,7 +70,7 @@
if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
return
- scanning = 1
+ scanning = TRUE
user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.")
to_chat(user, "You scan \the [A]. The scanner is now analysing the results...")
@@ -80,14 +80,20 @@
//Make our lists
var/list/fingerprints = list()
- var/list/blood = A.return_blood_DNA()
- var/list/fibers = A.return_fibers()
+ var/list/blood = list()
+ var/list/fibers = list()
var/list/reagents = list()
var/target_name = A.name
// Start gathering
+ if(A.blood_DNA && A.blood_DNA.len)
+ blood = A.blood_DNA.Copy()
+
+ if(A.suit_fibers && A.suit_fibers.len)
+ fibers = A.suit_fibers.Copy()
+
if(ishuman(A))
var/mob/living/carbon/human/H = A
@@ -96,7 +102,8 @@
else if(!ismob(A))
- fingerprints = A.return_fingerprints()
+ if(A.fingerprints && A.fingerprints.len)
+ fingerprints = A.fingerprints.Copy()
// Only get reagents from non-mobs.
if(A.reagents && A.reagents.reagent_list.len)
@@ -115,40 +122,40 @@
// We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
- var/found_something = 0
+ var/found_something = FALSE
add_log("[STATION_TIME_TIMESTAMP("hh:mm:ss")][get_timestamp()] - [target_name]", 0)
// Fingerprints
if(length(fingerprints))
- sleep(30)
+ sleep(3 SECONDS)
add_log("Prints:")
for(var/finger in fingerprints)
add_log("[finger]")
- found_something = 1
+ found_something = TRUE
// Blood
if (length(blood))
- sleep(30)
+ sleep(3 SECONDS)
add_log("Blood:")
- found_something = 1
+ found_something = TRUE
for(var/B in blood)
add_log("Type: [blood[B]] DNA: [B]")
//Fibers
if(length(fibers))
- sleep(30)
+ sleep(3 SECONDS)
add_log("Fibers:")
for(var/fiber in fibers)
add_log("[fiber]")
- found_something = 1
+ found_something = TRUE
//Reagents
if(length(reagents))
- sleep(30)
+ sleep(3 SECONDS)
add_log("Reagents:")
for(var/R in reagents)
add_log("Reagent: [R] Volume: [reagents[R]]")
- found_something = 1
+ found_something = TRUE
// Get a new user
var/mob/holder = null
@@ -164,10 +171,10 @@
to_chat(holder, "You finish scanning \the [target_name].")
add_log("---------------------------------------------------------", 0)
- scanning = 0
+ scanning = FALSE
return
-/obj/item/detective_scanner/proc/add_log(msg, broadcast = 1)
+/obj/item/detective_scanner/proc/add_log(msg, broadcast = TRUE)
if(scanning)
if(broadcast && ismob(loc))
var/mob/M = loc
@@ -207,4 +214,4 @@
return
to_chat(user, "Scanner Report")
for(var/iterLog in log)
- to_chat(user, iterLog)
+ to_chat(user, iterLog)
\ No newline at end of file
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index ca1a961a92..757aadaea1 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -2,6 +2,9 @@
BLOOD SYSTEM
****************************************************/
+#define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations.
+
+
/mob/living/carbon/human/proc/suppress_bloodloss(amount)
if(bleedsuppress)
return
@@ -30,6 +33,9 @@
bleed_rate = 0
return
+ if(bleed_rate <= 0)
+ bleed_rate = 0
+
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
@@ -80,6 +86,9 @@
var/obj/item/bodypart/BP = X
var/brutedamage = BP.brute_dam
+ if(BP.status == BODYPART_ROBOTIC) //for the moment, synth limbs won't bleed, but soon, my pretty.
+ continue
+
//We want an accurate reading of .len
listclearnulls(BP.embedded_objects)
temp_bleed += 0.5*BP.embedded_objects.len
@@ -87,7 +96,7 @@
if(brutedamage >= 20)
temp_bleed += (brutedamage * 0.013)
- bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
+ bleed_rate = max(bleed_rate - 0.50, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
if(bleed_rate && !bleedsuppress && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
bleed(bleed_rate)
@@ -105,9 +114,11 @@
/mob/living/carbon/human/bleed(amt)
amt *= physiology.bleed_mod
if(!(NOBLOOD in dna.species.species_traits))
- ..()
-
-
+ .=..()
+ if(dna.species.exotic_blood && .) // Do we have exotic blood, and have we left any on the ground?
+ var/datum/reagent/R = GLOB.chemical_reagents_list[get_blood_id()]
+ if(istype(R) && isturf(loc))
+ R.reaction_turf(get_turf(src), amt * EXOTIC_BLEED_MULTIPLIER)
/mob/living/proc/restore_blood()
blood_volume = initial(blood_volume)
@@ -123,16 +134,16 @@
//Gets blood from mob to a container or other mob, preserving all data in it.
/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
if(!blood_volume || !AM.reagents)
- return 0
+ return FALSE
if(blood_volume < (BLOOD_VOLUME_BAD * blood_ratio) && !forced)
- return 0
+ return FALSE
if(blood_volume < amount)
amount = blood_volume
var/blood_id = get_blood_id()
if(!blood_id)
- return 0
+ return FALSE
blood_volume -= amount
@@ -141,29 +152,27 @@
if(iscarbon(AM))
var/mob/living/carbon/C = AM
if(blood_id == C.get_blood_id())//both mobs have the same blood substance
- if(blood_id == "blood") //normal blood
+ if(blood_id == "blood" || blood_id == "jellyblood") //normal blood
if(blood_data["viruses"])
for(var/thing in blood_data["viruses"])
var/datum/disease/D = thing
if((D.spread_flags & DISEASE_SPREAD_SPECIAL) || (D.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS))
continue
C.ForceContractDisease(D)
- if(!(blood_data["blood_type"] in get_safe_blood(C.dna.blood_type)))
- C.reagents.add_reagent("toxin", amount * 0.5)
- return 1
+ //This used to inject oof ouch results, but since we add the reagent, and the reagent causes oof ouch on mob life... why double dip?
C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM)
- return 1
+ return TRUE
AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature)
- return 1
+ return TRUE
/mob/living/proc/get_blood_data(blood_id)
return
/mob/living/carbon/get_blood_data(blood_id)
- if(blood_id == "blood") //actual blood reagent
+ if(blood_id == "blood" || blood_id == "jellyblood") //actual blood reagent
var/blood_data = list()
//set the blood data
blood_data["donor"] = src
@@ -174,6 +183,7 @@
blood_data["viruses"] += D.Copy()
blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0)
+ blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
if(disease_resistances && disease_resistances.len)
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
@@ -206,21 +216,6 @@
if(istype(ling))
blood_data["changeling_loudness"] = ling.loudfactor
return blood_data
- if(blood_id == "slimejelly") //Just so MKUltra works. Takes the minimum required data. Sishen is testing if this breaks stuff.
- var/blood_data = list()
- if(mind)
- blood_data["mind"] = mind
- else if(last_mind)
- blood_data["mind"] = last_mind
- if(ckey)
- blood_data["ckey"] = ckey
- else if(last_mind)
- blood_data["ckey"] = ckey(last_mind.key)
- blood_data["gender"] = gender
- blood_data["real_name"] = real_name
- return blood_data
-
-
//get the id of the substance this mob use as blood.
/mob/proc/get_blood_id()
@@ -234,12 +229,15 @@
if(!(HAS_TRAIT(src, TRAIT_NOCLONE)))
return "blood"
-/mob/living/carbon/human/get_blood_id()
- if(dna.species.exotic_blood)
+/mob/living/carbon/get_blood_id()
+ if(isjellyperson(src))
+ return "jellyblood"
+ if(dna?.species?.exotic_blood)
return dna.species.exotic_blood
else if((NOBLOOD in dna.species.species_traits) || (HAS_TRAIT(src, TRAIT_NOCLONE)))
return
- return "blood"
+ else
+ return "blood"
// This is has more potential uses, and is probably faster than the old proc.
/proc/get_safe_blood(bloodtype)
@@ -248,16 +246,21 @@
return
var/static/list/bloodtypes_safe = list(
- "A-" = list("A-", "O-"),
- "A+" = list("A-", "A+", "O-", "O+"),
- "B-" = list("B-", "O-"),
- "B+" = list("B-", "B+", "O-", "O+"),
- "AB-" = list("A-", "B-", "O-", "AB-"),
- "AB+" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+"),
- "O-" = list("O-"),
- "O+" = list("O-", "O+"),
- "L" = list("L"),
- "U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U")
+ "A-" = list("A-", "O-", "SY"),
+ "A+" = list("A-", "A+", "O-", "O+", "SY"),
+ "B-" = list("B-", "O-", "SY"),
+ "B+" = list("B-", "B+", "O-", "O+", "SY"),
+ "AB-" = list("A-", "B-", "O-", "AB-", "SY"),
+ "AB+" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "SY"),
+ "O-" = list("O-","SY"),
+ "O+" = list("O-", "O+","SY"),
+ "L" = list("L","SY"),
+ "U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U","SY"),
+ "HF" = list("HF", "SY"),
+ "X*" = list("X*", "SY"),
+ "SY" = list("SY"),
+ "GEL" = list("GEL","SY"),
+ "BUG" = list("BUG", "SY")
)
var/safe = bloodtypes_safe[bloodtype]
@@ -266,7 +269,7 @@
//to add a splatter of blood or other mob liquid.
/mob/living/proc/add_splatter_floor(turf/T, small_drip)
- if(get_blood_id() != "blood")
+ if(get_blood_id() == null)
return
if(!T)
T = get_turf(src)
@@ -280,24 +283,27 @@
drop.drips++
drop.add_overlay(pick(drop.random_icon_states))
drop.transfer_mob_blood_dna(src)
+ drop.update_icon()
return
else
- temp_blood_DNA = drop.return_blood_DNA() //we transfer the dna from the drip to the splatter
+ temp_blood_DNA = list()
+ temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter
qdel(drop)//the drip is replaced by a bigger splatter
else
drop = new(T, get_static_viruses())
drop.transfer_mob_blood_dna(src)
+ drop.update_icon()
return
// Find a blood decal or create a new one.
- var/obj/effect/decal/cleanable/blood/B = locate() in T
+ var/obj/effect/decal/cleanable/blood/splats/B = locate() in T
if(!B)
- B = new /obj/effect/decal/cleanable/blood/splatter(T, get_static_viruses())
- if (B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit
+ B = new /obj/effect/decal/cleanable/blood/splats(T, get_static_viruses())
+ if(B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit
B.bloodiness += BLOOD_AMOUNT_PER_DECAL
B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
if(temp_blood_DNA)
- B.add_blood_DNA(temp_blood_DNA)
+ B.blood_DNA |= temp_blood_DNA
/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
if(!(NOBLOOD in dna.species.species_traits))
@@ -306,10 +312,10 @@
/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip)
if(!T)
T = get_turf(src)
- var/obj/effect/decal/cleanable/xenoblood/B = locate() in T.contents
+ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in T.contents
if(!B)
B = new(T)
- B.add_blood_DNA(list("UNKNOWN DNA" = "X*"))
+ B.blood_DNA["UNKNOWN DNA"] = "X*"
/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip)
if(!T)
@@ -318,6 +324,44 @@
if(!B)
B = new(T)
+/mob/living/proc/add_splash_floor(turf/T)
+ if(get_blood_id() == null)
+ return
+ if(!T)
+ T = get_turf(src)
+
+ var/list/temp_blood_DNA
+
+ // Find a blood decal or create a new one.
+ var/obj/effect/decal/cleanable/blood/B = locate() in T
+ if(!B)
+ B = new /obj/effect/decal/cleanable/blood/splatter(T, get_static_viruses())
+ if(B.bloodiness < MAX_SHOE_BLOODINESS) //add more blood, up to a limit
+ B.bloodiness += BLOOD_AMOUNT_PER_DECAL
+ B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
+ src.transfer_blood_to(B, 10) //very heavy bleeding, should logically leave larger pools
+ if(temp_blood_DNA)
+ B.blood_DNA |= temp_blood_DNA
+
+/mob/living/carbon/human/add_splash_floor(turf/T)
+ if(!(NOBLOOD in dna.species.species_traits))
+ ..()
+
+/mob/living/carbon/alien/add_splash_floor(turf/T)
+ if(!T)
+ T = get_turf(src)
+ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in T.contents
+ if(!B)
+ B = new(T)
+ B.blood_DNA["UNKNOWN DNA"] = "X*"
+
+/mob/living/silicon/robot/add_splash_floor(turf/T)
+ if(!T)
+ T = get_turf(src)
+ var/obj/effect/decal/cleanable/oil/B = locate() in T.contents
+ if(!B)
+ B = new(T)
+
//This is a terrible way of handling it.
/mob/living/proc/ResetBloodVol()
if(ishuman(src))
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index cc11c0e8bb..19500653d9 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -147,9 +147,9 @@
/mob/living/proc/exit_blood_effect(obj/effect/decal/cleanable/B)
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
//Makes the mob have the color of the blood pool it came out of
- var/newcolor = rgb(149, 10, 10)
- if(istype(B, /obj/effect/decal/cleanable/xenoblood))
- newcolor = rgb(43, 186, 0)
+ var/newcolor = BLOOD_COLOR_HUMAN
+ if(istype(B, /obj/effect/decal/cleanable/blood/xeno))
+ newcolor = BLOOD_COLOR_XENO
add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
// but only for a few seconds
spawn(30)
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 97b29ca4e1..1b2944c1f6 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -10,7 +10,10 @@
/mob/living/brain/Initialize()
. = ..()
create_dna(src)
- stored_dna.initialize_dna(random_blood_type())
+ if(stored_dna.blood_type)
+ stored_dna.initialize_dna(stored_dna.blood_type)
+ else
+ stored_dna.initialize_dna(random_blood_type())
if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned)
var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it.
OB.brainmob = src
@@ -21,6 +24,8 @@
if(!stored_dna.species)
var/rando_race = pick(GLOB.roundstart_races)
stored_dna.species = new rando_race()
+ if(stored_dna.species.exotic_bloodtype)
+ stored_dna.blood_type = stored_dna.species.exotic_bloodtype
/mob/living/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index c8ece3f656..3ad7acfcdc 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -20,7 +20,7 @@
var/heat_protection = 0.5
var/leaping = 0
- gib_type = /obj/effect/decal/cleanable/xenoblood/xgibs
+ gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
unique_name = 1
var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?")
diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm
index ce2b4401e9..77300e1435 100644
--- a/code/modules/mob/living/carbon/alien/death.dm
+++ b/code/modules/mob/living/carbon/alien/death.dm
@@ -2,7 +2,7 @@
if(with_bodyparts)
new /obj/effect/gibspawner/xeno(drop_location())
else
- new /obj/effect/gibspawner/xenobodypartless(drop_location())
+ new /obj/effect/gibspawner/xeno/bodypartless(drop_location())
/mob/living/carbon/alien/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-a")
diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm
index e16be71ccf..e7cf70f441 100644
--- a/code/modules/mob/living/carbon/alien/larva/death.dm
+++ b/code/modules/mob/living/carbon/alien/larva/death.dm
@@ -10,7 +10,7 @@
if(with_bodyparts)
new /obj/effect/gibspawner/larva(drop_location())
else
- new /obj/effect/gibspawner/larvabodypartless(drop_location())
+ new /obj/effect/gibspawner/larva/bodypartless(drop_location())
/mob/living/carbon/alien/larva/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-l")
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index df1be454ee..7b6962794a 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -89,6 +89,8 @@
owner.adjustFireLoss(-heal_amt)
owner.adjustOxyLoss(-heal_amt)
owner.adjustCloneLoss(-heal_amt)
+ if(owner.blood_volume && (owner.blood_volume < BLOOD_VOLUME_NORMAL))
+ owner.blood_volume += 5
else
owner.adjustPlasma(plasma_rate * 0.1)
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 41daf642f2..a1184613fe 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -49,6 +49,7 @@
//Gets filled up in create_bodyparts()
var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
+ var/list/leg_bodyparts = list()
var/icon_render_key = ""
var/static/list/limb_icon_cache = list()
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index cc0c0d7434..b509b31e5f 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -85,7 +85,7 @@
if(!forced && HAS_TRAIT(src, TRAIT_TOXINLOVER)) //damage becomes healing and healing becomes damage
amount = -amount
if(amount > 0)
- blood_volume -= 5*amount
+ blood_volume -= 3*amount // x5 is too much, x3 should be still penalizing enough.
else
blood_volume -= amount
return ..()
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 64b75bc801..b0c3f61eec 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -5,10 +5,35 @@
new /obj/effect/temp_visual/dust_animation(loc, "dust-h")
/mob/living/carbon/human/spawn_gibs(with_bodyparts)
- if(with_bodyparts)
- new /obj/effect/gibspawner/human(drop_location(), dna, get_static_viruses())
+ if(isjellyperson(src))
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/slime(drop_location(), dna, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/slime/bodypartless(drop_location(), dna, get_static_viruses())
+
+ if(isipcperson(src))
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/ipc(drop_location(), dna, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/ipc/bodypartless(drop_location(), dna, get_static_viruses())
+
+ if(isxenoperson(src))
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/xeno/xenoperson(drop_location(), dna, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/xeno/xenoperson/bodypartless(drop_location(), dna, get_static_viruses())
+
+ if(islizard(src))
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/lizard(drop_location(), dna, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/lizard/bodypartless(drop_location(), dna, get_static_viruses())
+
else
- new /obj/effect/gibspawner/humanbodypartless(drop_location(), dna, get_static_viruses())
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/human(drop_location(), dna, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/human/bodypartless(drop_location(), dna, get_static_viruses())
/mob/living/carbon/human/spawn_dust(just_ash = FALSE)
if(just_ash)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 6ebc4f8a32..a4eee82e0c 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -1,4 +1,4 @@
-/mob/living/carbon/human/examine(mob/user) //User is the person being examined
+/mob/living/carbon/human/examine(mob/user)
//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
var/t_He = p_they(TRUE)
var/t_His = p_their(TRUE)
@@ -45,7 +45,7 @@
if(wear_suit)
msg += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)].\n"
//suit/armor storage
- if(s_store)
+ if(s_store && !(SLOT_S_STORE in obscured))
msg += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name].\n"
//back
if(back)
@@ -56,11 +56,10 @@
if(!(I.item_flags & ABSTRACT))
msg += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
- GET_COMPONENT(FR, /datum/component/forensics)
//gloves
if(gloves && !(SLOT_GLOVES in obscured))
msg += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands.\n"
- else if(FR && length(FR.blood_DNA))
+ else if(length(blood_DNA))
var/hand_number = get_num_arms(FALSE)
if(hand_number)
msg += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!\n"
@@ -86,7 +85,7 @@
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
msg += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face.\n"
- if (wear_neck && !(SLOT_NECK in obscured))
+ if(wear_neck && !(SLOT_NECK in obscured))
msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
//eyes
@@ -152,7 +151,7 @@
var/temp = getBruteLoss() //no need to calculate each of these twice
- msg += ""
+ msg += "" //Everything below gets this span
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/list/disabled = list()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 02e6043462..f2ca5bc939 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -32,7 +32,7 @@
if(CONFIG_GET(flag/disable_stambuffer))
togglesprint()
- AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, .proc/clean_blood)))
+ AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /mob/living/carbon/human/clean_blood)))
/mob/living/carbon/human/ComponentInitialize()
@@ -689,16 +689,17 @@
if(..())
dropItemToGround(I)
-/mob/living/carbon/human/proc/clean_blood(datum/source, strength)
- if(strength < CLEAN_STRENGTH_BLOOD)
- return
- if(gloves)
- if(SEND_SIGNAL(gloves, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
- update_inv_gloves()
+/mob/living/carbon/human/clean_blood()
+ var/mob/living/carbon/human/H = src
+ if(H.gloves)
+ if(H.gloves.clean_blood())
+ H.update_inv_gloves()
else
- if(bloody_hands)
- bloody_hands = 0
- update_inv_gloves()
+ ..() // Clear the Blood_DNA list
+ if(H.bloody_hands)
+ H.bloody_hands = 0
+ H.update_inv_gloves()
+ update_icons() //apply the now updated overlays to the mob
/mob/living/carbon/human/wash_cream()
if(creamed) //clean both to prevent a rare bug
@@ -1104,3 +1105,18 @@
/mob/living/carbon/human/species/zombie/krokodil_addict
race = /datum/species/krokodil_addict
+
+/mob/living/carbon/human/species/mammal
+ race = /datum/species/mammal
+
+/mob/living/carbon/human/species/insect
+ race = /datum/species/insect
+
+/mob/living/carbon/human/species/xeno
+ race = /datum/species/xeno
+
+/mob/living/carbon/human/species/ipc
+ race = /datum/species/ipc
+
+/mob/living/carbon/human/species/roundstartslime
+ race = /datum/species/jelly/roundstartslime
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 657c32ba01..b1f11f6463 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -51,6 +51,9 @@
var/bleed_rate = 0 //how much are we bleeding
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
+ var/blood_state = BLOOD_STATE_NOT_BLOODY
+ var/list/blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
+
var/name_override //For temporary visible name changes
var/genital_override = FALSE //Force genitals on things incase of chems
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index b65d62b63b..8bc8866380 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -127,3 +127,9 @@
return FALSE
return .
+/*
+/mob/living/carbon/human/transfer_blood_dna(list/blood_dna)
+ ..()
+ if(blood_dna.len)
+ last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
+ last_blood_DNA = blood_dna[blood_dna.len]*/
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 6ea9c985e2..4e6f9e0eb9 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -56,20 +56,20 @@
//Bloody footprints
var/turf/T = get_turf(src)
if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
- for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
- if (oldFP.blood_state == S.blood_state)
- return
- //No oldFP or they're all a different kind of blood
- S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
- if (S.bloody_shoes[S.blood_state] > BLOOD_LOSS_IN_SPREAD)
- var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
- FP.blood_state = S.blood_state
- FP.entered_dirs |= dir
- FP.bloodiness = S.bloody_shoes[S.blood_state] - BLOOD_LOSS_IN_SPREAD
- FP.add_blood_DNA(S.return_blood_DNA())
- FP.update_icon()
+ var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
+ if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == bloodtype_to_color(S.last_bloodtype)))
+ return
+ S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state]-BLOOD_LOSS_PER_STEP)
+ var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
+ FP.blood_state = S.blood_state
+ FP.entered_dirs |= dir
+ FP.bloodiness = S.bloody_shoes[S.blood_state]
+ if(S.last_bloodtype)
+ FP.blood_DNA += list(S.last_blood_DNA = S.last_bloodtype)
+ FP.update_icon()
update_inv_shoes()
//End bloody footprints
+
S.step_action()
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index a59d9e914b..34b8abc311 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -339,7 +339,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
if(C.dna.species.exotic_bloodtype)
- C.dna.blood_type = random_blood_type()
+ if(!new_species.exotic_bloodtype)
+ C.dna.blood_type = random_blood_type()
+ else
+ C.dna.blood_type = new_species.exotic_bloodtype
if(DIGITIGRADE in species_traits)
C.Digitigrade_Leg_Swap(TRUE)
for(var/X in inherent_traits)
@@ -1024,6 +1027,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return "TAUR"
//END EDIT
+/* TODO: Snowflake trail marks
+// Impliments different trails for species depending on if they're wearing shoes.
+/datum/species/proc/get_move_trail(var/mob/living/carbon/human/H)
+ if(H.lying)
+ return /obj/effect/decal/cleanable/blood/footprints/tracks/body
+ if(H.shoes || (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)))
+ var/obj/item/clothing/shoes/shoes = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) ? H.wear_suit : H.shoes // suits take priority over shoes
+ return shoes.move_trail
+ else
+ return move_trail */
/datum/species/proc/spec_life(mob/living/carbon/human/H)
if(HAS_TRAIT(H, TRAIT_NOBREATH))
diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
index b4e55b60a5..d264f11b73 100644
--- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
@@ -17,6 +17,7 @@
toxic_food = MEAT | RAW
mutanteyes = /obj/item/organ/eyes/insect
should_draw_citadel = TRUE
+ exotic_bloodtype = "BUG"
/datum/species/insect/on_species_gain(mob/living/carbon/C)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index 043ee4fde1..0c3bcc2b00 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -10,6 +10,7 @@
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
disliked_food = null
liked_food = GROSS
+ exotic_bloodtype = "BUG"
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(chem.id == "pestkiller")
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index 0390d4accc..90714b390c 100644
--- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -65,7 +65,7 @@
miss_sound = 'sound/weapons/slashmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
skinned_type = /obj/item/stack/sheet/animalhide/xeno
- exotic_bloodtype = "L"
+ exotic_bloodtype = "X*"
damage_overlay_type = "xeno"
liked_food = MEAT
diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm
index 95b924ea18..135c98860a 100644
--- a/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -12,8 +12,8 @@
default_features = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
mutanttongue = /obj/item/organ/tongue/robot/ipc
-
- exotic_blood = "oil"
+ mutant_heart = /obj/item/organ/heart/ipc
+ exotic_bloodtype = "HF"
var/datum/action/innate/monitor_change/screen
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 8e98569644..f416854838 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -4,13 +4,15 @@
id = "jelly"
default_color = "00FF90"
say_mod = "chirps"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD,WINGCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
mutantlungs = /obj/item/organ/lungs/slime
+ mutant_heart = /obj/item/organ/heart/slime
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur", "deco_wings") //CIT CHANGE
default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None") //CIT CHANGE
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
- exotic_blood = "slimejelly"
+ exotic_blood = "jellyblood"
+ exotic_bloodtype = "GEL"
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
var/datum/action/innate/slime_change/slime_change //CIT CHANGE
@@ -121,7 +123,7 @@
name = "Xenobiological Slime Entity"
id = "slime"
default_color = "00FFFF"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
say_mod = "says"
hair_color = "mutcolor"
hair_alpha = 150
@@ -396,7 +398,7 @@
id = "slimeperson"
limbs_id = "slime"
default_color = "00FFFF"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
inherent_traits = list(TRAIT_TOXINLOVER)
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur")
default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index fa3e29f119..a68aded85f 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -180,7 +180,7 @@ There are several things that need to be remembered:
inv.update_icon()
if(!gloves && bloody_hands)
- var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER)
+ var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
if(get_num_arms() < 2)
if(has_left_hand())
bloody_overlay.icon_state = "bloodyhands_left"
@@ -270,6 +270,32 @@ There are several things that need to be remembered:
if(client && hud_used)
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_SHOES]
inv.update_icon()
+/*
+ if(!shoes && bloody_feet)
+ var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
+ if(dna.features["taur"] != "None")
+ if(dna.features["taur"] in GLOB.noodle_taurs)
+ bloody_overlay = mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "snekbloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
+ if(get_num_legs() < 2)
+ if(has_left_leg())
+ bloody_overlay.icon_state = "snekbloodyfeet_left"
+ else if(has_right_leg())
+ bloody_overlay.icon_state = "snekbloodyfeet_right"
+ else if(dna.features["taur"] in GLOB.paw_taurs)
+ bloody_overlay = mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "pawbloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
+ if(get_num_legs() < 2)
+ if(has_left_leg())
+ bloody_overlay.icon_state = "pawbloodyfeet_left"
+ else if(has_right_leg())
+ bloody_overlay.icon_state = "pawbloodyfeet_right"
+ else
+ if(get_num_legs() < 2)
+ if(has_left_leg())
+ bloody_overlay.icon_state = "bloodyfeet_left"
+ else if(has_right_leg())
+ bloody_overlay.icon_state = "bloodyfeet_right"
+
+ overlays_standing[GLOVES_LAYER] = bloody_overlay*/
if(shoes)
var/obj/item/clothing/shoes/S = shoes
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index cdae073af8..63a83ac96b 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -97,8 +97,12 @@
/mob/living/carbon/update_damage_overlays()
remove_overlay(DAMAGE_LAYER)
+ var/dam_colors = "#E62525"
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ dam_colors = bloodtype_to_color(H.dna.blood_type)
- var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER)
+ var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER, color = dam_colors)
overlays_standing[DAMAGE_LAYER] = damage_overlay
for(var/X in bodyparts)
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index ab1e906cf2..d31c368ca4 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -198,7 +198,6 @@
)
if(blood)
- target_types += /obj/effect/decal/cleanable/xenoblood
target_types += /obj/effect/decal/cleanable/blood
target_types += /obj/effect/decal/cleanable/trail_holder
target_types += /obj/effect/decal/cleanable/insectguts
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 1bc7493684..94283f82da 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -476,7 +476,8 @@
if(isturf(next))
if(bloodiness)
var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
- B.add_blood_DNA(return_blood_DNA())
+ if(blood_DNA && blood_DNA.len)
+ B.blood_DNA |= blood_DNA.Copy()
var/newdir = get_dir(next, loc)
if(newdir == dir)
B.setDir(newdir)
@@ -489,7 +490,6 @@
B.setDir(newdir)
bloodiness--
-
var/oldloc = loc
var/moved = step_towards(src, next) // attempt to move
if(cell)
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 3d92912f9c..5240b4d06c 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -168,7 +168,6 @@
/mob/living/simple_animal/hostile/alien/maid/Initialize(mapload)
. = ..()
- AddComponent(/datum/component/cleaning)
/mob/living/simple_animal/hostile/alien/maid/AttackingTarget()
if(ismovableatom(target))
@@ -177,6 +176,7 @@
qdel(target)
return TRUE
var/atom/movable/M = target
- SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ M.clean_blood()
visible_message("[src] polishes \the [target].")
return TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
index c2d0a214b4..910e9c3c4a 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
@@ -39,7 +39,7 @@
animal_species = /mob/living/simple_animal/hostile/asteroid/gutlunch
childtype = list(/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck = 45, /mob/living/simple_animal/hostile/asteroid/gutlunch/guthen = 55)
- wanted_objects = list(/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/blood/gibs/)
+ wanted_objects = list(/obj/effect/decal/cleanable/blood/gibs/xeno, /obj/effect/decal/cleanable/blood/gibs/)
var/obj/item/udder/gutlunch/udder = null
/mob/living/simple_animal/hostile/asteroid/gutlunch/Initialize()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 93b4d32123..8c287229d7 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -487,6 +487,26 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/mob/proc/can_hear()
. = TRUE
+/proc/bloodtype_to_color(var/type)
+ . = BLOOD_COLOR_HUMAN
+ switch(type)
+ if("U")//Universal blood; a bit orange
+ . = BLOOD_COLOR_UNIVERSAL
+ if("SY")//Synthetics blood; blue
+ . = BLOOD_COLOR_SYNTHETIC
+ if("L")//lizard, a bit pink/purple
+ . = BLOOD_COLOR_LIZARD
+ if("X*")//xeno blood; greenish yellow
+ . = BLOOD_COLOR_XENO
+ if("HF")// Oil/Hydraulic blood. something something why not. reee
+ . = BLOOD_COLOR_OIL
+ if("GEL")// slimepeople blood, rgb 0, 255, 144
+ . = BLOOD_COLOR_SLIME
+ if("BUG")// yellowish, like, y'know bug guts I guess.
+ . = BLOOD_COLOR_BUG
+ //add more stuff to the switch if you have more blood colors for different types
+ // the defines are in _DEFINES/misc.dm
+
//Examine text for traits shared by multiple types. I wish examine was less copypasted.
/mob/proc/common_trait_examine()
if(HAS_TRAIT(src, TRAIT_DISSECTED))
@@ -497,4 +517,4 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
dissectionmsg = " via Experimental Dissection"
else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Thorough Dissection"))
dissectionmsg = " via Thorough Dissection"
- . += "This body has been dissected and analyzed[dissectionmsg].
"
\ No newline at end of file
+ . += "This body has been dissected and analyzed[dissectionmsg].
"
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 5bcb7a60df..875a65d306 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -158,6 +158,7 @@
if(..())
if(reagents.total_volume)
if(M.reagents)
+ reagents.reaction(M, INJECT)
reagents.trans_to(M, reagents.total_volume)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index 1117bc1000..06ce7b91e4 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -170,7 +170,7 @@
if(iscarbon(user))
var/mob/living/carbon/C = user
user_dna = C.dna
- B.add_blood_DNA(user_dna)
+ B.add_blood_DNA(user_dna, C.diseases)
var/datum/callback/gibspawner = CALLBACK(GLOBAL_PROC, /proc/spawn_atom_to_turf, /obj/effect/gibspawner/generic, B, 1, FALSE, list(user_dna))
B.throw_at(target, BRAINS_BLOWN_THROW_RANGE, BRAINS_BLOWN_THROW_SPEED, callback=gibspawner)
return(BRUTELOSS)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index dace31c2f7..8b881b57ed 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -163,15 +163,26 @@
var/splatter_dir = dir
if(starting)
splatter_dir = get_dir(starting, target_loca)
- if(isalien(L))
+ var/obj/item/bodypart/B = L.get_bodypart(def_zone)
+ if(B.status == BODYPART_ROBOTIC) // So if you hit a robotic, it sparks instead of bloodspatters
+ do_sparks(2, FALSE, target.loc)
+ if(prob(25))
+ new /obj/effect/decal/cleanable/oil(target_loca)
+ else if(isalien(L))
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
else
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color(H.dna.blood_type))
+ else
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color())
+
if(iscarbon(L))
var/mob/living/carbon/C = L
C.bleed(damage)
else
L.add_splatter_floor(target_loca)
+
else if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm
index dfc6df537d..42aef1ec9d 100644
--- a/code/modules/projectiles/projectile/bullets/smg.dm
+++ b/code/modules/projectiles/projectile/bullets/smg.dm
@@ -17,31 +17,40 @@
/obj/item/projectile/bullet/c45_cleaning/on_hit(atom/target, blocked = FALSE)
. = ..()
var/turf/T = get_turf(target)
-
- //section shamelessly copypasta'd from the clean component
- SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
for(var/A in T)
if(is_cleanable(A))
qdel(A)
- else if(istype(A, /obj/item))
- var/obj/item/I = A
- SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- if(ismob(I.loc))
- var/mob/M = I.loc
+ else if(isitem(A))
+ var/obj/item/cleaned_item = A
+ SEND_SIGNAL(cleaned_item, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_item.clean_blood()
+ if(ismob(cleaned_item.loc))
+ var/mob/M = cleaned_item.loc
M.regenerate_icons()
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
- if(cleaned_human.head)
- SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- if(cleaned_human.wear_suit)
- SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- else if(cleaned_human.w_uniform)
- SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- if(cleaned_human.shoes)
- SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
- cleaned_human.wash_cream()
- cleaned_human.regenerate_icons()
+ if(cleaned_human.lying)
+ if(cleaned_human.head)
+ SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.head.clean_blood()
+ cleaned_human.update_inv_head()
+ if(cleaned_human.wear_suit)
+ SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.wear_suit.clean_blood()
+ cleaned_human.update_inv_wear_suit()
+ else if(cleaned_human.w_uniform)
+ SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.w_uniform.clean_blood()
+ cleaned_human.update_inv_w_uniform()
+ if(cleaned_human.shoes)
+ SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.shoes.clean_blood()
+ cleaned_human.update_inv_shoes()
+ SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ cleaned_human.clean_blood()
+ cleaned_human.wash_cream()
+ cleaned_human.regenerate_icons()
// 4.6x30mm (Autorifles)
@@ -57,4 +66,4 @@
/obj/item/projectile/bullet/incendiary/c46x30mm
name = "4.6x30mm incendiary bullet"
damage = 10
- fire_stacks = 1
+ fire_stacks = 1
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index 6efa4276b6..05fa4d382a 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -188,7 +188,7 @@
to_chat(usr, "ERROR: Cannot replicate virus strain.")
return
A = A.Copy()
- var/list/data = list("viruses" = list(A))
+ var/list/data = list("blood_DNA" = "UNKNOWN DNA", "blood_type" = "SY", "viruses" = list(A))
var/obj/item/reagent_containers/glass/bottle/B = new(drop_location())
B.name = "[A.name] culture bottle"
B.desc = "A small bottle. Contains [A.agent] culture in synthblood medium."
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 95b4a33c0d..7b41368495 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,9 +1,9 @@
/datum/reagent/blood
- data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_HUMAN, "blood_type"= null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
name = "Blood"
id = "blood"
- color = "#C80000" // rgb: 200, 0, 0
- description = "Blood from a human, or otherwise."
+ color = BLOOD_COLOR_HUMAN // rgb: 200, 0, 0
+ description = "Blood from some creature."
metabolization_rate = 5 //fast rate so it disappears fast.
taste_description = "iron"
taste_mult = 1.3
@@ -28,27 +28,75 @@
if(iscarbon(L))
var/mob/living/carbon/C = L
- if(C.get_blood_id() == "blood" && (method == INJECT || (method == INGEST && C.dna && C.dna.species && (DRINKSBLOOD in C.dna.species.species_traits))))
- if(!data || !(data["blood_type"] in get_safe_blood(C.dna.blood_type)))
- C.reagents.add_reagent("toxin", reac_volume * 0.5)
- else
- C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM)
+ var/blood_id = C.get_blood_id()
+ if((blood_id == "blood" || blood_id == "jellyblood") && (method == INJECT || (method == INGEST && C.dna && C.dna.species && (DRINKSBLOOD in C.dna.species.species_traits))))
+ C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM * C.blood_ratio)
+ // we don't care about bloodtype here, we're just refilling the mob
- if(reac_volume >= 10 && istype(L))
+ if(reac_volume >= 10 && istype(L) && method != INJECT)
L.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
+/datum/reagent/blood/on_mob_life(mob/living/carbon/C) //Because lethals are preferred over stamina. damnifino.
+ var/blood_id = C.get_blood_id()
+ if((blood_id == "blood" || blood_id == "jellyblood"))
+ if(!data || !(data["blood_type"] in get_safe_blood(C.dna.blood_type))) //we only care about bloodtype here because this is where the poisoning should be
+ C.adjustToxLoss(rand(2,8)*REM, TRUE, TRUE) //forced to ensure people don't use it to gain beneficial toxin as slime person
+ ..()
+
/datum/reagent/blood/reaction_obj(obj/O, volume)
if(volume >= 3 && istype(O))
- O.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
+ O.add_blood_DNA(data)
+
+/datum/reagent/blood/reaction_turf(turf/T, reac_volume)//splash the blood all over the place
+ if(!istype(T))
+ return
+ if(reac_volume < 3)
+ return
+
+ var/obj/effect/decal/cleanable/blood/B = locate() in T //find some blood here
+ if(!B)
+ B = new(T)
+ if(data["blood_DNA"])
+ B.blood_DNA[data["blood_DNA"]] = data["blood_type"]
+ if(!B.reagents)
+ B.reagents.add_reagent(id, reac_volume)
+ B.update_icon()
/datum/reagent/blood/on_new(list/data)
if(istype(data))
SetViruses(src, data)
+ color = bloodtype_to_color(data["blood_type"])
+ if(data["blood_type"] == "SY")
+ name = "Synthetic Blood"
+ taste_description = "oily"
+
+ if(data["blood_type"] == "X*")
+ name = "Xenomorph Blood"
+ taste_description = "acidic heresy"
+ shot_glass_icon_state = "shotglassgreen"
+ pH = 2.5
+
+ if(data["blood_type"] == "HF")
+ name = "Hydraulic Blood"
+ taste_description = "burnt oil"
+ pH = 9.75
+
+ if(data["blood_type"] == "BUG")
+ name = "Insect Blood"
+ taste_description = "greasy"
+ pH = 7.25
+
+ if(data["blood_type"] == "L")
+ name = "Lizard Blood"
+ taste_description = "spicy"
+ pH = 6.85
+
+
/datum/reagent/blood/on_merge(list/mix_data)
if(data && mix_data)
if(data["blood_DNA"] != mix_data["blood_DNA"])
- data["cloneable"] = 0 //On mix, consider the genetic sampling unviable for pod cloning if the DNA sample doesn't match.
+ data["cloneable"] = FALSE //On mix, consider the genetic sampling unviable for pod cloning if the DNA sample doesn't match.
if(data["viruses"] || mix_data["viruses"])
var/list/mix1 = data["viruses"]
@@ -78,27 +126,111 @@
var/datum/disease/D = thing
. += D
-/datum/reagent/blood/reaction_turf(turf/T, reac_volume)//splash the blood all over the place
- if(!istype(T))
- return
- if(reac_volume < 3)
- return
+/datum/reagent/blood/synthetics
+ data = list("donor"=null,"viruses"=null,"blood_DNA"="REPLICATED", "bloodcolor" = BLOOD_COLOR_SYNTHETIC, "blood_type"="SY","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Synthetic Blood"
+ id = "syntheticblood"
+ taste_description = "oily"
+ color = BLOOD_COLOR_SYNTHETIC // rgb: 11, 7, 48
- var/obj/effect/decal/cleanable/blood/B = locate() in T //find some blood here
- if(!B)
- B = new(T)
- if(data["blood_DNA"])
- B.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
+/datum/reagent/blood/lizard
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_LIZARD, "blood_type"="L","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Lizard Blood"
+ id = "lizardblood"
+ taste_description = "spicy"
+ color = BLOOD_COLOR_LIZARD // rgb: 11, 7, 48
+ pH = 6.85
+
+/datum/reagent/blood/jellyblood
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_SLIME, "blood_type"="GEL","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Slime Jelly Blood"
+ id = "jellyblood"
+ description = "A gooey semi-liquid produced from one of the deadliest lifeforms in existence. SO REAL."
+ color = BLOOD_COLOR_SLIME
+ taste_description = "slime"
+ taste_mult = 1.3
+ pH = 4
+
+/datum/reagent/blood/xenomorph
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_XENO, "blood_type"="X*","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Xenomorph Blood"
+ id = "xenoblood"
+ taste_description = "acidic heresy"
+ color = BLOOD_COLOR_XENO // greenish yellow ooze
+ shot_glass_icon_state = "shotglassgreen"
+ pH = 2.5
+
+/datum/reagent/blood/oil
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_OIL, "blood_type"="HF","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Hydraulic Blood"
+ id = "oilblood"
+ taste_description = "burnt oil"
+ color = BLOOD_COLOR_OIL // dark, y'know, expected batman colors.
+ pH = 9.75
+
+/datum/reagent/blood/insect
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_BUG, "blood_type"="BUG","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ name = "Insectoid Blood"
+ id = "bugblood"
+ taste_description = "waxy"
+ color = BLOOD_COLOR_BUG // Bug colored, I guess.
+ pH = 7.25
+
+
+/datum/reagent/blood/jellyblood/on_mob_life(mob/living/carbon/M)
+ if(prob(10))
+ if(M.dna?.species?.exotic_bloodtype != "GEL")
+ to_chat(M, "Your insides are burning!")
+ M.adjustToxLoss(rand(20,60)*REM, 0)
+ . = 1
+ else if(prob(40) && isjellyperson(M))
+ M.heal_bodypart_damage(2*REM)
+ . = 1
+ ..()
/datum/reagent/liquidgibs
name = "Liquid gibs"
id = "liquidgibs"
- color = "#FF9966"
+ color = BLOOD_COLOR_HUMAN
description = "You don't even want to think about what's in here."
taste_description = "gross iron"
shot_glass_icon_state = "shotglassred"
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_HUMAN, "blood_type"= "O+","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
pH = 7.45
+/datum/reagent/liquidgibs/xeno
+ name = "Liquid xeno gibs"
+ id = "liquidxenogibs"
+ color = BLOOD_COLOR_XENO
+ taste_description = "blended heresy"
+ shot_glass_icon_state = "shotglassgreen"
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_XENO, "blood_type"="X*","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ pH = 2.5
+
+/datum/reagent/liquidgibs/slime
+ name = "Slime sludge"
+ id = "liquidslimegibs"
+ color = BLOOD_COLOR_SLIME
+ taste_description = "slime"
+ shot_glass_icon_state = "shotglassgreen"
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_SLIME, "blood_type"="GEL","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ pH = 4
+
+/datum/reagent/liquidgibs/synth
+ name = "Synthetic sludge"
+ id = "liquidsyntheticgibs"
+ color = BLOOD_COLOR_SYNTHETIC
+ taste_description = "jellied plastic"
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_SYNTHETIC, "blood_type"="SY","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+
+/datum/reagent/liquidgibs/oil
+ name = "Hydraulic sludge"
+ id = "liquidoilgibs"
+ color = BLOOD_COLOR_OIL
+ taste_description = "chunky burnt oil"
+ data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_OIL, "blood_type"="HF","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
+ pH = 9.75
+
/datum/reagent/vaccine
//data must contain virus type
name = "Vaccine"
@@ -585,6 +717,30 @@
race = /datum/species/android
mutationtext = "The pain subsides. You feel... artificial."
+//Citadel Races
+/datum/reagent/mutationtoxin/mammal
+ name = "Mammal Mutation Toxin"
+ id = "mammalmutationtoxin"
+ description = "A glowing toxin."
+ color = "#5EFF3B" //RGB: 94, 255, 59
+ race = /datum/species/mammal
+ mutationtext = "The pain subsides. You feel... fluffier."
+
+/datum/reagent/mutationtoxin/insect
+ name = "Insect Mutation Toxin"
+ id = "insectmutationtoxin"
+ description = "A glowing toxin."
+ color = "#5EFF3B" //RGB: 94, 255, 59
+ race = /datum/species/insect
+ mutationtext = "The pain subsides. You feel... attracted to dark, moist areas."
+
+/datum/reagent/mutationtoxin/xenoperson
+ name = "Xeno-Hybrid Mutation Toxin"
+ id = "xenopersonmutationtoxin"
+ description = "A glowing toxin."
+ color = "#5EFF3B" //RGB: 94, 255, 59
+ race = /datum/species/xeno
+ mutationtext = "The pain subsides. You feel... oddly longing for the Queen." //sadly, not the British one.
//BLACKLISTED RACES
/datum/reagent/mutationtoxin/skeleton
@@ -947,12 +1103,12 @@
reagent_state = SOLID
taste_description = "iron"
pH = 6
-
+ overdose_threshold = 30
color = "#c2391d"
/datum/reagent/iron/on_mob_life(mob/living/carbon/C)
if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio))
- C.blood_volume += 0.5
+ C.blood_volume += 0.01 //we'll have synthetics from medbay.
..()
/datum/reagent/iron/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
@@ -961,6 +1117,17 @@
M.reagents.add_reagent("toxin", reac_volume)
..()
+/datum/reagent/iron/overdose_start(mob/living/M)
+ to_chat(M, "You start feeling your guts twisting painfully!")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "[id]_overdose", /datum/mood_event/overdose, name)
+
+/datum/reagent/iron/overdose_process(mob/living/carbon/C)
+ if(prob(20))
+ var/obj/item/organ/liver/L = C.getorganslot(ORGAN_SLOT_LIVER)
+ if (istype(L))
+ C.applyLiverDamage(2) //mild until the fabled med rework comes out. the organ damage galore
+ ..()
+
/datum/reagent/gold
name = "Gold"
id = "gold"
@@ -1077,17 +1244,19 @@
pH = 5.5
/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
- if(istype(O, /obj/effect/decal/cleanable))
+ if(istype(O, /obj/effect/decal/cleanable) || istype(O, /obj/item/projectile/bullet/reusable/foam_dart) || istype(O, /obj/item/ammo_casing/caseless/foam_dart))
qdel(O)
else
if(O)
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ O.clean_blood()
/datum/reagent/space_cleaner/reaction_turf(turf/T, reac_volume)
if(reac_volume >= 1)
T.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ T.clean_blood()
for(var/obj/effect/decal/cleanable/C in T)
qdel(C)
@@ -1105,26 +1274,33 @@
H.lip_style = null
H.update_body()
for(var/obj/item/I in C.held_items)
- SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ I.clean_blood()
if(C.wear_mask)
- if(SEND_SIGNAL(C.wear_mask, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ SEND_SIGNAL(C.wear_mask, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ if(C.wear_mask.clean_blood())
C.update_inv_wear_mask()
if(ishuman(M))
var/mob/living/carbon/human/H = C
if(H.head)
- if(SEND_SIGNAL(H.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ SEND_SIGNAL(H.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ if(H.head.clean_blood())
H.update_inv_head()
if(H.wear_suit)
- if(SEND_SIGNAL(H.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ SEND_SIGNAL(H.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ if(H.wear_suit.clean_blood())
H.update_inv_wear_suit()
else if(H.w_uniform)
- if(SEND_SIGNAL(H.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ SEND_SIGNAL(H.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ if(H.w_uniform.clean_blood())
H.update_inv_w_uniform()
if(H.shoes)
- if(SEND_SIGNAL(H.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ SEND_SIGNAL(H.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ if(H.shoes.clean_blood())
H.update_inv_shoes()
H.wash_cream()
- SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+ SEND_SIGNAL(M, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
+ M.clean_blood()
/datum/reagent/space_cleaner/ez_clean
name = "EZ Clean"
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 2ed9a31107..374f7715bb 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -283,6 +283,12 @@
results = list("regen_jelly" = 2)
required_reagents = list("tricordrazine" = 1, "slimejelly" = 1)
+/datum/chemical_reaction/jelly_convert
+ name = "Blood Jelly Conversion"
+ id = "blood_jelly"
+ results = list("slimejelly" = 1)
+ required_reagents = list("toxin" = 1, "jellyblood" = 1)
+
/datum/chemical_reaction/corazone
name = "Corazone"
id = "corazone"
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index b3f9591f64..d475b118b2 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -26,7 +26,7 @@
create_reagents(volume, reagent_flags)
if(spawned_disease)
var/datum/disease/F = new spawned_disease()
- var/list/data = list("viruses"= list(F))
+ var/list/data = list("blood_DNA" = "UNKNOWN DNA", "blood_type" = "SY","viruses"= list(F))
reagents.add_reagent("blood", disease_amount, data)
add_initial_reagents()
diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm
index 3e555f385f..fe35981bfe 100644
--- a/code/modules/reagents/reagent_containers/blood_pack.dm
+++ b/code/modules/reagents/reagent_containers/blood_pack.dm
@@ -4,13 +4,16 @@
icon = 'icons/obj/bloodpack.dmi'
icon_state = "bloodpack"
volume = 200
+ reagent_flags = DRAINABLE
var/blood_type = null
var/labelled = 0
+ var/color_to_apply = "#FFFFFF"
+ var/mutable_appearance/fill_overlay
/obj/item/reagent_containers/blood/Initialize()
. = ..()
if(blood_type != null)
- reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
+ reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_colour"=color, "blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
update_icon()
/obj/item/reagent_containers/blood/on_reagent_change(changetype)
@@ -18,6 +21,7 @@
var/datum/reagent/blood/B = reagents.has_reagent("blood")
if(B && B.data && B.data["blood_type"])
blood_type = B.data["blood_type"]
+ color_to_apply = bloodtype_to_color(blood_type)
else
blood_type = null
update_pack_name()
@@ -45,7 +49,7 @@
/obj/item/reagent_containers/blood/random/Initialize()
icon_state = "bloodpack"
- blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L")
+ blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L", "SY", "HF", "GEL", "BUG")
return ..()
/obj/item/reagent_containers/blood/APlus
@@ -72,6 +76,18 @@
/obj/item/reagent_containers/blood/universal
blood_type = "U"
+/obj/item/reagent_containers/blood/synthetics
+ blood_type = "SY"
+
+/obj/item/reagent_containers/blood/oilblood
+ blood_type = "HF"
+
+/obj/item/reagent_containers/blood/jellyblood
+ blood_type = "GEL"
+
+/obj/item/reagent_containers/blood/insect
+ blood_type = "BUG"
+
/obj/item/reagent_containers/blood/attackby(obj/item/I, mob/user, params)
if (istype(I, /obj/item/pen) || istype(I, /obj/item/toy/crayon))
if(!user.is_literate())
diff --git a/code/modules/research/designs/machine_desings/machine_designs_medical.dm b/code/modules/research/designs/machine_desings/machine_designs_medical.dm
index 65b3d74f71..2f95954e01 100644
--- a/code/modules/research/designs/machine_desings/machine_designs_medical.dm
+++ b/code/modules/research/designs/machine_desings/machine_designs_medical.dm
@@ -89,3 +89,11 @@
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_ENGINEERING
build_path = /obj/item/circuitboard/machine/clonescanner
category = list("Medical Machinery")
+
+/datum/design/board/bloodbankgen
+ name = "Machine Design (Blood Bank Generator Board)"
+ desc = "The circuit board for a blood bank generator."
+ id = "bloodbankgen"
+ build_path = /obj/item/circuitboard/machine/bloodbankgen
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+ category = list ("Medical Machinery")
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 5b3a21dd5c..82037a9b48 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -60,7 +60,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index dffb7bf355..b46be627fb 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -768,6 +768,8 @@
px_y = 12
stam_heal_tick = 2
max_stamina_damage = 50
+ var/blood_state = BLOOD_STATE_NOT_BLOODY
+ var/list/bloody_legs = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
/obj/item/bodypart/l_leg/is_disabled()
if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
@@ -828,6 +830,8 @@
px_y = 12
max_stamina_damage = 50
stam_heal_tick = 2
+ var/blood_state = BLOOD_STATE_NOT_BLOODY
+ var/list/bloody_legs = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
/obj/item/bodypart/r_leg/is_disabled()
if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index a2e8017956..c6e2da0849 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -49,6 +49,27 @@
+/mob/proc/has_left_leg()
+ return TRUE
+
+/mob/living/carbon/has_left_leg()
+ var/obj/item/bodypart/l_leg = get_bodypart(BODY_ZONE_L_LEG)
+ if(l_leg)
+ return TRUE
+ else
+ return FALSE
+
+/mob/proc/has_right_leg()
+ return TRUE
+
+/mob/living/carbon/has_right_leg()
+ var/obj/item/bodypart/r_leg = get_bodypart(BODY_ZONE_R_LEG)
+ if(r_leg)
+ return TRUE
+ else
+ return FALSE
+
+
//Limb numbers
/mob/proc/get_num_arms(check_disabled = TRUE)
return 2
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 8e4caab436..82fbf932e9 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -57,7 +57,7 @@
/obj/item/organ/heart/prepare_eat()
var/obj/S = ..()
- S.icon_state = "heart-off"
+ S.icon_state = "[icon_base]-off"
return S
/obj/item/organ/heart/on_life()
@@ -90,6 +90,12 @@
owner.set_heartattack(TRUE)
failed = TRUE
+obj/item/organ/heart/slime
+ name = "slime heart"
+ desc = "It seems we've gotten to the slimy core of the matter."
+ icon_state = "heart-s-on"
+ icon_base = "heart-s"
+
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."
@@ -212,6 +218,19 @@ obj/item/organ/heart/cybernetic/upgraded/on_life()
+/obj/item/organ/heart/ipc
+ name = "IPC heart"
+ desc = "An electronic pump that regulates hydraulic functions, they have an auto-restart after EMPs."
+ icon_state = "heart-c"
+ organ_flags = ORGAN_SYNTHETIC
+
+/obj/item/organ/heart/ipc/emp_act()
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ Stop()
+ addtimer(CALLBACK(src, .proc/Restart), 10)
+
/obj/item/organ/heart/freedom
name = "heart of freedom"
desc = "This heart pumps with the passion to give... something freedom."
diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi
index 6a1a35f326..5bc30f886c 100644
Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ
diff --git a/icons/effects/fluidtracks.dmi b/icons/effects/fluidtracks.dmi
new file mode 100644
index 0000000000..e2f0c97479
Binary files /dev/null and b/icons/effects/fluidtracks.dmi differ
diff --git a/icons/effects/footprints.dmi b/icons/effects/footprints.dmi
index a98344abe4..69207097c0 100644
Binary files a/icons/effects/footprints.dmi and b/icons/effects/footprints.dmi differ
diff --git a/icons/mob/dam_mob.dmi b/icons/mob/dam_mob.dmi
index fe92746b43..c34b57b434 100644
Binary files a/icons/mob/dam_mob.dmi and b/icons/mob/dam_mob.dmi differ
diff --git a/icons/obj/bloodbank.dmi b/icons/obj/bloodbank.dmi
new file mode 100644
index 0000000000..4b4b2b6990
Binary files /dev/null and b/icons/obj/bloodbank.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index bdfbae3d75..fcc28de7b9 100755
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
index e677c1f3ab..e7017b8481 100644
--- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
+++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
@@ -307,7 +307,7 @@
var/mob/M = loc
M.update_inv_hands()
- SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)//blood overlays get weird otherwise, because the sprite changes. (retained from original desword because I have no idea what this is)
+ clean_blood()
/obj/item/twohanded/dualsaber/hypereutactic/AltClick(mob/living/user)
if(!user.canUseTopic(src, BE_CLOSE, FALSE) || hacked)
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human.dm b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
index e0d592827e..e5d386b56b 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
@@ -1,12 +1,3 @@
-/mob/living/carbon/human/species/mammal
- race = /datum/species/mammal
-
-/mob/living/carbon/human/species/insect
- race = /datum/species/insect
-
-/mob/living/carbon/human/species/xeno
- race = /datum/species/xeno
-
/mob/living/proc/resist_embedded()
return
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 00063c22d4..c8ebde11d9 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,11 +1,3 @@
-/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
- if(istype(O, /obj/effect/decal/cleanable) || istype(O, /obj/item/projectile/bullet/reusable/foam_dart) || istype(O, /obj/item/ammo_casing/caseless/foam_dart))
- qdel(O)
- else
- if(O)
- O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
-
/datum/reagent/syndicateadrenals
name = "Syndicate Adrenaline"
id = "syndicateadrenals"
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
index 47f71d1acf..7fcae0eb13 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -327,10 +327,10 @@
//So slimes can play too.
/datum/chemical_reaction/fermi/enthrall/slime
- required_catalysts = list("slimejelly" = 1)
+ required_catalysts = list("jellyblood" = 1)
/datum/chemical_reaction/fermi/enthrall/slime/FermiFinish(datum/reagents/holder, var/atom/my_atom)
- var/datum/reagent/toxin/slimejelly/B = locate(/datum/reagent/toxin/slimejelly) in my_atom.reagents.reagent_list//The one line change.
+ var/datum/reagent/blood/jellyblood/B = locate(/datum/reagent/blood/jellyblood) in my_atom.reagents.reagent_list//The one line change.
var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in my_atom.reagents.reagent_list
if(!B.data)
var/list/seen = viewers(5, get_turf(my_atom))
diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
index 0e823a658f..df3922dc09 100644
--- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
+++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
@@ -2,7 +2,7 @@
/datum/reagent/consumable/semen
name = "Semen"
id = "semen"
- description = "Sperm from some animal. Useless for anything but insemination, really."
+ description = "Sperm from some animal. I bet you'll drink this out of a bucket someday."
taste_description = "something salty"
taste_mult = 2 //Not very overpowering flavor
data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null)
@@ -39,7 +39,9 @@
add_blood_DNA(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/semen/replace_decal(obj/effect/decal/cleanable/semen/S)
- S.add_blood_DNA(return_blood_DNA())
+ if(S.blood_DNA)
+ blood_DNA |= S.blood_DNA.Copy()
+ ..()
/datum/reagent/consumable/femcum
name = "Female Ejaculate"
@@ -71,7 +73,8 @@
add_blood_DNA(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F)
- F.add_blood_DNA(return_blood_DNA())
+ if(F.blood_DNA)
+ blood_DNA |= F.blood_DNA.Copy()
..()
/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume)
diff --git a/modular_citadel/icons/mob/64x32_effects.dmi b/modular_citadel/icons/mob/64x32_effects.dmi
index 7db65a8fc3..a11b3584a3 100644
Binary files a/modular_citadel/icons/mob/64x32_effects.dmi and b/modular_citadel/icons/mob/64x32_effects.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 702f34f80c..1a45dc619f 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -47,7 +47,6 @@
#include "code\__DEFINES\flags.dm"
#include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm"
-#include "code\__DEFINES\forensics.dm"
#include "code\__DEFINES\hud.dm"
#include "code\__DEFINES\integrated_electronics.dm"
#include "code\__DEFINES\interaction_flags.dm"
@@ -357,7 +356,6 @@
#include "code\datums\components\empprotection.dm"
#include "code\datums\components\footstep.dm"
#include "code\datums\components\forced_gravity.dm"
-#include "code\datums\components\forensics.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm"
#include "code\datums\components\knockoff.dm"
@@ -386,7 +384,6 @@
#include "code\datums\components\virtual_reality.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm"
-#include "code\datums\components\decals\blood.dm"
#include "code\datums\components\storage\storage.dm"
#include "code\datums\components\storage\concrete\_concrete.dm"
#include "code\datums\components\storage\concrete\bag_of_holding.dm"
@@ -579,6 +576,7 @@
#include "code\game\machinery\autolathe.dm"
#include "code\game\machinery\bank_machine.dm"
#include "code\game\machinery\Beacon.dm"
+#include "code\game\machinery\bloodbankgen.dm"
#include "code\game\machinery\buttons.dm"
#include "code\game\machinery\cell_charger.dm"
#include "code\game\machinery\cloning.dm"
@@ -758,6 +756,7 @@
#include "code\game\objects\effects\decals\misc.dm"
#include "code\game\objects\effects\decals\remains.dm"
#include "code\game\objects\effects\decals\cleanable\aliens.dm"
+#include "code\game\objects\effects\decals\cleanable\gibs.dm"
#include "code\game\objects\effects\decals\cleanable\humans.dm"
#include "code\game\objects\effects\decals\cleanable\misc.dm"
#include "code\game\objects\effects\decals\cleanable\robots.dm"
diff --git a/tools/mapmerge2/dmi.py b/tools/mapmerge2/dmi.py
index f0a8182c9f..c12964cead 100644
--- a/tools/mapmerge2/dmi.py
+++ b/tools/mapmerge2/dmi.py
@@ -45,6 +45,8 @@ class Dmi:
@classmethod
def from_file(cls, fname):
image = Image.open(fname)
+ if image.mode != 'RGBA':
+ image = image.convert('RGBA')
# no metadata = regular image file
if 'Description' not in image.info:
@@ -250,4 +252,4 @@ if __name__ == '__main__':
Dmi.from_file(os.path.join(dirpath, filename))
count += 1
- print(f"Successfully parsed {count} dmi files")
+ print(f"Successfully parsed {count} dmi files")
\ No newline at end of file
diff --git a/tools/mapmerge2/dmm.py b/tools/mapmerge2/dmm.py
index 8bb1dca353..15aa04c07f 100644
--- a/tools/mapmerge2/dmm.py
+++ b/tools/mapmerge2/dmm.py
@@ -343,7 +343,7 @@ def _parse(map_raw_text):
in_map_block = False
in_coord_block = False
in_map_string = False
- iter_x = 0
+ base_x = 0
adjust_y = True
curr_num = ""
@@ -487,7 +487,7 @@ def _parse(map_raw_text):
curr_x = int(curr_num)
if curr_x > maxx:
maxx = curr_x
- iter_x = 0
+ base_x = curr_x
curr_num = ""
reading_coord = "y"
elif reading_coord == "y":
@@ -521,21 +521,15 @@ def _parse(map_raw_text):
adjust_y = False
else:
curr_y += 1
- if curr_x > maxx:
- maxx = curr_x
- if iter_x > 1:
- curr_x = 1
- iter_x = 0
-
+ curr_x = base_x
else:
curr_key = BASE * curr_key + base52_r[char]
curr_key_len += 1
if curr_key_len == key_length:
- iter_x += 1
- if iter_x > 1:
- curr_x += 1
-
grid[curr_x, curr_y, curr_z] = duplicate_keys.get(curr_key, curr_key)
+ if curr_x > maxx:
+ maxx = curr_x
+ curr_x += 1
curr_key = 0
curr_key_len = 0
@@ -551,4 +545,4 @@ def _parse(map_raw_text):
data = DMM(key_length, Coordinate(maxx, maxy, maxz))
data.dictionary = dictionary
data.grid = grid
- return data
+ return data
\ No newline at end of file
diff --git a/tools/mapmerge2/update_paths.py b/tools/mapmerge2/update_paths.py
index 2c316e941d..deab468ecd 100644
--- a/tools/mapmerge2/update_paths.py
+++ b/tools/mapmerge2/update_paths.py
@@ -173,4 +173,4 @@ if __name__ == "__main__":
parser.add_argument("--directory", "-d", help="path to maps directory, defaults to _maps/")
parser.add_argument("--inline", "-i", help="treat update source as update string instead of path", action="store_true")
parser.add_argument("--verbose", "-v", help="toggle detailed update information", action="store_true")
- main(parser.parse_args())
+ main(parser.parse_args())
\ No newline at end of file