diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm
index d80e3759..97dd5564 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,
/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,
/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,
/area/ruin/unpowered/xenonest)
"by" = (
diff --git a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
index f1a3005c..9c273f4d 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 29bd7d05..2f08d9a2 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 66ab3e60..92373463 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 7edc7b45..c251a338 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 e72dbaae..800cfbb5 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -28566,6 +28566,7 @@
/obj/structure/disposalpipe/segment{
dir = 6
},
+/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"blu" = (
@@ -62813,6 +62814,10 @@
/obj/structure/trash_pile,
/turf/open/floor/plating,
/area/maintenance/port/fore)
+"xNJ" = (
+/obj/machinery/bloodbankgen,
+/turf/open/floor/plasteel/white,
+/area/medical/sleeper)
"xYc" = (
/obj/item/crowbar,
/obj/item/wrench,
@@ -99725,7 +99730,7 @@ bCs
bxa
bER
bFV
-byu
+xNJ
byu
bKn
bLF
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index c2e36e11..348ccc76 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -6448,6 +6448,7 @@
"mES" = (/obj/machinery/door/airlock/maintenance/abandoned{name = "Surgical Room"},/turf/open/floor/plating,/area/maintenance/department/science)
"mHy" = (/obj/item/storage/fancy/cigarettes/cigpack_shadyjims,/turf/open/floor/wood,/area/maintenance/department/engine)
"mIa" = (/obj/structure/disposalpipe/segment{dir = 10},/obj/machinery/light/small{dir = 8},/turf/open/floor/plating,/area/maintenance/department/engine)
+"mKw" = (/obj/machinery/bloodbankgen,/turf/open/floor/plasteel/white,/area/medical/medbay/central)
"mLc" = (/obj/structure/sign/warning/electricshock,/turf/closed/wall/r_wall,/area/engine/supermatter)
"mLB" = (/obj/structure/cable{icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/turf/open/floor/plating{icon_state = "platingdmg1"},/area/maintenance/department/security/brig)
"mMz" = (/obj/effect/spawner/structure/window/reinforced,/obj/structure/cable,/obj/machinery/door/poddoor/preopen{id = "misclab"; name = "test chamber blast door"},/turf/open/floor/plating,/area/science/xenobiology)
@@ -6901,6 +6902,7 @@
"wrU" = (/obj/machinery/photocopier,/obj/machinery/firealarm{dir = 4; pixel_x = -28},/turf/open/floor/wood,/area/lawoffice)
"wsx" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/machinery/light{dir = 4; light_color = "#e8eaff"},/obj/effect/turf_decal/stripes/line{dir = 4},/turf/open/floor/plasteel,/area/engine/engineering)
"wun" = (/obj/structure/cable{icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/structure/disposalpipe/junction/yjunction{dir = 8},/turf/open/floor/plasteel,/area/hallway/primary/central)
+"wvg" = (/obj/machinery/bloodbankgen,/turf/open/floor/plasteel/white,/area/medical/chemistry)
"wwG" = (/obj/effect/turf_decal/stripes/line{dir = 8},/turf/open/floor/plating,/area/maintenance/department/security/brig)
"wxb" = (/obj/structure/cable{icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/open/floor/plating{icon_state = "platingdmg3"},/area/maintenance/department/security/brig)
"wxJ" = (/obj/effect/turf_decal/delivery,/obj/machinery/door/poddoor/preopen{id = "prison release"; name = "prisoner processing blast door"},/turf/open/floor/plasteel/dark,/area/security/brig)
@@ -7135,13 +7137,13 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZxaKsxaAbaKaKtaJBbaKbbTaKuastbtPbtQbnvbtRbtSbtTboubtUbtVbtWbtXbtYbnvbtZbsybjQbuabubbucbudbucbuebuabkhbufbrfbugcqmcqmaoNblobuibpYbujbukbulbumbunbpYqbmtTlcqivfncSKcCtbupbuqburbuscClbutbyCbuubktbkubuvbkubktbktbktbktbktbktbuwbuxbuybodfjsbuAwBbwBbwlKbuBdkRbuCgDZcKAbuDbuEbuFbuGbuHbrRwkZbuKbkFofNxzpxprnuvjxljwebwebwebwfcucbwhbwebwfbuUbwebwebuWbkFmtIgICoBbpMGufaufahUJwXuuvonaqblXiPjblXxKcaaaabyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamZEbGIbGIaZxaKvaFKaKwaZxaKvaFKaKxaKyaYGbvabvbbnvbnvbtSbnvbvcbouboubvdbvebvcbvcbvfbvgbvhbvibvjjsjbvkkQytixrarjUVbvmbvnbvobvlbvlbvlbvlbvpababvrbvsbwUbvtmcfgGAbvugkScqiufxduFbyFbvwbvxbvybvzbqbbsUbvAbvBbvCcqpbvEbvFbvGbvHbvIbvJbvKbvLbvMbvNbvObvPbvQbvRbvSbvTbvUeNqbvVbvWbvVbvYbvZbwabwbbwcbjwbkFbnjdqwbkFgdLugCihkihktXnbrRbxMbxNbxObnjbxMbxQbxRbnjbxMbxSbxTbkFbwmbwnbkFiPzoNEtaAriWcOpmMzbkFblXblXblXbkFaaaaedaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaZxaZxaZxaZxaZxtOeaZxaZxbwqbwraYGbwsbwtbnvbnvbwubnvbwvbwwbwxbwybwzbwAbvcbwBbwCbwDbwEbwFbwGbwHbwIcSJbwEbwKbwLbwMbwNbwObwPbwPcqsbwQbpXbwSbwTbsKbwVnnfbwWwnwtTlcqiufxoxtbxcbxdbxebxfbxgabTbxibxjbxkbxlbxmbxnbxobxpabcbxrbxsabUbxubxvbxwbxxbxybxzbxAbwabxCbxDeNqcxtbxGbxHbvYbxJefubxKbxLbjwldQbwmspzbkFiLlgdJpXgcPThfZbnjbzkbzlbzmbnjbznxxObzpbnjbzqbzrbzsbkFkFuvRibkFsXRoepqcHjtflGSdmTbkFblXblXeQRbkFahtabyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaKzaKAaKAaKAaKAaKAaKBaKCaKFaKWaYGbybbycbnvbydbtSbyebyfbygbyhbyibyjbykbvcbylbymbynbsAbyobypbuabyobsAbsAbyrbysbytbyubyvbyubyvbyubyvbpYbywbyxbsKbyzbyAbpYceptTlerVabebyEnIUbyGbyHbyImdLbqbbyJhiYbyKcqtbyLbyMbyNbyObyPbyQbyRbySbyTbyUbyVbyWbyXbyYbyZbzabzbbzcurPbzdbzebzdfkHtAKbzhbzibzjbjwlNWbwmspzbkFbkFbkFbkFbkFbkFbkFbAHblXblXbnjbAHblXblXbnjbAHblXblXbkFtSLdKsbwmsXRbndbndbndbndbkFbkFbkFxKcbkFbkFaaaabyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaKzaKAaKAaKAaKAaKAaKBaKCaKFaKWaYGbybbycbnvbydbtSbyebyfbygbyhbyibyjbykbvcbylbymbynbsAbyobypbuabyobsAbsAbyrbysbytbyubyvbyubyvbyubyvbpYbywbyxwvgbyzbyAbpYceptTlerVabebyEnIUbyGbyHbyImdLbqbbyJhiYbyKcqtbyLbyMbyNbyObyPbyQbyRbySbyTbyUbyVbyWbyXbyYbyZbzabzbbzcurPbzdbzebzdfkHtAKbzhbzibzjbjwlNWbwmspzbkFbkFbkFbkFbkFbkFbkFbAHblXblXbnjbAHblXblXbnjbAHblXblXbkFtSLdKsbwmsXRbndbndbndbndbkFbkFbkFxKcbkFbkFaaaabyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaKXaLpbzzbzzbzzaLqaLrbzzbzAbzBaYGbzCbzDbnvbzEbwubzFbzGbzHbzIbzJbzKbzLbvcbzMbzNbzObsAbzPbzQbzRbzSbzTbzUbzVbzWbzXbzYbzZbAabAbbAcbAdbpYbAebAfbAgoohbAibpYePStTlrMtbAmbBpbAobApbAqbArbCJfRsbAtbAtbAtbAubAvbAwbAxbAybAybBobAAbAAbABbAAbAAbAAbAAbACbADbAEbAFbAFbAFwnJvTNwnJbAFbAFbAFbAFbAFbHymSclWyspzbxPbwmlWykPisyQkkQbkFblXbBUblXbnjblXbBUblXbnjblXblXblXbkFiVJoKabwmpwSmlraLsahtaaaaaaaaaahtaaaaaaaaaaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaLtaLJaZxaZxaZxbAIbAJvIUbAKbALaYGbzCbAMbnvbANbAObAPbAQbARbASbATbAUbAVbvcbAWbAXbAYbsAbCjbzQbzReFjbBcbBdbBebBfbpPwLobBgbBhbBibBjbBkbpYbpYbBlbpYbpYbpYbpYnhWqUeksCdhzvyNbBqbBrbBsbBtbBufRsaLMaLNaLObAubsUbBzbkobBBbBoaaabAAbBCbBDbBEbBFbBGbAAbBHbBIbBJbAFbBKbBLbBMbBNbBObBPbBQbBRbBSbBTbHyscigXgwFTnevabgiVJiVJiVJrKLbkFblXbDeblXbnjblXbDeblXbnjblXbDeblXbkFiVJrgnbwmbwmsEBbwmahiaaaaaaaaaaedabyabyaedabyabyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVpaZxaLtaLJaZxahtbBVabIbBXbBXbBXbBXbBXbBYbvbbnvbnvbnvbnvbBZbCabCbbCcbCdbCebvcbCfbCgbChbsAbCiiojbBbbClbCmbyobCnbCobCpabhbCrbCsbCtbCubCvabibCxbCybCzbCAbCBafYrGzdggfdQnkkbBpbCEbCFbCGbCHbCIbAoaLPaMdaMebAtcqkcqvbkobCNbCOahtbCPbBCbBDbCQbCRbCRbCSbCTbCUbBJbCVbCWbCWbCXbBNbCZbCWbDabDbbDcbDdbHybwmbwmbwmhgDbwmlWyhxnrFqlWybkFbkFbkFbkFbkFbkFbkFbkFbkFbkFbkFbkFbkFaadjRGeuQvtljEXhSMahiaaaaaaaaaahtaaaaaaaaaaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagLnaZxaLtaMfaZxahtbDfabIbBXbDgbDgbDhbvabTlbDjibUbDibDkbnvbvcbvcbvcbDlbDmbDnbvcbDobDpbDqbsAbDrbsAbDrbsAbDrbsAbDsbkhbpPwLobDtbDubDvbDwbDxbDybDybDybDybDybDzbvarPdphJbmDbDAbBpbDBbDCbDDbDEbDFbAoaMIaMJaMKbAtbsUbBzbkobDKbBoahtbAAbDLbDMbDNbDObDPabkbDRbDSbDTablbDVbDWbDXbDYbDXbDXbEabEbbEcbEdbHyglfpNyveMbEfbAFtSLuvqobPlWybwmkgRdMOhTlbwmqIOdmPlWysZuwfcbwmueVdoodtmgmpvuQbwmruibwmahiaaaaaaaaaaedahtahtabyabyaedahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahtsTgaZxaKXaMMaZxahtbDfahtbBXbEjbEkbElacbbEnbEobmfbEpbmfbEqbDibErbvcbvcbvcbvcbvcbEsbEtbEubjcbEvbEwbExbEybEzbkbbEAbEBbECbzYbEDbEEbEFbEGbEHbDybEIbEJbEKatebEMbvaxDjphJbmDbEQbBpbERbESbETbEUbEVfRsaMNaMOaMPbAubsUbBzbkobEZbCOaaabCPbFabFbbFcbCRbFdbCSbCTbwbbFfbCVbFhkmnbFibFjbFkbFlbFmbFnbGubFpbHybFrbFsbFtbFubAFlWybFxbFybFzbwmbFBlWybFCbwmjXAbFDlWylWysAKbwmheCefUbwmbwmbwmbwmbwmbwmahtahtabyaaaaaaaaaaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabFEaaaaaaaaaaaaaaaaaaahtahtgLnaZxaLtaMMaZxahtbDfabIbBXbFFbvabvabvabvabvabsnbsnbvabFGbEnbFHbFIbFJbFKbFLbAWbErbFMbFNbFObFPbkhbkhbFQbnFacpbFSbkhbFTbFUbFUbFUbFUbFUbFUbDybFVbFWbFXbDybFYbvabltlCYjrbbGabBpbBpbBpbBpbBpbBpbBpbAtbGbbGcbAubGdbBzbkobGebBoahtbAAbGfbGgbGhbCRbGibAAbGjbGkbGlbAFbGmbGnbGobGpbGqbGrbGsbGtbGubGvabmqtAbGxbGynoMabniVJtSLbGBlWybwmbwmrxQbwmbwmbwmbwmfKjbwmbwmbwmuugeMCjFwrNBaaaaaaahtaaaahtaaaahtaaaaaaaaaaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabFEaaaaaaaaaaaaaaaaaaahtahtgLnaZxaLtaMMaZxahtbDfabIbBXbFFbvabvabvabvabvabsnbsnbvabFGbEnbFHbFIbFJbFKbFLbAWbErbFMbFNbFObFPmKwbkhbFQbnFacpbFSbkhbFTbFUbFUbFUbFUbFUbFUbDybFVbFWbFXbDybFYbvabltlCYjrbbGabBpbBpbBpbBpbBpbBpbBpbAtbGbbGcbAubGdbBzbkobGebBoahtbAAbGfbGgbGhbCRbGibAAbGjbGkbGlbAFbGmbGnbGobGpbGqbGrbGsbGtbGubGvabmqtAbGxbGynoMabniVJtSLbGBlWybwmbwmrxQbwmbwmbwmbwmfKjbwmbwmbwmuugeMCjFwrNBaaaaaaahtaaaahtaaaahtaaaaaaaaaaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabGDbGEbGFbGEaMQbGHbGIaaaahtahtahtgLnaZxaNkaMMaZxahtagSaaabvabvabvabGKbGLbGMbvabvabvabvabGNbDibErbGObGPbGQbGRbAWbGSbGTbGUbFObGVbkhbGXbuhbuhactbGZbuhbHabFUbHbbHcbHdbFUbFUbFUbFUbHebFUbFUbDzbvajCvbAkbAlbHgbvDbHhbHibHjbHkbHlbHmaIAbHnbHobHgbHqbHrbHsbHtbCOahtbCPbCRbHubCRbCRbHvbHwbuzbuzbuzbHybHybHybHybHybHybHyubWbHzbGubHAnsDkhkbHCbHDbHEbAGbwmbwmbwmxlAbwmsvNlWynzDrosrosgxKlWybwmhXtbwmiVJiVJxpDbwmahtabyabyabyabyaedabyabyaedabyahtahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabHIbGDbGEbHJbHKbHLbGEbHMbHNaqGaqGaqGeOAaZxaNlaMMaZxahtagSbvabvabHPbHQbHQbHQbHRbHQbHSbvabHTbGNbDibErbHUbHVbHXbHXbHYbHZbIabIbbFObIcbIdbIebIfbIgbkbbCnbIhbIibIjbIkbIlbImbInbIobIpbIqbIrbIsbFUbDzbvabOKbItbIumVjbIvbIvbIvbIxbIvbIvbIycqwbIAbRXcqxbICbIDbBAbIEbBoaaabAAbIFbIGbIHbIIbIJbHwabIabIabIaaaaaaaaaaaaabIaaaaaaubWbIKbILbIMrPWbINcxbfBzbJVfwrrBhbIPbIQbIRlQnbIQrosuojbwmvpzpWFbIQbIQbIQbIQbIQdVJjQhbwmaaaahtahtaaaahtaaaahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabybITbIUpbmbIVbIWbIXbHMbGEbGEbGEbGEaZxaZxaNnaMMaZxahtagSbIZbJabJbbJcbJdbJebJfbJgbJhbvabJibGNbJjpQwbJksENbJmbJlbGWbGWcBKbJnbFObFObFObjcbjcbjcbjcbJobkhbJpabobJrbJsbJrabpbJubJvbJwbJxbJyabqbJAbvabENbJBbJCbJDcqzcqzcqzcqzbJEbJFbJGcqDbJHcqEbJJbJKbJLbJMbJNbJNbJNbHwbHwbJObHwbHwbHwbHwbJPbJPbJPbJPbJPahtabyabyabyahtxIxbJQbJRbJSkfhdAFbJTbCVbLhgMmbwmbwmbwmbwmbwmuekizFbwmbwmbwmbwmbwmbwmrNBbwmbwmjDAbwmbwmaaaaedabyabyaedabyabyaedabyahtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 8662d19f..7c2250ea 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -111,11 +111,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 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 c4db590e..6049fd79 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 4979823a..91cc89ce 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
@@ -101,4 +102,4 @@
* The arguments are the same when the text and number values are the same and all other values have the same ref
*/
#define ELEMENT_BESPOKE (1 << 1)
-#define COMSIG_MOVABLE_UPDATE_GLIDE_SIZE "movable_glide_size" //Called when the movable's glide size is updated: (new_glide_size)
\ No newline at end of file
+#define COMSIG_MOVABLE_UPDATE_GLIDE_SIZE "movable_glide_size" //Called when the movable's glide size is updated: (new_glide_size)
diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm
index ef96b83c..16d76360 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 657c69b8..00000000
--- 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 70c7bb40..7d4dc1ca 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -73,11 +73,19 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
#define iszombie(A) (is_species(A, /datum/species/zombie))
#define ismoth(A) (is_species(A, /datum/species/moth))
-#define isinsect(A) (is_species(A, /datum/species/insect))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
#define isvampire(A) (is_species(A,/datum/species/vampire))
+// 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))
@@ -193,6 +201,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 616ffaae..752e4e56 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -147,12 +147,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 635f7738..09fd94b6 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -761,7 +761,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 b7ef4528..0a28cdf3 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -58,3 +58,63 @@ 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/beam.dm b/code/datums/beam.dm
index d0b6d791..d97ee9a7 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -61,7 +61,8 @@
/datum/beam/proc/recalculate_in(time)
if(timing_id)
deltimer(timing_id)
- timing_id = addtimer(CALLBACK(src, .proc/recalculate), time, TIMER_STOPPABLE)
+ if(!finished)
+ timing_id = addtimer(CALLBACK(src, .proc/recalculate), time, TIMER_STOPPABLE)
/datum/beam/proc/after_calculate()
if((sleep_time == null) || finished) //Does not automatically recalculate.
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index bc99665f..a836ac95 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/decal.dm b/code/datums/components/decal.dm
index 5300493a..641dbdb1 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 3114ddb2..c8be6251 100644
--- a/code/datums/components/decals/blood.dm
+++ b/code/datums/components/decals/blood.dm
@@ -7,33 +7,7 @@
. = ..()
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
diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm
deleted file mode 100644
index cdfe89cf..00000000
--- 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 ffeae38f..1cf42496 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 2e6f8f79..20e3b317 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 72bf1c36..112915a2 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 4d1ed323..ec22b6b7 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 60640c6d..526d482e 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,19 @@
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 +144,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/elements/cleaning.dm b/code/datums/elements/cleaning.dm
index 3e0c60ad..e4fb3edd 100644
--- a/code/datums/elements/cleaning.dm
+++ b/code/datums/elements/cleaning.dm
@@ -15,24 +15,34 @@
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!")
diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm
index 1b095c55..31023b3f 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 551a977a..f9ed7a31 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -43,6 +43,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()
@@ -231,7 +237,7 @@
return FALSE
/atom/proc/CheckExit()
- return 1
+ return TRUE
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
@@ -288,6 +294,11 @@
if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
should_override = TRUE
+
+ if(blood_DNA && !istype(src, /obj/effect/decal))
+ override[EXAMINE_POSITION_BEFORE] = " blood-stained "
+ should_override = TRUE
+
if(should_override)
. = override.Join("")
@@ -297,7 +308,7 @@
/atom/proc/examine(mob/user)
. = list("[get_examine_string(user, TRUE)].")
-
+
if(desc)
. += desc
@@ -360,12 +371,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)
@@ -383,18 +396,115 @@
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()
+ . = blood_DNA? TRUE : FALSE
+ blood_DNA = null
/atom/proc/wash_cream()
return TRUE
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 78d79ea7..6d681f81 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 00000000..c92e5508
--- /dev/null
+++ b/code/game/machinery/bloodbankgen.dm
@@ -0,0 +1,336 @@
+/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/maxbloodstored = 1000
+ var/menustat = "menu"
+ var/efficiency = 0
+ var/productivity = 0
+
+/obj/machinery/bloodbankgen/Initialize()
+ . = ..()
+ create_reagents(maxbloodstored, AMOUNT_VISIBLE)
+ update_icon()
+
+/obj/machinery/bloodbankgen/Destroy()
+ QDEL_NULL(bag)
+ QDEL_NULL(outbag)
+ return ..()
+
+/obj/machinery/bloodbankgen/examine(mob/user)
+ . = ..()
+ if(bag)
+ . += "It has \a [bag.name] hooked to its input slot. The counter reads: \"Current Capacity: [bag.reagents.total_volume] of [bag.reagents.maximum_volume]\""
+ if(outbag)
+ . += "It has \a [bag.name] hooked to its output slot. The counter reads: \"Current Capacity: [outbag.reagents.total_volume] of [outbag.reagents.maximum_volume]\""
+
+
+/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
+
+ var/transfer_amount = 20
+
+ if(draining)
+ if(reagents.total_volume >= reagents.maximum_volume || !bag || !bag.reagents.total_volume)
+ beep_stop_pumping()
+ return
+ var/blood_amount = bag.reagents.get_reagent_amount("blood")
+ //monitor the machine and blood bag's reagents storage.
+ var/amount = min(blood_amount, min(transfer_amount, reagents.maximum_volume - reagents.total_volume))
+ if(!amount)
+ beep_stop_pumping()
+ return
+ var/bonus = bag.blood_type == "SY" ? 0 : 5 * efficiency //no infinite loops using synthetics.
+ reagents.add_reagent("syntheticblood", amount + bonus)
+ bag.reagents.remove_reagent("blood", amount)
+ update_icon()
+
+ if(filling)
+ if(!reagents.total_volume || !outbag || outbag.reagents.total_volume >= outbag.reagents.maximum_volume)
+ beep_stop_pumping("[src] pings.", TRUE)
+ return
+ //monitor the output bag's reagents storage.
+ var/amount = min(transfer_amount, outbag.reagents.maximum_volume - outbag.reagents.total_volume)
+ reagents.trans_to(outbag, amount)
+ update_icon()
+
+/obj/machinery/bloodbankgen/proc/beep_stop_pumping(msg = "[src] beeps loudly.", out_instead_of_in = FALSE)
+ if(out_instead_of_in)
+ filling = FALSE
+ else
+ draining = FALSE
+ updateUsrDialog()
+ audible_message(msg)
+ playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
+
+/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) || default_unfasten_wrench(user, O, 20) == SUCCESSFUL_UNFASTEN)
+ 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))
+ . = TRUE //no afterattack
+ var/msg
+ if(panel_open)
+ . += "Close the maintenance panel"
+ if(!anchored)
+ . += "[msg ? " and a" : "A"]nchor its bolts"
+ if(length(msg))
+ to_chat(user, "[msg] first.")
+ return
+ 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, "You cannot put this in [src]!")
+
+/obj/machinery/bloodbankgen/is_operational()
+ return ..() && anchored
+
+/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, 420)
+ 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
+ draining = 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
+ filling = 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(. | !is_operational())
+ return
+
+ usr.set_machine(src)
+
+ if(href_list["activateinput"])
+ activateinput()
+
+ else if(href_list["detachinput"])
+ detachinput()
+
+ else if(href_list["activateoutput"])
+ activateoutput()
+
+ else if(href_list["detachoutput"])
+ detachoutput()
+
+ updateUsrDialog()
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 82b58649..7f34e845 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -354,7 +354,8 @@
O.organ_flags &= ~ORGAN_FROZEN
unattached_flesh.Cut()
mess = FALSE
- new /obj/effect/gibspawner/generic(get_turf(src))
+ if(mob_occupant)
+ mob_occupant.spawn_gibs()
audible_message("You hear a splat.")
update_icon()
return
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index a7d62ea6..69363d5a 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -329,7 +329,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 f03c4bf6..e2a7ba99 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/item/reagent_containers/chem_pack))
-/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,7 +201,6 @@
if(usr.incapacitated())
return
-
mode = !mode
to_chat(usr, "The IV drip is now [mode ? "injecting" : "taking blood"].")
update_icon()
@@ -204,7 +209,9 @@
. = ..()
if(get_dist(user, src) > 2)
return
+
. += "[src] is [mode ? "injecting" : "taking blood"].\n"
+
if(beaker)
if(beaker.reagents && beaker.reagents.reagent_list.len)
. += "\tAttached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.\n"
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 85720764..51970125 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 = null
var/datum/component/radioactive/contamination = AM.GetComponent(/datum/component/radioactive)
if(contamination)
qdel(contamination)
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index acc123b5..5ea822f5 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)
. = ..()
. += "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 44bd9643..b200dc03 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -10,6 +10,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)
@@ -29,7 +30,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))
@@ -83,7 +84,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()
@@ -92,4 +95,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 663707de..4301709f 100644
--- a/code/game/objects/effects/decals/cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/cleanable/aliens.dm
@@ -1,71 +1,73 @@
// 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*"))
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 00000000..dc621f17
--- /dev/null
+++ b/code/game/objects/effects/decals/cleanable/gibs.dm
@@ -0,0 +1,234 @@
+/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
+ bloodiness = 0
+ 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 439ae734..ef9e1d1a 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
+ blood_state = BLOOD_STATE_BLOOD
bloodiness = BLOOD_AMOUNT_PER_DECAL
+ 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
+ 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,27 @@
random_icon_states = null
var/list/existing_dirs = list()
-/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
- return TRUE
+/obj/effect/decal/cleanable/trail_holder/update_icon()
+ color = blood_DNA_to_color()
-/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/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
+/obj/effect/cleanable/trail_holder/Initialize()
. = ..()
- reagents.add_reagent("liquidgibs", 5)
+ update_icon()
/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()
+/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
return TRUE
+/obj/effect/decal/cleanable/trail_holder/transfer_blood_dna()
+ ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/trail_holder/transfer_mob_blood_dna()
+ . = ..()
+ update_icon()
+
//BLOODY FOOTPRINTS
/obj/effect/decal/cleanable/blood/footprints
@@ -127,15 +84,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,11 +101,12 @@
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))
@@ -156,8 +115,8 @@
/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 +129,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)
@@ -184,9 +143,49 @@
/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 833b89e6..cd208d33 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/proximity.dm b/code/game/objects/effects/proximity.dm
index fa6babbb..23977746 100644
--- a/code/game/objects/effects/proximity.dm
+++ b/code/game/objects/effects/proximity.dm
@@ -109,4 +109,4 @@
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
set waitfor = FALSE
- monitor.hasprox_receiver.HasProximity(AM)
+ monitor?.hasprox_receiver.HasProximity(AM)
diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm
index d4f440c3..4d1baf68 100644
--- a/code/game/objects/effects/spawners/gibspawner.dm
+++ b/code/game/objects/effects/spawners/gibspawner.dm
@@ -1,25 +1,66 @@
/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, list/blood_dna)
. = ..()
-
- 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)
+ if(!issilicon(source_mob))
+ dna_to_add = blood_dna || 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"]]"
+ else
+ dna_to_add = temp_mob.get_blood_dna_list()
+ else if(!issilicon(temp_mob))
+ dna_to_add = temp_mob.get_blood_dna_list()
+ qdel(temp_mob)
+ else
+ dna_to_add = list("Non-human DNA" = random_blood_type()) //else, generate a random bloodtype for it.
+
+
for(var/i = 1, i<= gibtypes.len, i++)
if(gibamounts[i])
for(var/j = 1, j<= gibamounts[i], j++)
@@ -29,10 +70,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 +83,157 @@
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 dd7267c5..296112a4 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 ecae0d85..30fec05d 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -543,6 +543,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 b9cc55de..04243ae7 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -43,6 +43,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 22d2a2f8..a27526ba 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -422,7 +422,7 @@ GENE 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/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index 75b6acfe..7da65b41 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -117,7 +117,7 @@
if(!O.reagents)
continue
var/reagent_list = pretty_string_from_reagent_list(O.reagents)
- user.log_message("removed [O] ([reagent_list]) from [src]")
+ user.log_message("removed [O] ([reagent_list]) from [src]", LOG_GAME)
beakers = list()
to_chat(user, "You open the [initial(name)] assembly and remove the payload.")
return // First use of the wrench remove beakers, then use the wrench to remove the activation mechanism.
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 057375cd..1f0c1c49 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -263,7 +263,7 @@
if (B && !QDELETED(B))
H.internal_organs -= B
qdel(B)
- new /obj/effect/gibspawner/generic(get_turf(H), H.dna)
+ H.spawn_gibs()
return (BRUTELOSS)
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user)
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index ac1e2848..5d384a93 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 af6f02cd..caab2855 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -18,7 +18,6 @@
var/fix_bone= 0
/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 52064e05..873cb7ba 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -390,10 +390,14 @@
. = ..()
/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())
- fingerprintslast = from.fingerprintslast
+ if(from.blood_DNA)
+ blood_DNA = from.blood_DNA.Copy()
+ if(from.fingerprints)
+ fingerprints = from.fingerprints.Copy()
+ if(from.fingerprintshidden)
+ fingerprintshidden = from.fingerprintshidden.Copy()
+ if(from.fingerprintslast)
+ fingerprintslast = from.fingerprintslast
//TODO bloody overlay
/obj/item/stack/microwave_act(obj/machinery/microwave/M)
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 0e768094..55f5e061 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -34,6 +34,8 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
/obj/item/storage/toolbox/update_icon()
..()
cut_overlays()
+ if(length(blood_DNA))
+ add_blood_overlay()
if(has_latches)
var/icon/I = icon('icons/obj/storage.dmi', latches)
add_overlay(I)
@@ -312,4 +314,4 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
generate_rubber_toolbox_icon()
icon = GLOB.rubber_toolbox_icons[icon_state]
. = ..()
- AddComponent(/datum/component/bouncy)
\ No newline at end of file
+ AddComponent(/datum/component/bouncy)
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 46c1506f..360e9943 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())
@@ -881,4 +882,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 186fb6da..92d9e550 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -319,6 +319,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
@@ -329,8 +330,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)
@@ -382,7 +384,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))
@@ -399,9 +402,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)
@@ -499,7 +504,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)
@@ -555,7 +561,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)
@@ -676,4 +683,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 1f03b222..1730a2ec 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -238,6 +238,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 b05fcad6..a399c91e 100644
--- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
@@ -372,6 +372,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/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index b756265b..49fb6720 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -741,7 +741,7 @@
var/turf/T = get_turf(target)
if(T)
for(var/obj/effect/decal/cleanable/blood/B in view(T, 2))
- if(B.blood_state == "blood")
+ if(B.blood_state == BLOOD_STATE_BLOOD)
if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam
temp += 30
else
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index fd8d2ce1..666e9907 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -311,7 +311,7 @@
if(ishuman(cultist))
var/mob/living/carbon/human/H = cultist
H.eye_color = "f00"
- H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
+ H.dna?.update_ui_block(DNA_EYE_COLOR_BLOCK)
ADD_TRAIT(H, TRAIT_CULT_EYES, "valid_cultist")
H.update_body()
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 97d6ce3e..48a9879c 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -891,7 +891,7 @@ structure_check() searches for nearby cultist structures required for the invoca
if(new_human)
new_human.visible_message("[new_human] suddenly dissolves into bones and ashes.", \
"Your link to the world fades. Your form breaks apart.")
- for(var/obj/I in new_human)
+ for(var/obj/item/I in new_human)
new_human.dropItemToGround(I, TRUE)
new_human.dust()
else if(choice == "Ascend as a Dark Spirit")
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index d4b05440..13a332de 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -255,7 +255,7 @@
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
var/mob/living/carbon/human/target = null
- var/list/mob/living/carbon/human/possible = list()
+ var/list/mob/living/carbon/human/possible
var/obj/item/voodoo_link = null
var/cooldown_time = 30 //3s
var/cooldown = 0
@@ -293,7 +293,7 @@
user.unset_machine()
/obj/item/voodoo/attack_self(mob/user)
- if(!target && possible.len)
+ if(!target && length(possible))
target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
return
@@ -333,15 +333,12 @@
cooldown = world.time + cooldown_time
/obj/item/voodoo/proc/update_targets()
- possible = list()
+ possible = null
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)])
- possible |= H
+ if(md5(H.dna.uni_identity) in voodoo_link.fingerprints)
+ LAZYOR(possible, H)
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
if(prob(50) || force)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 9d47a6cf..13d08dd5 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1381,17 +1381,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 988a0510..00cb9b1e 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()
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index c8116ea4..fc1e78b6 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -46,11 +46,11 @@
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)
..()
if(ismob(loc))
var/mob/M = loc
- M.update_inv_head()
\ No newline at end of file
+ M.update_inv_head()
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 7f7cc60f..337bd4a5 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 dd3ff919..94472f79 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 59fba6e5..b420ee67 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,28 @@
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 +101,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 bd837c14..6e469faa 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -5,6 +5,7 @@
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
@@ -30,12 +31,12 @@
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"))
+ 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 list("Fox","Wolf","Otie","Drake","Lab","Shepherd","Husky","Eevee","Panther","Horse","Cow","Tiger","Deer"))
+ else if(H.dna.features["taur"] in GLOB.paw_taurs)
taurmode = PAW_TAURIC
if(tauric == TRUE)
center = TRUE
@@ -53,11 +54,11 @@
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
- IF_HAS_BLOOD_DNA(src)
- if(taurmode >= SNEK_TAURIC)
- . += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood")
+ 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")
+ . += 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
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 422be6e3..2889242c 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 17396093..7ab5b2db 100644
--- a/code/modules/detectivework/detective_work.dm
+++ b/code/modules/detectivework/detective_work.dm
@@ -1,111 +1,101 @@
//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--
+ LAZYINITLIST(suit_fibers)
+ 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())
+ if(fingerprints)
+ LAZYINITLIST(A.fingerprints)
+ A.fingerprints |= fingerprints //detective
+ if(fingerprintshidden)
+ LAZYINITLIST(A.fingerprintshidden)
+ A.fingerprintshidden |= fingerprintshidden //admin
A.fingerprintslast = fingerprintslast
diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm
index 1a4a2d87..60e4b7af 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 f9cd1256..bff010a3 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
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index ca1a961a..051aea93 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,9 +86,12 @@
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
+ temp_bleed += 0.5 * BP.embedded_objects.len
if(brutedamage >= 20)
temp_bleed += (brutedamage * 0.013)
@@ -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,26 @@
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 = drop.blood_DNA.Copy() //transfer dna from drip to 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 +311,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 +323,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 cc11c0e8..19500653 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 97b29ca4..1b2944c1 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 41732d7f..f7fdd2d3 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 fbae1e89..a2c5db48 100644
--- a/code/modules/mob/living/carbon/alien/death.dm
+++ b/code/modules/mob/living/carbon/alien/death.dm
@@ -1,8 +1,9 @@
-/mob/living/carbon/alien/spawn_gibs(with_bodyparts)
+/mob/living/carbon/alien/spawn_gibs(with_bodyparts, atom/loc_override)
+ var/location = loc_override ? loc_override.drop_location() : drop_location()
if(with_bodyparts)
- new /obj/effect/gibspawner/xeno(drop_location())
+ new /obj/effect/gibspawner/xeno(location, src)
else
- new /obj/effect/gibspawner/xenobodypartless(drop_location())
+ new /obj/effect/gibspawner/xeno/bodypartless(location, src)
/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 f9ed1f9b..9d0688e5 100644
--- a/code/modules/mob/living/carbon/alien/larva/death.dm
+++ b/code/modules/mob/living/carbon/alien/larva/death.dm
@@ -6,11 +6,12 @@
update_icons()
-/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts)
+/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts, atom/loc_override)
+ var/location = loc_override ? loc_override.drop_location() : drop_location()
if(with_bodyparts)
- new /obj/effect/gibspawner/larva(drop_location())
+ new /obj/effect/gibspawner/larva(location, src)
else
- new /obj/effect/gibspawner/larvabodypartless(drop_location())
+ new /obj/effect/gibspawner/larva/bodypartless(location, src)
/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 df1be454..7b696279 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/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index ada57d67..343f22d7 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 //5x was too much, this is punishing 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 db54b035..f61c8741 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -4,11 +4,22 @@
/mob/living/carbon/human/dust_animation()
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())
+/mob/living/carbon/human/spawn_gibs(with_bodyparts, atom/loc_override)
+ var/location = loc_override ? loc_override.drop_location() : drop_location()
+ if(dna?.species?.gib_types)
+ var/blood_dna = get_blood_dna_list()
+ var/datum/species/S = dna.species
+ var/length = length(S.gib_types)
+ if(length)
+ var/path = (with_bodyparts && length > 1) ? S.gib_types[2] : S.gib_types[1]
+ new path(location, src, get_static_viruses())
+ else
+ new S.gib_types(location, src, get_static_viruses(), blood_dna)
else
- new /obj/effect/gibspawner/humanbodypartless(drop_location(), dna, get_static_viruses())
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/human(location, src, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/human/bodypartless(location, src, 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 f155ff62..415218c4 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -45,7 +45,7 @@
if(wear_suit)
. += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
//suit/armor storage
- if(s_store)
+ if(s_store && !(SLOT_S_STORE in obscured))
. += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name]."
//back
if(back)
@@ -56,11 +56,10 @@
if(!(I.item_flags & ABSTRACT))
. += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
- GET_COMPONENT(FR, /datum/component/forensics)
//gloves
if(gloves && !(SLOT_GLOVES in obscured))
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
- else if(FR && length(FR.blood_DNA))
+ else if(length(blood_DNA))
var/hand_number = get_num_arms(FALSE)
if(hand_number)
. += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!"
@@ -83,7 +82,7 @@
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
. += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face."
- if (wear_neck && !(SLOT_NECK in obscured))
+ if(wear_neck && !(SLOT_NECK in obscured))
. += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
//eyes
@@ -146,7 +145,7 @@
. += "It appears that [t_his] brain is missing..."
var/temp = getBruteLoss() //no need to calculate each of these twice
-
+
var/list/msg = list()
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)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 263e86f0..89765081 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -33,7 +33,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()
@@ -699,16 +699,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
@@ -1110,6 +1111,20 @@
/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
//define holder_type on nerds we wanna commit scoop to
/* /mob/living/carbon/human
var/holder_type = /obj/item/clothing/head/mob_holder/micro
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index d0a16ea0..ea25104c 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -49,6 +49,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 5dc4400f..d489c2e3 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -127,3 +127,10 @@
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 4dc63308..95f1a69c 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -56,18 +56,17 @@
//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
+ 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)
- 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/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()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index cc2d088d..fef4c127 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
+ var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
var/skinned_type
var/liked_food = NONE
var/disliked_food = GROSS
@@ -314,7 +315,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/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)
@@ -968,6 +972,16 @@ GLOBAL_LIST_EMPTY(roundstart_races)
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/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm
index 44001e62..ad9ba837 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -6,6 +6,7 @@
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
meat = null
+ gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
mutanttongue = /obj/item/organ/tongue/robot
limbs_id = "synth"
diff --git a/code/modules/mob/living/carbon/human/species_types/corporate.dm b/code/modules/mob/living/carbon/human/species_types/corporate.dm
index 146090b3..3de530ff 100644
--- a/code/modules/mob/living/carbon/human/species_types/corporate.dm
+++ b/code/modules/mob/living/carbon/human/species_types/corporate.dm
@@ -17,4 +17,5 @@
use_skintones = 0
species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
- sexes = 0
\ No newline at end of file
+ sexes = 0
+ gib_types = /obj/effect/gibspawner/robot
\ No newline at end of file
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 3ef8b0f8..40cbcbab 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/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index fc4b9a4e..5b039296 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,16 @@
id = "jelly"
default_color = "00FF90"
say_mod = "chirps"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
+ 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") //CIT CHANGE
default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None") //CIT CHANGE
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
- exotic_blood = "slimejelly"
+ gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
+ 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 +124,7 @@
name = "Slimeperson"
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
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 38e5ec85..ce4591f0 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -16,6 +16,7 @@
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard
+ gib_types = list(/obj/effect/gibspawner/lizard, /obj/effect/gibspawner/lizard/bodypartless)
skinned_type = /obj/item/stack/sheet/animalhide/lizard
exotic_bloodtype = "L"
disliked_food = GRAIN | DAIRY
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
index 02825e35..1929d87f 100644
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
@@ -14,6 +14,7 @@
liked_food = VEGETABLES | DAIRY| CLOTH
disliked_food = FRUIT | GROSS
toxic_food = MEAT | RAW
+ exotic_bloodtype = "BUG"
/datum/species/moth/on_species_gain(mob/living/carbon/C)
. = ..()
@@ -58,4 +59,4 @@
if(H.loc && !isspaceturf(H.loc) && H.dna.features["moth_wings"] != "Burnt Off")
var/datum/gas_mixture/current = H.loc.return_air()
if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
- return TRUE
\ No newline at end of file
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index fea6ab43..1d0370c7 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -9,6 +9,7 @@
dangerous_existence = 1
blacklisted = 1
meat = null
+ gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
limbs_id = "synth"
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index e278e7dc..1a75d508 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -186,7 +186,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"
@@ -276,6 +276,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 5c67b69a..3541840a 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -145,8 +145,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/death.dm b/code/modules/mob/living/death.dm
index ba81bd4e..31f6f842 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -19,8 +19,12 @@
/mob/living/proc/gib_animation()
return
-/mob/living/proc/spawn_gibs()
- new /obj/effect/gibspawner/generic(drop_location(), null, get_static_viruses())
+/mob/living/proc/spawn_gibs(with_bodyparts, atom/loc_override)
+ var/location = loc_override ? loc_override.drop_location() : drop_location()
+ if(mob_biotypes & MOB_ROBOTIC)
+ new /obj/effect/gibspawner/robot(location, src, get_static_viruses())
+ else
+ new /obj/effect/gibspawner/generic(location, src, get_static_viruses())
/mob/living/proc/spill_organs()
return
diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm
index 040c4265..73574102 100644
--- a/code/modules/mob/living/silicon/death.dm
+++ b/code/modules/mob/living/silicon/death.dm
@@ -1,5 +1,5 @@
-/mob/living/silicon/spawn_gibs()
- new /obj/effect/gibspawner/robot(drop_location())
+/mob/living/silicon/spawn_gibs(with_bodyparts, atom/loc_override)
+ new /obj/effect/gibspawner/robot(loc_override ? loc_override.drop_location() : drop_location(), src)
/mob/living/silicon/spawn_dust()
new /obj/effect/decal/remains/robot(loc)
@@ -10,4 +10,4 @@
diag_hud_set_status()
diag_hud_set_health()
update_health_hud()
- . = ..()
\ No newline at end of file
+ . = ..()
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index ef4d9aef..c9b9963d 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -184,8 +184,9 @@
return TRUE
/mob/living/simple_animal/bot/death(gibbed)
- explode()
- ..()
+ . = ..()
+ if(!gibbed)
+ explode()
/mob/living/simple_animal/bot/proc/explode()
qdel(src)
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index 9e72c22a..8e98e2dd 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -289,7 +289,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
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 7b1fa9c9..3601f1ca 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -474,7 +474,8 @@
if(isturf(next))
if(bloodiness)
var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
- B.add_blood_DNA(return_blood_DNA())
+ if(length(blood_DNA))
+ B.blood_DNA |= blood_DNA.Copy()
var/newdir = get_dir(next, loc)
if(newdir == dir)
B.setDir(newdir)
@@ -487,7 +488,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 79a90132..bb513581 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -177,6 +177,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 c2d0a214..910e9c3c 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/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
index d144ad27..e48f17e3 100644
--- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -92,7 +92,7 @@
if(M)
playsound(src, 'sound/magic/demon_consume.ogg', 50, 1)
M.adjustBruteLoss(60)
- new /obj/effect/gibspawner/generic(get_turf(M))
+ M.spawn_gibs()
if(M.stat == DEAD)
var/mob/living/simple_animal/hostile/netherworld/blankbody/blank
blank = new(loc)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index 33cca488..f94938b8 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -215,7 +215,7 @@
melee_damage_upper = 10
attacktext = "ferociously mauls"
environment_smash = ENVIRONMENT_SMASH_NONE
- loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xenobodypartless, /obj/effect/particle_effect/foam, /obj/item/soap)
+ loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap)
attack_reagent = /datum/reagent/peaceborg_confuse
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer
@@ -259,7 +259,7 @@
melee_damage_lower = 10
melee_damage_upper = 20
attacktext = "awkwardly flails at"
- loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xenobodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/humanbodypartless, /obj/effect/gibspawner/human)
+ loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
/mob/living/simple_animal/hostile/retaliate/clown/mutant/blob
name = "Something that was once a clown"
@@ -272,5 +272,5 @@
mob_size = MOB_SIZE_LARGE
speed = 20
attacktext = "bounces off of"
- loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xenobodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/humanbodypartless, /obj/effect/gibspawner/human)
- attack_reagent = /datum/reagent/toxin/mindbreaker
\ No newline at end of file
+ loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
+ attack_reagent = /datum/reagent/toxin/mindbreaker
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 487185e1..134dc9f0 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -332,8 +332,8 @@
speak_chance *= 1.27 // 20 crackers to go from 1% to 100%
speech_shuffle_rate += 10
to_chat(user, "[src] eagerly devours the cracker.")
- ..()
- return
+ return // the cracker was deleted
+ return ..()
//Bullets
/mob/living/simple_animal/parrot/bullet_act(obj/item/projectile/Proj)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 3a3dacee..04a0aa40 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -486,3 +486,23 @@ 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
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 6acc68cf..acb30365 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -158,7 +158,7 @@
if(..())
if(reagents.total_volume)
if(M.reagents)
- reagents.trans_to(M, reagents.total_volume)
+ reagents.reaction(M, INJECT)
/obj/item/pen/sleepy/Initialize()
diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm
index 142388c3..9e098446 100644
--- a/code/modules/power/singularity/particle_accelerator/particle.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle.dm
@@ -59,7 +59,12 @@
/obj/effect/accelerated_particle/proc/move()
if(!step(src,dir))
- forceMove(get_step(src,dir))
+ var/turf/T = get_step(src,dir)
+ if(T)
+ forceMove(T)
+ else
+ qdel(src)
+ return
movement_range--
if(movement_range == 0)
qdel(src)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 71c771c3..9686b3c9 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -86,10 +86,9 @@
if(iscarbon(user))
var/mob/living/carbon/C = user
C.visible_message("[C]'s head begins to collapse in on itself!", "Your head feels like it's collapsing in on itself! This was really not a good idea!", "You hear something crack and explode in gore.")
- var/turf/T = get_turf(C)
for(var/i in 1 to 3)
C.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
- new /obj/effect/gibspawner/generic(T)
+ C.spawn_gibs()
sleep(1)
C.ghostize()
var/obj/item/bodypart/head/rip_u = C.get_bodypart(BODY_ZONE_HEAD)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index 31f6b3dd..26e14ed5 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -153,7 +153,7 @@
#define BRAINS_BLOWN_THROW_RANGE 3
#define BRAINS_BLOWN_THROW_SPEED 1
-/obj/item/gun/ballistic/suicide_act(mob/user)
+/obj/item/gun/ballistic/suicide_act(mob/living/user)
var/obj/item/organ/brain/B = user.getorganslot(ORGAN_SLOT_BRAIN)
if (B && chambered && chambered.BB && can_trigger_gun(user) && !chambered.BB.nodamage)
user.visible_message("[user] is putting the barrel of [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!")
@@ -166,12 +166,10 @@
var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE)
B.Remove(user)
B.forceMove(T)
- var/datum/dna/user_dna
if(iscarbon(user))
var/mob/living/carbon/C = user
- user_dna = C.dna
- B.add_blood_DNA(user_dna)
- var/datum/callback/gibspawner = CALLBACK(GLOBAL_PROC, /proc/spawn_atom_to_turf, /obj/effect/gibspawner/generic, B, 1, FALSE, list(user_dna))
+ B.add_blood_DNA(C.dna, C.diseases)
+ var/datum/callback/gibspawner = CALLBACK(user, /mob/living/proc/spawn_gibs, FALSE, B)
B.throw_at(target, BRAINS_BLOWN_THROW_RANGE, BRAINS_BLOWN_THROW_SPEED, callback=gibspawner)
return(BRUTELOSS)
else
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 6dd37062..58f52f81 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -364,14 +364,17 @@
desc = "Decreases the cooldown of a kinetic accelerator. Not rated for minebot use."
modifier = 2.5
minebot_upgrade = FALSE
+ var/decreased
/obj/item/borg/upgrade/modkit/cooldown/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user)
. = ..()
if(.)
- KA.overheat_time -= modifier
+ var/old = KA.overheat_time
+ KA.overheat_time = max(0, KA.overheat_time - modifier)
+ decreased = old - KA.overheat_time
/obj/item/borg/upgrade/modkit/cooldown/uninstall(obj/item/gun/energy/kinetic_accelerator/KA)
- KA.overheat_time += modifier
+ KA.overheat_time += decreased
..()
/obj/item/borg/upgrade/modkit/cooldown/minebot
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 3cf287d1..27b896c9 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -163,10 +163,19 @@
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)
diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm
index 4a36ecf9..bcb7397e 100644
--- a/code/modules/projectiles/projectile/bullets/smg.dm
+++ b/code/modules/projectiles/projectile/bullets/smg.dm
@@ -19,29 +19,40 @@
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)
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index 720d411d..5e80c42a 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 81d2b87e..85f42356 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,8 +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
+ 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
@@ -27,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"]
@@ -77,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"
@@ -604,6 +737,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
@@ -966,12 +1123,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.25
..()
/datum/reagent/iron/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
@@ -980,6 +1137,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"
@@ -1096,17 +1264,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)
@@ -1124,26 +1294,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 c45a7e44..67070475 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -282,6 +282,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 8f0eae2e..3d1c5671 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -27,7 +27,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 3e555f38..fe35981b 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/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 68c8925d..101aa1be 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -104,7 +104,7 @@
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) // transfer from, transfer to - who cares?
to_chat(user, "You fill [src] with [trans] units of the solution. It now contains [reagents.total_volume] units.")
- if (reagents.total_volume >= reagents.maximum_volume)
+ if (round(reagents.total_volume, 0.1) >= reagents.maximum_volume)
mode=!mode
update_icon()
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 7cb8a460..2e0d769d 100644
--- a/code/modules/research/designs/machine_desings/machine_designs_medical.dm
+++ b/code/modules/research/designs/machine_desings/machine_designs_medical.dm
@@ -105,3 +105,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 9b97f75e..b4a860c8 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -61,7 +61,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","genescanner")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "genescanner", "bloodbankgen")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index a2e80179..d33d0167 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -31,7 +31,7 @@
return FALSE
/mob/living/carbon/alien/larva/has_left_hand()
- return 1
+ return TRUE
/mob/proc/has_right_hand(check_disabled = TRUE)
@@ -45,10 +45,31 @@
return FALSE
/mob/living/carbon/alien/larva/has_right_hand()
- return 1
+ return TRUE
+/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 977a33b8..e84cd518 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."
@@ -215,6 +221,12 @@ obj/item/organ/heart/cybernetic/upgraded/on_life()
desc = "An electronic pump that regulates hydraulic functions, the electronics have EMP shielding."
icon_state = "heart-c"
+/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/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 6a1a35f3..5bc30f88 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 00000000..e2f0c974
Binary files /dev/null and b/icons/effects/fluidtracks.dmi differ
diff --git a/icons/effects/footprints.dmi b/icons/effects/footprints.dmi
index d7871b7a..69207097 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 fe92746b..c34b57b4 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 00000000..4b4b2b69
Binary files /dev/null and b/icons/obj/bloodbank.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 76ac0c71..d26e7a00 100644
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 2be99436..d0e059e7 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 bb8d4a5f..e5d386b5 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
@@ -1,18 +1,3 @@
-/mob/living/carbon/human/species/mammal
- race = /datum/species/mammal
-
-/mob/living/carbon/human/species/avian
- race = /datum/species/avian
-
-/mob/living/carbon/human/species/aquatic
- race = /datum/species/aquatic
-
-/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/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index 2e8dfb78..8daffa28 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -221,8 +221,9 @@
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
+ gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
skinned_type = /obj/item/stack/sheet/animalhide/xeno
- exotic_bloodtype = "L"
+ exotic_bloodtype = "X*"
damage_overlay_type = "xeno"
liked_food = MEAT
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
index 2e0df07e..543cec81 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -1,5 +1,5 @@
/datum/species/ipc
- name = "I.P.C"
+ name = "I.P.C."
id = "ipc"
say_mod = "beeps"
default_color = "00FF00"
@@ -10,16 +10,16 @@
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
mutant_bodyparts = list("ipc_screen", "ipc_antenna")
default_features = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
- meat = null //robots can't make meat silly!
-//Just robo looking parts.
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
+ gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
+ mutanttongue = /obj/item/organ/tongue/robot/ipc
mutant_heart = /obj/item/organ/heart/ipc
mutantlungs = /obj/item/organ/lungs/ipc
mutantliver = /obj/item/organ/liver/ipc
mutantstomach = /obj/item/organ/stomach/ipc
mutanteyes = /obj/item/organ/eyes/ipc
- mutanttongue = /obj/item/organ/tongue/robot
- exotic_bloodtype = "oil"
+ exotic_bloodtype = "HF"
var/datum/action/innate/monitor_change/screen
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 87586fb5..2acad715 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -8,7 +8,7 @@
id = "slimeperson"
limbs_id = "slime"
default_color = "00FFFF"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD,WINGCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
inherent_traits = list(TRAIT_TOXINLOVER)
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "deco_wings")
default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
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 00063c22..c8ebde11 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 91d7a1c2..11f525a4 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -10,7 +10,7 @@
if(clear_conversion == REACTION_CLEAR_IMPURE | REACTION_CLEAR_INVERSE)
for(var/id in results)
var/datum/reagent/R = my_atom.reagents.has_reagent("[id]")
- if(R.purity == 1)
+ if(!R || R.purity == 1)
continue
var/cached_volume = R.volume
@@ -25,7 +25,6 @@
my_atom.reagents.add_reagent(R.impure_chem, impureVol, FALSE, other_purity = 1)
R.cached_purity = R.purity
R.purity = 1
- return
//Called when temperature is above a certain threshold, or if purity is too low.
/datum/chemical_reaction/proc/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH, Exploding = FALSE)
@@ -317,10 +316,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 0337d213..d9f2cdf0 100644
--- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
+++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
@@ -36,13 +36,15 @@
icon_state = "semen1"
random_icon_states = list("semen1", "semen2", "semen3", "semen4")
-/obj/effect/decal/cleanable/semen/New()
- ..()
- dir = pick(1,2,4,8)
+/obj/effect/decal/cleanable/semen/Initialize(mapload)
+ . = ..()
+ dir = GLOB.cardinals
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
+ return ..()
/datum/reagent/consumable/femcum
name = "Female Ejaculate"
@@ -68,14 +70,15 @@
blood_state = null
bloodiness = null
-/obj/effect/decal/cleanable/femcum/New()
- ..()
- dir = pick(1,2,4,8)
+/obj/effect/decal/cleanable/femcum/Initialize(mapload)
+ . = ..()
+ dir = GLOB.cardinals
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
+ return ..()
/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume)
if(!istype(T))
@@ -117,7 +120,9 @@
add_blood_DNA(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/milk/replace_decal(obj/effect/decal/cleanable/milk/S)
- S.add_blood_DNA(return_blood_DNA())
+ if(S.blood_DNA)
+ blood_DNA |= S.blood_DNA
+ return ..()
//aphrodisiac & anaphrodisiac
diff --git a/modular_citadel/icons/mob/64x32_effects.dmi b/modular_citadel/icons/mob/64x32_effects.dmi
index 7db65a8f..a11b3584 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 98f712d1..a3faaffe 100644
--- 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"
@@ -365,7 +364,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"
@@ -394,7 +392,6 @@
#include "code\datums\components\uplink.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"
@@ -600,6 +597,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"
@@ -782,6 +780,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 f0a8182c..c12964ce 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 8bb1dca3..15aa04c0 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 2c316e94..deab468e 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