mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 01:34:01 +00:00
## About The Pull Request This PR adds some wacky interactions for meat and hauntium, should you choose to transmute items into them using metalgen. - You can imprint a mob's specific meat onto metalgen using their blood (It doesn't even have to be the blood reagent, it can be any reagent that was drawn from a mob's blood). - Mob meat now applies the source's blood color to items made out of it. - Organs and bodyparts made primarily out of meat become organic, if they weren't already. - Organs and bodyparts made primarily out of hauntium become ghostly, if they weren't already. This makes them suitable for ghost species wall-phasing. ## Why It's Good For The Game Regarding the cosmetic change to mob meat, I thought it only appropriate that mob meat material should take on the color of the mob it was taken from. For imprinting mob meat onto metalgen using that mob's blood, I thought it would be funny to take people's blood and transmute objects into being made out of those people's own flesh. For meaty bodyparts and organs being organic, it can be argued that the thing that makes organic bodyparts and organs organic is being made out of meat, so I think the reverse logic should also apply. For hauntium bodyparts and organs being ghostly, the ghostly nature of ghostly bodyparts and organs should be what allows them to not fall out of a ghost when they become incorporeal. And how could something made primarily out of a substance extracted from ghosts **NOT** be ghostly in nature? That said, it's only *theoretically* possible to get hauntium bodyparts and organs as a ghost, what with there being no way to do surgery on ghosts. Good luck figuring out and executing the steps to actually do this. ## Changelog 🆑 add: Items made out of a specific mob's meat take on the color of that mob's blood. add: Blood (or anything a mob uses as blood) can be used to imprint that mob's meat onto metalgen. add: Organs and bodyparts made predominantly out of meat become organic, if they weren't already. Likewise, hauntium makes them ghostly. /🆑
229 lines
8.2 KiB
Plaintext
229 lines
8.2 KiB
Plaintext
/// Element that blood reagents use to apply their data (not blood regen!) to mobs
|
|
/// Only added to blood drawn *from* someone, so don't put behavior that should work with any reagent onto this
|
|
/datum/element/blood_reagent
|
|
element_flags = ELEMENT_BESPOKE
|
|
argument_hash_start_idx = 3
|
|
/// Blood type associated with this element
|
|
var/datum/blood_type/blood_type
|
|
|
|
/*
|
|
* Arguments:
|
|
* * blood_source - mob this blood came from, can be null
|
|
* * blood_type - blood type datum we grab data and behavior from, cannot be null
|
|
*/
|
|
/datum/element/blood_reagent/Attach(datum/reagent/target, mob/living/blood_source, datum/blood_type/blood_type)
|
|
. = ..()
|
|
if (!istype(target) || !istype(blood_type))
|
|
return ELEMENT_INCOMPATIBLE
|
|
|
|
src.blood_type = blood_type
|
|
RegisterSignal(target, COMSIG_REAGENT_EXPOSE_MOB, PROC_REF(on_mob_expose))
|
|
RegisterSignal(target, COMSIG_REAGENT_EXPOSE_TURF, PROC_REF(on_turf_expose))
|
|
RegisterSignal(target, COMSIG_REAGENT_EXPOSE_OBJ, PROC_REF(on_obj_expose))
|
|
RegisterSignal(target, COMSIG_REAGENT_ON_MERGE, PROC_REF(on_merge))
|
|
RegisterSignal(target, COMSIG_REAGENT_ON_TRANSFER, PROC_REF(on_transfer))
|
|
|
|
if (!target.data)
|
|
target.data = list()
|
|
|
|
target.data["blood_type"] = blood_type
|
|
if (blood_type.desc)
|
|
target.description = blood_type.desc
|
|
target.color = blood_type.get_color()
|
|
|
|
|
|
if (!blood_source)
|
|
target.material = GET_MATERIAL_REF(/datum/material/meat/blood_meat, target)
|
|
return
|
|
|
|
target.material = GET_MATERIAL_REF(/datum/material/meat/mob_meat, blood_source)
|
|
|
|
var/list/blood_data = blood_source.get_blood_data()
|
|
if(blood_data["viruses"])
|
|
var/list/to_preserve = list()
|
|
for (var/datum/disease/disease in blood_data["viruses"])
|
|
to_preserve += disease.Copy()
|
|
blood_data["viruses"] = to_preserve
|
|
|
|
for (var/key in blood_data)
|
|
if (!islist(blood_data[key]))
|
|
target.data[key] = blood_data[key]
|
|
continue
|
|
|
|
var/list/data_list = blood_data[key]
|
|
var/list/target_data = target.data[key]
|
|
if (!target_data)
|
|
target.data[key] = data_list.Copy()
|
|
else
|
|
// Concat viruses, resistances, etc
|
|
target_data |= data_list
|
|
|
|
// Shouldn't realistically happen but just in case
|
|
/datum/element/blood_reagent/Detach(datum/reagent/target)
|
|
. = ..()
|
|
UnregisterSignal(target, list(
|
|
COMSIG_REAGENT_EXPOSE_MOB,
|
|
COMSIG_REAGENT_EXPOSE_TURF,
|
|
COMSIG_REAGENT_EXPOSE_OBJ,
|
|
COMSIG_REAGENT_ON_MERGE,
|
|
COMSIG_REAGENT_ON_TRANSFER,
|
|
))
|
|
|
|
/// Cover the mob in blood and transfer our viruses and resistances to them
|
|
/datum/element/blood_reagent/proc/on_mob_expose(
|
|
datum/reagent/source,
|
|
mob/living/exposed_mob,
|
|
methods = TOUCH,
|
|
reac_volume,
|
|
show_message = TRUE,
|
|
touch_protection = 0,
|
|
)
|
|
SIGNAL_HANDLER
|
|
|
|
if ((methods & (TOUCH | VAPOR)) && reac_volume >= 3 && (blood_type.blood_flags & (BLOOD_ADD_DNA | BLOOD_COVER_MOBS)))
|
|
exposed_mob.add_blood_DNA(list("[source.data?["blood_DNA"] || blood_type.dna_string]" = blood_type))
|
|
|
|
// Somehow got a no-data reagent, probably artificially created blood
|
|
if (!source.data)
|
|
return
|
|
|
|
if (!(blood_type.blood_flags & BLOOD_TRANSFER_VIRAL_DATA))
|
|
return
|
|
|
|
for(var/datum/disease/strain as anything in source.data["viruses"])
|
|
if ((strain.spread_flags & DISEASE_SPREAD_SPECIAL) || (strain.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS))
|
|
continue
|
|
|
|
if (methods & INGEST)
|
|
if (!strain.has_required_infectious_organ(exposed_mob, ORGAN_SLOT_STOMACH))
|
|
continue
|
|
exposed_mob.ForceContractDisease(strain)
|
|
|
|
else if (methods & (INJECT|PATCH))
|
|
if (!strain.has_required_infectious_organ(exposed_mob, ORGAN_SLOT_HEART))
|
|
continue
|
|
exposed_mob.ForceContractDisease(strain)
|
|
|
|
else if ((methods & (VAPOR|INHALE)) && (strain.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS))
|
|
if (!strain.has_required_infectious_organ(exposed_mob, ORGAN_SLOT_LUNGS))
|
|
continue
|
|
exposed_mob.ContactContractDisease(strain)
|
|
|
|
else if ((methods & TOUCH) && (strain.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS))
|
|
exposed_mob.ContactContractDisease(strain)
|
|
|
|
/// Have to inject, inhale or ingest it. No curefoam/cheap curesprays
|
|
if (source.data["resistances"] && (methods & (INGEST|INJECT|INHALE)))
|
|
for(var/datum/disease/infection in exposed_mob.diseases)
|
|
if (!infection.bypasses_immunity && (infection.GetDiseaseID() in source.data["resistances"]))
|
|
infection.cure(add_resistance = FALSE)
|
|
|
|
/// Create or mix in a blood splatter and transfer our diseases to it
|
|
/datum/element/blood_reagent/proc/on_turf_expose(datum/reagent/source, turf/exposed_turf, reac_volume)
|
|
SIGNAL_HANDLER
|
|
|
|
if (reac_volume < 3 || !(blood_type.blood_flags & (BLOOD_ADD_DNA | BLOOD_COVER_TURFS)))
|
|
return
|
|
|
|
var/dna_list = list("[source.data?["blood_DNA"] || blood_type.dna_string]" = blood_type)
|
|
var/obj/effect/decal/cleanable/blood/splatter = locate() in exposed_turf
|
|
if (!splatter)
|
|
if (!(blood_type.blood_flags & BLOOD_COVER_TURFS))
|
|
return
|
|
splatter = new(exposed_turf, (blood_type.blood_flags & BLOOD_TRANSFER_VIRAL_DATA) ? source.data?["viruses"] : null, dna_list)
|
|
splatter.adjust_bloodiness(-splatter.bloodiness + reac_volume / BLOOD_TO_UNITS_MULTIPLIER)
|
|
return
|
|
|
|
splatter.add_blood_DNA(dna_list)
|
|
if (blood_type.blood_flags & BLOOD_COVER_TURFS)
|
|
splatter.adjust_bloodiness(reac_volume / BLOOD_TO_UNITS_MULTIPLIER)
|
|
|
|
if (!(blood_type.blood_flags & BLOOD_TRANSFER_VIRAL_DATA) || !source.data?["viruses"])
|
|
return
|
|
|
|
var/list/viruses_to_add = list()
|
|
for(var/datum/disease/virus in source.data["viruses"])
|
|
if (virus.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)
|
|
viruses_to_add += virus
|
|
|
|
if (length(viruses_to_add))
|
|
splatter.AddComponent(/datum/component/infective, viruses_to_add)
|
|
|
|
/datum/element/blood_reagent/proc/on_obj_expose(datum/reagent/source, obj/exposed_obj, reac_volume, methods = TOUCH, show_message = TRUE)
|
|
SIGNAL_HANDLER
|
|
|
|
if (reac_volume < 3 || !(methods & (VAPOR | TOUCH)))
|
|
return
|
|
|
|
if (blood_type.blood_flags & (BLOOD_ADD_DNA | BLOOD_COVER_ITEMS))
|
|
exposed_obj.add_blood_DNA(list(list("[source.data?["blood_DNA"] || blood_type.dna_string]" = blood_type) = blood_type))
|
|
|
|
if (!(blood_type.blood_flags & BLOOD_TRANSFER_VIRAL_DATA) || !source.data?["viruses"])
|
|
return
|
|
|
|
var/list/viruses_to_add = list()
|
|
for (var/datum/disease/virus in source.data["viruses"])
|
|
if (virus.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)
|
|
viruses_to_add += virus
|
|
|
|
if (length(viruses_to_add))
|
|
exposed_obj.AddComponent(/datum/component/infective, viruses_to_add)
|
|
|
|
/datum/element/blood_reagent/proc/on_merge(datum/reagent/source, list/mix_data, amount)
|
|
SIGNAL_HANDLER
|
|
|
|
// Presumably artificially generated blood
|
|
if (!source.data || !mix_data)
|
|
return
|
|
|
|
// Mixed blood cannot be used for cloning
|
|
if (source.data["blood_DNA"] != mix_data["blood_DNA"])
|
|
source.data["cloneable"] = FALSE
|
|
|
|
var/list/source_viruses = source.data["viruses"]
|
|
var/list/mix_viruses = mix_data["viruses"]
|
|
if (source_viruses && mix_viruses)
|
|
var/list/mix_target = list()
|
|
var/list/to_preserve = list()
|
|
for (var/datum/disease/disease as anything in source_viruses)
|
|
if (istype(disease, /datum/disease/advance))
|
|
mix_target += disease
|
|
else
|
|
to_preserve += disease
|
|
|
|
for (var/datum/disease/disease as anything in mix_viruses)
|
|
if (istype(disease, /datum/disease/advance))
|
|
mix_target += disease
|
|
else
|
|
to_preserve += disease
|
|
|
|
var/datum/disease/advance/disease = Advance_Mix(mix_target)
|
|
if (disease)
|
|
to_preserve += disease
|
|
source.data["viruses"] = to_preserve
|
|
else if (mix_viruses)
|
|
source.data["viruses"] = mix_viruses.Copy()
|
|
|
|
if (mix_data["resistances"])
|
|
if (!source.data["resistances"])
|
|
source.data["resistances"] = list()
|
|
source.data["resistances"] |= mix_data["resistances"]
|
|
|
|
// Features are randomly recombinated based on amount mixed in
|
|
var/list/source_features = source.data["features"]
|
|
var/list/mix_features = mix_data["features"]
|
|
if (source_features && mix_features)
|
|
for (var/feature_key in mix_features)
|
|
if (!source_features[feature_key] || prob(amount / (source.volume + amount) * 100))
|
|
source_features[feature_key] = mix_features[feature_key]
|
|
|
|
if (mix_data["trace_chem"])
|
|
if (!source.data["trace_chem"])
|
|
source.data["trace_chem"] = mix_data["trace_chem"]
|
|
else
|
|
source.data["trace_chem"] = list2params(params2list(source.data["trace_chem"]) | params2list(mix_data["trace_chem"]))
|
|
|
|
/datum/element/blood_reagent/proc/on_transfer(datum/reagent/reagent, datum/reagents/target_holder, datum/reagent/new_reagent)
|
|
SIGNAL_HANDLER
|
|
new_reagent.AddElement(/datum/element/blood_reagent, null, blood_type)
|