mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
[PORT]: Elementizes and Greyscales blood decals/overlays 2 (#21126)
cause cowbot said it's good to go --------- Co-authored-by: cowbot92 <75333826+cowbot92@users.noreply.github.com>
This commit is contained in:
@@ -330,6 +330,9 @@
|
||||
#define SOFA_BROWN "#a75400"
|
||||
#define SOFA_MAROON "#830000"
|
||||
|
||||
/// Color used for default blood
|
||||
#define COLOR_BLOOD "#CC0000"
|
||||
|
||||
GLOBAL_LIST_INIT(cable_colors, list(
|
||||
CABLE_COLOR_BLUE = CABLE_HEX_COLOR_BLUE,
|
||||
CABLE_COLOR_CYAN = CABLE_HEX_COLOR_CYAN,
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
/// You do not need this if you are only unregistering signals, for instance.
|
||||
/// You would need it if you are doing something like removing the target from a processing list.
|
||||
#define ELEMENT_DETACH_ON_HOST_DESTROY (1 << 0)
|
||||
|
||||
|
||||
// /datum/element flags
|
||||
/// Causes the detach proc to be called when the host object is being deleted
|
||||
#define ELEMENT_DETACH (1 << 0)
|
||||
/**
|
||||
* Only elements created with the same arguments given after `argument_hash_start_idx` share an element instance
|
||||
* The arguments are the same when the text and number values are the same and all other values have the same ref
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
/// Every proc you pass to RegisterSignal must have this.
|
||||
#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
/// Signifies that this proc is used to handle signals, but also sleeps.
|
||||
/// Do not use this for new work.
|
||||
#define SIGNAL_HANDLER_DOES_SLEEP
|
||||
|
||||
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
|
||||
#define AddElement(arguments...) _AddElement(list(##arguments))
|
||||
|
||||
|
||||
@@ -115,12 +115,11 @@
|
||||
GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
|
||||
//Bloody shoes/footprints
|
||||
#define MAX_SHOE_BLOODINESS 100
|
||||
#define BLOODY_FOOTPRINT_BASE_ALPHA 150
|
||||
#define BLOOD_GAIN_PER_STEP 100
|
||||
#define BLOOD_LOSS_PER_STEP 5
|
||||
#define BLOOD_LOSS_IN_SPREAD 20
|
||||
#define BLOOD_AMOUNT_PER_DECAL 20
|
||||
#define BLOODY_FOOTPRINT_BASE_ALPHA 80 /// Minimum alpha of footprints
|
||||
#define BLOOD_AMOUNT_PER_DECAL 50 /// How much blood a regular blood splatter contains
|
||||
#define BLOOD_ITEM_MAX 200 /// How much blood an item can have stuck on it
|
||||
#define BLOOD_POOL_MAX 300 /// How much blood a blood decal can contain
|
||||
#define BLOOD_FOOTPRINTS_MIN 5 /// How much blood a footprint need to at least contain
|
||||
|
||||
//Bloody shoe blood states
|
||||
#define BLOOD_STATE_HUMAN "blood"
|
||||
|
||||
@@ -737,3 +737,15 @@
|
||||
///sort any value in a list
|
||||
/proc/sort_list(list/list_to_sort, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(list_to_sort.Copy(), cmp)
|
||||
|
||||
|
||||
/// ORs two lazylists together without inserting errant nulls, returning a new list and not modifying the existing lists.
|
||||
#define LAZY_LISTS_OR(left_list, right_list)\
|
||||
(length(left_list)\
|
||||
? length(right_list)\
|
||||
? (left_list | right_list)\
|
||||
: left_list.Copy()\
|
||||
: length(right_list)\
|
||||
? right_list.Copy()\
|
||||
: null\
|
||||
)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/proc/random_blood_type()
|
||||
return pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
||||
|
||||
/proc/random_eye_color()
|
||||
switch(pick(20;"brown",20;"hazel",20;"grey",15;"blue",15;"green",1;"amber",1;"albino"))
|
||||
if("brown")
|
||||
|
||||
@@ -39,6 +39,14 @@ GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup)
|
||||
|
||||
GLOBAL_LIST_EMPTY(emote_list)
|
||||
|
||||
GLOBAL_LIST_INIT(blood_types, generate_blood_types())
|
||||
|
||||
/proc/generate_blood_types()
|
||||
. = list()
|
||||
for(var/path in subtypesof(/datum/blood_type))
|
||||
var/datum/blood_type/new_type = new path()
|
||||
.[new_type.name] = new_type
|
||||
|
||||
/// Keys are the names of the accents, values are the name of their .json file.
|
||||
GLOBAL_LIST_INIT(accents_name2file, strings("accents.json", "accent_file_names", directory = "strings/accents"))
|
||||
/// List of all accents
|
||||
|
||||
91
code/datums/blood_types.dm
Normal file
91
code/datums/blood_types.dm
Normal file
@@ -0,0 +1,91 @@
|
||||
/datum/blood_type
|
||||
/// Displayed name of the blood type.
|
||||
var/name = "?"
|
||||
/// Shown color of the blood type.
|
||||
var/color = COLOR_BLOOD
|
||||
/// Blood types that are safe to use with people that have this blood type.
|
||||
var/compatible_types = list()
|
||||
|
||||
/datum/blood_type/New()
|
||||
. = ..()
|
||||
compatible_types |= /datum/blood_type/universal
|
||||
|
||||
/datum/blood_type/universal
|
||||
name = "U"
|
||||
|
||||
/datum/blood_type/universal/New()
|
||||
. = ..()
|
||||
compatible_types |= subtypesof(/datum/blood_type)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//--------------------Normal human bloodtypes-----------------//
|
||||
////////////////////////////////////////////////////////////////
|
||||
/datum/blood_type/a_minus
|
||||
name = "A-"
|
||||
compatible_types = list(/datum/blood_type/a_minus, /datum/blood_type/o_minus)
|
||||
|
||||
/datum/blood_type/a_plus
|
||||
name = "A+"
|
||||
compatible_types = list(/datum/blood_type/a_minus, /datum/blood_type/a_plus, /datum/blood_type/o_minus, /datum/blood_type/o_plus)
|
||||
|
||||
/datum/blood_type/b_minus
|
||||
name = "B-"
|
||||
compatible_types = list(/datum/blood_type/b_minus, /datum/blood_type/o_minus, /datum/blood_type/universal)
|
||||
|
||||
/datum/blood_type/b_plus
|
||||
name = "B+"
|
||||
compatible_types = list(/datum/blood_type/b_minus, /datum/blood_type/b_plus, /datum/blood_type/o_minus, /datum/blood_type/o_plus)
|
||||
|
||||
/datum/blood_type/ab_minus
|
||||
name = "AB-"
|
||||
compatible_types = list(/datum/blood_type/b_minus, /datum/blood_type/a_minus, /datum/blood_type/ab_minus, /datum/blood_type/o_minus)
|
||||
|
||||
/datum/blood_type/ab_plus
|
||||
name = "AB+"
|
||||
compatible_types = list(/datum/blood_type/b_minus, /datum/blood_type/a_minus, /datum/blood_type/ab_minus, /datum/blood_type/o_minus)
|
||||
|
||||
/datum/blood_type/o_minus
|
||||
name = "O-"
|
||||
compatible_types = list(/datum/blood_type/o_minus)
|
||||
|
||||
/datum/blood_type/o_plus
|
||||
name = "O+"
|
||||
compatible_types = list(/datum/blood_type/o_minus, /datum/blood_type/o_plus)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//--------------------Other species bloodtypes----------------//
|
||||
////////////////////////////////////////////////////////////////
|
||||
/datum/blood_type/lizard
|
||||
name = "L"
|
||||
color = LIGHT_COLOR_BLUEGREEN
|
||||
compatible_types = list(/datum/blood_type/lizard)
|
||||
|
||||
|
||||
/datum/blood_type/universal/synthetic //Blood for preterni
|
||||
name = "Synthetic"
|
||||
color = LIGHT_COLOR_ELECTRIC_CYAN
|
||||
|
||||
/*
|
||||
The species have exotic blood, but with how dna is stored, they still need a blood type
|
||||
They're literally ONLY used to colour bloodsplats as far as I know (maybe it will be possible to podclone from bloodsplats)
|
||||
*/
|
||||
/datum/blood_type/xenomorph //for xenomorph gib dna and polysmorph bloodsplats
|
||||
name = "X"
|
||||
color = "#00FF32"
|
||||
compatible_types = list(/datum/blood_type/xenomorph)
|
||||
|
||||
/datum/blood_type/electricity
|
||||
name = "E"
|
||||
color = "#cbee63" //slightly more yellowy than regular liquid electricity because of the grey scale image used
|
||||
compatible_types = list(/datum/blood_type/electricity)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//-----------------Wonky simplemob(?) bloodtypes--------------//
|
||||
////////////////////////////////////////////////////////////////
|
||||
/datum/blood_type/animal //for simplemob gib dna
|
||||
name = "Y-"
|
||||
compatible_types = list(/datum/blood_type/animal)
|
||||
|
||||
/datum/blood_type/gorilla
|
||||
name = "G"
|
||||
compatible_types = list(/datum/blood_type/gorilla)
|
||||
289
code/datums/components/bloodysoles.dm
Normal file
289
code/datums/components/bloodysoles.dm
Normal file
@@ -0,0 +1,289 @@
|
||||
|
||||
|
||||
//Component for clothing items that can pick up blood from decals and spread it around everywhere when walking, such as shoes or suits with integrated shoes.
|
||||
|
||||
/datum/component/bloodysoles
|
||||
/// The type of the last grub pool we stepped in, used to decide the type of footprints to make
|
||||
var/last_blood_state = BLOOD_STATE_NOT_BLOODY
|
||||
|
||||
/// How much of each grubby type we have on our feet
|
||||
var/list/bloody_shoes = list(BLOOD_STATE_HUMAN = 0,BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
|
||||
|
||||
/// The ITEM_SLOT_* slot the item is equipped on, if it is.
|
||||
var/equipped_slot
|
||||
|
||||
/// The parent item but casted into atom type for easier use.
|
||||
var/atom/parent_atom
|
||||
|
||||
/// Either the mob carrying the item, or the mob itself for the /feet component subtype
|
||||
var/mob/living/carbon/wielder
|
||||
|
||||
/// The world.time when we last picked up blood
|
||||
var/last_pickup
|
||||
|
||||
/datum/component/bloodysoles/Initialize()
|
||||
if(!isclothing(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
parent_atom = parent
|
||||
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
|
||||
|
||||
//Unregisters from the wielder if necessary
|
||||
|
||||
/datum/component/bloodysoles/proc/unregister()
|
||||
if(!QDELETED(wielder))
|
||||
UnregisterSignal(wielder, COMSIG_MOVABLE_MOVED)
|
||||
UnregisterSignal(wielder, COMSIG_STEP_ON_BLOOD)
|
||||
wielder = null
|
||||
equipped_slot = null
|
||||
|
||||
|
||||
//Returns true if the parent item is obscured by something else that the wielder is wearing
|
||||
|
||||
/datum/component/bloodysoles/proc/is_obscured()
|
||||
return equipped_slot in wielder.check_obscured_slots(TRUE)
|
||||
|
||||
//Run to update the icon of the parent
|
||||
|
||||
/datum/component/bloodysoles/proc/update_icon()
|
||||
var/obj/item/parent_item = parent
|
||||
parent_item.update_slot_icon()
|
||||
|
||||
//Run to equally share the blood between us and a decal
|
||||
/datum/component/bloodysoles/proc/share_blood(obj/effect/decal/cleanable/pool)
|
||||
last_blood_state = pool.blood_state
|
||||
|
||||
// Share the blood between our boots and the blood pool
|
||||
var/total_bloodiness = pool.bloodiness + bloody_shoes[last_blood_state]
|
||||
|
||||
// We can however be limited by how much blood we can hold
|
||||
var/new_our_bloodiness = min(BLOOD_ITEM_MAX, total_bloodiness / 2)
|
||||
|
||||
bloody_shoes[last_blood_state] = new_our_bloodiness
|
||||
pool.bloodiness = total_bloodiness - new_our_bloodiness // Give the pool the remaining blood incase we were limited
|
||||
|
||||
parent_atom.add_blood_DNA(pool.return_blood_DNA())
|
||||
update_icon()
|
||||
|
||||
//Find a blood decal on a turf that matches our last_blood_state
|
||||
|
||||
/datum/component/bloodysoles/proc/find_pool_by_blood_state(turf/turfLoc, typeFilter = null)
|
||||
for(var/obj/effect/decal/cleanable/blood/pool in turfLoc)
|
||||
if(pool.blood_state == last_blood_state && (!typeFilter || istype(pool, typeFilter)))
|
||||
return pool
|
||||
|
||||
|
||||
//Adds the parent type to the footprint's shoe_types var
|
||||
|
||||
/datum/component/bloodysoles/proc/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/FP)
|
||||
FP.shoe_types |= parent.type
|
||||
|
||||
/*
|
||||
Called when the parent item is equipped by someone
|
||||
Used to register our wielder
|
||||
*/
|
||||
/datum/component/bloodysoles/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!iscarbon(equipper))
|
||||
return
|
||||
var/obj/item/parent_item = parent
|
||||
if(!(parent_item.slot_flags & slot))
|
||||
unregister()
|
||||
return
|
||||
|
||||
equipped_slot = slot
|
||||
wielder = equipper
|
||||
RegisterSignal(wielder, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
RegisterSignal(wielder, COMSIG_STEP_ON_BLOOD, PROC_REF(on_step_blood))
|
||||
|
||||
/*
|
||||
Called when the parent item has been dropped
|
||||
Used to deregister our wielder
|
||||
*/
|
||||
/datum/component/bloodysoles/proc/on_drop(datum/source, mob/dropper)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
unregister()
|
||||
|
||||
/*
|
||||
Called when the wielder has moved
|
||||
Used to make bloody footprints on the ground
|
||||
*/
|
||||
/datum/component/bloodysoles/proc/on_moved(datum/source, OldLoc, Dir, Forced)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(bloody_shoes[last_blood_state] == 0)
|
||||
return
|
||||
if(QDELETED(wielder) || is_obscured())
|
||||
return
|
||||
if(!(wielder.mobility_flags & MOBILITY_STAND) || !wielder.has_gravity(wielder.loc))
|
||||
return
|
||||
|
||||
var/half_our_blood = bloody_shoes[last_blood_state] / 2
|
||||
|
||||
// Add footprints in old loc if we have enough cream
|
||||
if(half_our_blood >= BLOOD_FOOTPRINTS_MIN)
|
||||
var/turf/oldLocTurf = get_turf(OldLoc)
|
||||
var/obj/effect/decal/cleanable/blood/footprints/oldLocFP = find_pool_by_blood_state(oldLocTurf, /obj/effect/decal/cleanable/blood/footprints)
|
||||
if(oldLocFP)
|
||||
// Footprints found in the tile we left, add us to it
|
||||
add_parent_to_footprint(oldLocFP)
|
||||
if (!(oldLocFP.exited_dirs & wielder.dir))
|
||||
oldLocFP.exited_dirs |= wielder.dir
|
||||
oldLocFP.update_icon()
|
||||
else if(find_pool_by_blood_state(oldLocTurf))
|
||||
// No footprints in the tile we left, but there was some other blood pool there. Add exit footprints on it
|
||||
bloody_shoes[last_blood_state] -= half_our_blood
|
||||
update_icon()
|
||||
|
||||
|
||||
oldLocFP = new(oldLocTurf)
|
||||
if(!QDELETED(oldLocFP)) ///prints merged
|
||||
oldLocFP.blood_state = last_blood_state
|
||||
oldLocFP.exited_dirs |= wielder.dir
|
||||
add_parent_to_footprint(oldLocFP)
|
||||
oldLocFP.bloodiness = half_our_blood
|
||||
oldLocFP.add_blood_DNA(parent_atom.return_blood_DNA())
|
||||
oldLocFP.update_icon()
|
||||
|
||||
half_our_blood = bloody_shoes[last_blood_state] / 2
|
||||
|
||||
// If we picked up the blood on this tick in on_step_blood, don't make footprints at the same place
|
||||
if(last_pickup && last_pickup == world.time)
|
||||
return
|
||||
|
||||
// Create new footprints
|
||||
if(half_our_blood >= BLOOD_FOOTPRINTS_MIN)
|
||||
bloody_shoes[last_blood_state] -= half_our_blood
|
||||
update_icon()
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/footprints/FP = new(get_turf(parent_atom))
|
||||
if(!QDELETED(FP)) ///prints merged
|
||||
FP.blood_state = last_blood_state
|
||||
FP.entered_dirs |= wielder.dir
|
||||
add_parent_to_footprint(FP)
|
||||
FP.bloodiness = half_our_blood
|
||||
FP.add_blood_DNA(parent_atom.return_blood_DNA())
|
||||
FP.update_icon()
|
||||
|
||||
|
||||
/*
|
||||
Called when the wielder steps in a pool of blood
|
||||
Used to make the parent item bloody
|
||||
*/
|
||||
/datum/component/bloodysoles/proc/on_step_blood(datum/source, obj/effect/decal/cleanable/pool)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(QDELETED(wielder) || is_obscured())
|
||||
return
|
||||
|
||||
if(istype(pool, /obj/effect/decal/cleanable/blood/footprints) && pool.blood_state == last_blood_state)
|
||||
// The pool we stepped in was actually footprints with the same type
|
||||
var/obj/effect/decal/cleanable/blood/footprints/pool_FP = pool
|
||||
add_parent_to_footprint(pool_FP)
|
||||
if((bloody_shoes[last_blood_state] / 2) >= BLOOD_FOOTPRINTS_MIN && !(pool_FP.entered_dirs & wielder.dir))
|
||||
// If our feet are bloody enough, add an entered dir
|
||||
pool_FP.entered_dirs |= wielder.dir
|
||||
pool_FP.update_icon()
|
||||
|
||||
share_blood(pool)
|
||||
|
||||
last_pickup = world.time
|
||||
|
||||
/*
|
||||
Called when the parent item is being washed
|
||||
*/
|
||||
/datum/component/bloodysoles/proc/on_clean(datum/source, clean_types)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!(clean_types & CLEAN_TYPE_BLOOD) || last_blood_state == BLOOD_STATE_NOT_BLOODY)
|
||||
return
|
||||
|
||||
bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
|
||||
last_blood_state = BLOOD_STATE_NOT_BLOODY
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
|
||||
/*
|
||||
Like its parent but can be applied to carbon mobs instead of clothing items
|
||||
*/
|
||||
|
||||
/datum/component/bloodysoles/feet
|
||||
var/static/mutable_appearance/bloody_feet
|
||||
|
||||
/datum/component/bloodysoles/feet/Initialize()
|
||||
if(!iscarbon(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
parent_atom = parent
|
||||
wielder = parent
|
||||
|
||||
if(!bloody_feet)
|
||||
bloody_feet = mutable_appearance('icons/effects/blood.dmi', "shoeblood", SHOES_LAYER)
|
||||
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
RegisterSignal(parent, COMSIG_STEP_ON_BLOOD, PROC_REF(on_step_blood))
|
||||
RegisterSignal(parent, COMSIG_CARBON_UNEQUIP_SHOECOVER, PROC_REF(unequip_shoecover))
|
||||
RegisterSignal(parent, COMSIG_CARBON_EQUIP_SHOECOVER, PROC_REF(equip_shoecover))
|
||||
|
||||
/datum/component/bloodysoles/feet/update_icon()
|
||||
. = list()
|
||||
if(ishuman(wielder))// Monkeys get no bloody feet :(
|
||||
if(HAS_BLOOD_DNA(wielder))
|
||||
bloody_feet.color = bloody_feet.color = get_blood_dna_color(wielder.return_blood_DNA())
|
||||
. += bloody_feet
|
||||
if(bloody_shoes[BLOOD_STATE_HUMAN] > 0 && !is_obscured())
|
||||
wielder.remove_overlay(SHOES_LAYER)
|
||||
wielder.overlays_standing[SHOES_LAYER] = bloody_feet
|
||||
wielder.apply_overlay(SHOES_LAYER)
|
||||
else
|
||||
wielder.update_inv_shoes()
|
||||
|
||||
/datum/component/bloodysoles/feet/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/FP)
|
||||
if(ismonkey(wielder))
|
||||
FP.species_types |= "monkey"
|
||||
return
|
||||
|
||||
if(!ishuman(wielder))
|
||||
FP.species_types |= "unknown"
|
||||
return
|
||||
|
||||
// Find any leg of our human and add that to the footprint, instead of the default which is to just add the human type
|
||||
for(var/X in wielder.bodyparts)
|
||||
var/obj/item/bodypart/affecting = X
|
||||
if(affecting.body_part == LEG_RIGHT || affecting.body_part == LEG_LEFT)
|
||||
if(!affecting.bodypart_disabled)
|
||||
FP.species_types |= affecting.limb_id
|
||||
break
|
||||
|
||||
|
||||
/datum/component/bloodysoles/feet/is_obscured()
|
||||
if(wielder.shoes)
|
||||
return TRUE
|
||||
return ITEM_SLOT_FEET in wielder.check_obscured_slots(TRUE)
|
||||
|
||||
/datum/component/bloodysoles/feet/on_moved(datum/source, OldLoc, Dir, Forced)
|
||||
if(wielder.num_legs < 2)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/datum/component/bloodysoles/feet/on_step_blood(datum/source, obj/effect/decal/cleanable/pool)
|
||||
if(wielder.num_legs < 2)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/datum/component/bloodysoles/feet/proc/unequip_shoecover(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
update_icon()
|
||||
|
||||
/datum/component/bloodysoles/feet/proc/equip_shoecover(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
update_icon()
|
||||
@@ -1,39 +0,0 @@
|
||||
/datum/component/decal/blood
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_TYPE_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_ATOM_GET_EXAMINE_NAME, PROC_REF(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
|
||||
@@ -10,11 +10,11 @@
|
||||
var/list/scents //assoc dna = carbon mob
|
||||
|
||||
/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
|
||||
scents = scents | F.scents
|
||||
fingerprints = LAZY_LISTS_OR(fingerprints, F.fingerprints)
|
||||
hiddenprints = LAZY_LISTS_OR(hiddenprints, F.hiddenprints)
|
||||
blood_DNA = LAZY_LISTS_OR(blood_DNA, F.blood_DNA)
|
||||
fibers = LAZY_LISTS_OR(fibers, F.fibers)
|
||||
check_blood()
|
||||
check_blood()
|
||||
return ..()
|
||||
|
||||
@@ -48,10 +48,15 @@
|
||||
|
||||
/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/is_bloody(datum/source, clean_types)
|
||||
if(!isitem(parent))
|
||||
return FALSE
|
||||
|
||||
return length(blood_DNA) > 0
|
||||
|
||||
/datum/component/forensics/proc/wipe_fibers()
|
||||
fibers = null
|
||||
return TRUE
|
||||
@@ -193,7 +198,7 @@
|
||||
return
|
||||
if(!length(blood_DNA))
|
||||
return
|
||||
parent.LoadComponent(/datum/component/decal/blood)
|
||||
parent.AddElement(/datum/element/decal/blood, _color = get_blood_dna_color(blood_DNA))
|
||||
|
||||
//yog code for olfaction
|
||||
/datum/component/forensics/proc/wipe_scents()
|
||||
|
||||
@@ -344,7 +344,7 @@
|
||||
var/datum/data/record/M = new()
|
||||
M.fields["id"] = id
|
||||
M.fields["name"] = record_name
|
||||
M.fields["blood_type"] = H.dna.blood_type
|
||||
M.fields["blood_type"] = H.dna.blood_type.name
|
||||
M.fields["b_dna"] = H.dna.unique_enzymes
|
||||
M.fields["mi_dis"] = "None"
|
||||
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
||||
|
||||
@@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
var/unique_enzymes
|
||||
///Stores the hashed values of traits such as skin tones, hair style, and gender
|
||||
var/unique_identity
|
||||
var/blood_type
|
||||
var/datum/blood_type/blood_type
|
||||
///The type of mutant race the player is if applicable (i.e. potato-man)
|
||||
var/datum/species/species = new /datum/species/human
|
||||
///first value is mutant color
|
||||
|
||||
@@ -26,7 +26,15 @@
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
|
||||
if(element_flags & ELEMENT_DETACH_ON_HOST_DESTROY)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(OnTargetDelete), override = TRUE)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(Detach), override = TRUE)
|
||||
|
||||
/*
|
||||
The override = TRUE here is to suppress runtimes happening because of the blood decal element
|
||||
being applied multiple times to a same thing every time there is some bloody attacks,
|
||||
which happens due to ludicrous use of check_blood() in forensics.dm,
|
||||
and how elements system is design and coded; there isn't exactly a not-hacky
|
||||
way to determine whether a datum has this particular element before adding it...
|
||||
*/
|
||||
|
||||
/datum/element/proc/OnTargetDelete(datum/source, force)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
106
code/datums/elements/decals/_decals.dm
Normal file
106
code/datums/elements/decals/_decals.dm
Normal file
@@ -0,0 +1,106 @@
|
||||
/datum/element/decal
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
argument_hash_start_idx = 2
|
||||
/// Whether this decal can be cleaned.
|
||||
var/cleanable
|
||||
/// A description this decal appends to the target's examine message.
|
||||
var/description
|
||||
/// The overlay applied by this decal to the target.
|
||||
var/mutable_appearance/pic
|
||||
/*
|
||||
A short lecture on decal element collision on rotation
|
||||
If a given decal's rotated version is identical to one of existing (at a same target), pre-rotation decals,
|
||||
then the rotated decal won't stay after when the colliding pre-rotation decal gets rotated,
|
||||
resulting in some decal elements colliding into nonexistence. This internal tick-tock prevents
|
||||
such collision by forcing a non-collision.
|
||||
*/
|
||||
var/rotated
|
||||
|
||||
/datum/element/decal/Attach(atom/target, _icon, _icon_state, _dir, _cleanable=FALSE, _color, _layer=TURF_LAYER, _description, _alpha=255, _rotated=FALSE)
|
||||
. = ..()
|
||||
if(!isatom(target) || (pic ? FALSE : !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha, target)))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
description = _description
|
||||
cleanable = _cleanable
|
||||
rotated = _rotated
|
||||
|
||||
RegisterSignal(target,COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_overlay), TRUE)
|
||||
if(isturf(target))
|
||||
RegisterSignal(target,COMSIG_TURF_AFTER_SHUTTLE_MOVE, PROC_REF(shuttlemove_react), TRUE)
|
||||
if(target.flags_1 & INITIALIZED_1)
|
||||
target.update_icon() //could use some queuing here now maybe.
|
||||
else
|
||||
RegisterSignal(target,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE, PROC_REF(late_update_icon), TRUE)
|
||||
if(isitem(target))
|
||||
INVOKE_ASYNC(target, /obj/item/proc/update_slot_icon, TRUE)
|
||||
if(_dir)
|
||||
RegisterSignal(target, COMSIG_ATOM_DIR_CHANGE, PROC_REF(rotate_react),TRUE)
|
||||
if(_cleanable)
|
||||
RegisterSignal(target, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean_react),TRUE)
|
||||
if(_description)
|
||||
RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(examine),TRUE)
|
||||
|
||||
/**
|
||||
* ## generate_appearance
|
||||
*
|
||||
* If the decal was not given an appearance, it will generate one based on the other given arguments.
|
||||
* element won't be compatible if it cannot do either
|
||||
* all args are fed into creating an image, they are byond vars for images you'll recognize in the byond docs
|
||||
* (except source, source is the object whose appearance we're copying.)
|
||||
*/
|
||||
|
||||
/datum/element/decal/proc/generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha, source)
|
||||
if(!_icon || !_icon_state)
|
||||
return FALSE
|
||||
var/temp_image = image(_icon, null, _icon_state, _layer, _dir)
|
||||
pic = new(temp_image)
|
||||
pic.color = _color
|
||||
pic.alpha = _alpha
|
||||
pic.appearance_flags |= RESET_COLOR
|
||||
return TRUE
|
||||
|
||||
/datum/element/decal/Detach(atom/source, force)
|
||||
UnregisterSignal(source, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_TURF_AFTER_SHUTTLE_MOVE))
|
||||
source.update_icon()
|
||||
if(isitem(source))
|
||||
INVOKE_ASYNC(source, /obj/item/proc/update_slot_icon)
|
||||
return ..()
|
||||
|
||||
/datum/element/decal/proc/late_update_icon(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(source && istype(source))
|
||||
source.update_icon()
|
||||
UnregisterSignal(source,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)
|
||||
|
||||
|
||||
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
overlay_list += pic
|
||||
|
||||
/datum/element/decal/proc/shuttlemove_react(datum/source, turf/newT)
|
||||
SIGNAL_HANDLER
|
||||
Detach(source)
|
||||
newT.AddElement(/datum/element/decal, pic.icon, pic.icon_state, pic.dir, cleanable, pic.color, pic.layer, description, pic.alpha, rotated)
|
||||
|
||||
/datum/element/decal/proc/rotate_react(datum/source, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
Detach(source)
|
||||
source.AddElement(/datum/element/decal, pic.icon, pic.icon_state, angle2dir(dir2angle(pic.dir)+dir2angle(new_dir)-dir2angle(old_dir)), cleanable, pic.color, pic.layer, description, pic.alpha, !rotated)
|
||||
|
||||
/datum/element/decal/proc/clean_react(datum/source, clean_types)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(clean_types & cleanable)
|
||||
Detach(source)
|
||||
return TRUE
|
||||
return NONE
|
||||
|
||||
/datum/element/decal/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
examine_list += description
|
||||
44
code/datums/elements/decals/blood.dm
Normal file
44
code/datums/elements/decals/blood.dm
Normal file
@@ -0,0 +1,44 @@
|
||||
/datum/element/decal/blood
|
||||
|
||||
/datum/element/decal/blood/Attach(datum/target, _icon, _icon_state, _dir, _cleanable=CLEAN_TYPE_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
|
||||
if(!isitem(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
. = ..()
|
||||
RegisterSignal(target, COMSIG_ATOM_GET_EXAMINE_NAME, PROC_REF(get_examine_name), TRUE)
|
||||
|
||||
/datum/element/decal/blood/Detach(atom/source, force)
|
||||
UnregisterSignal(source, COMSIG_ATOM_GET_EXAMINE_NAME)
|
||||
return ..()
|
||||
|
||||
/datum/element/decal/blood/generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha, source)
|
||||
var/obj/item/I = source
|
||||
if(!_icon)
|
||||
_icon = 'icons/effects/blood.dmi'
|
||||
if(!_icon_state)
|
||||
_icon_state = "itemblood"
|
||||
if(!_color)
|
||||
_color = COLOR_BLOOD
|
||||
var/item_icon = I.icon
|
||||
var/item_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(item_icon)]-[item_icon_state]"
|
||||
pic = blood_splatter_appearances[index]
|
||||
|
||||
if(!pic)
|
||||
var/icon/blood_splatter_icon = icon(I.icon, I.icon_state, null, 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))
|
||||
pic.color = _color
|
||||
blood_splatter_appearances[index] = pic
|
||||
return TRUE
|
||||
|
||||
/datum/element/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/atom/A = source
|
||||
override[EXAMINE_POSITION_ARTICLE] = A.gender == PLURAL? "some" : "a"
|
||||
override[EXAMINE_POSITION_BEFORE] = " blood-stained "
|
||||
return COMPONENT_EXNAME_CHANGED
|
||||
@@ -732,11 +732,11 @@
|
||||
/mob/living/proc/get_blood_dna_list()
|
||||
if(get_blood_id() != /datum/reagent/blood)
|
||||
return
|
||||
return list("ANIMAL DNA" = "Y-")
|
||||
return list("ANIMAL DNA" = get_blood_type("Y-"))
|
||||
|
||||
///Get the mobs dna list
|
||||
/mob/living/carbon/get_blood_dna_list()
|
||||
if(!(get_blood_id() in list(/datum/reagent/blood, /datum/reagent/toxin/acid))) //polysmorphs have DNA located in literal acid, don't ask me why
|
||||
if(!(get_blood_id() in list(/datum/reagent/blood, /datum/reagent/toxin/acid, /datum/reagent/consumable/liquidelectricity))) //polysmorphs have DNA located in literal acid, don't ask me why
|
||||
return
|
||||
var/list/blood_dna = list()
|
||||
if(dna)
|
||||
@@ -746,10 +746,10 @@
|
||||
return blood_dna
|
||||
|
||||
/mob/living/carbon/alien/get_blood_dna_list()
|
||||
return list("UNKNOWN DNA" = "X*")
|
||||
return list("UNKNOWN DNA" = get_blood_type("X"))
|
||||
|
||||
/mob/living/silicon/get_blood_dna_list()
|
||||
return list("MOTOR OIL" = "SAE 5W-30") //just a little flavor text.
|
||||
return list("SYNTHETIC COOLANT" = get_blood_type("Coolant"))
|
||||
|
||||
///to add a mob's dna info into an object's blood_dna list.
|
||||
/atom/proc/transfer_mob_blood_dna(mob/living/L)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
data["patient"]["stat"] = "Dead"
|
||||
data["patient"]["statstate"] = "bad"
|
||||
data["patient"]["health"] = patient.health
|
||||
data["patient"]["blood_type"] = patient.dna.blood_type
|
||||
data["patient"]["blood_type"] = patient.dna.blood_type.name
|
||||
data["patient"]["maxHealth"] = patient.maxHealth
|
||||
data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
|
||||
data["patient"]["bruteLoss"] = patient.getBruteLoss()
|
||||
|
||||
@@ -1026,7 +1026,7 @@
|
||||
"UE"=scanner_occupant.dna.unique_enzymes,
|
||||
"UF"=scanner_occupant.dna.unique_features,
|
||||
"name"=scanner_occupant.real_name,
|
||||
"blood_type"=scanner_occupant.dna.blood_type)
|
||||
"blood_type"=scanner_occupant.dna.blood_type.name)
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -546,7 +546,8 @@
|
||||
if(3)
|
||||
R.fields["age"] = rand(AGE_MIN, AGE_MAX)
|
||||
if(4)
|
||||
R.fields["blood_type"] = random_blood_type()
|
||||
var/datum/blood_type/blood = random_blood_type()
|
||||
R.fields["blood_type"] = blood.name
|
||||
if(5)
|
||||
R.fields["p_stat"] = pick("*Unconscious*", "Active", "Physically Unfit")
|
||||
if(6)
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
var/bleed_status = "Patient is not currently bleeding."
|
||||
var/blood_status = " Patient either has no blood, or does not require it to function."
|
||||
var/blood_percent = round((altPatient.blood_volume / BLOOD_VOLUME_NORMAL(altPatient))*100)
|
||||
var/blood_type = altPatient.dna.blood_type
|
||||
var/blood_type = altPatient.dna.blood_type.name
|
||||
var/blood_warning = " "
|
||||
|
||||
for(var/thing in altPatient.diseases) //Disease Information
|
||||
|
||||
@@ -129,7 +129,11 @@
|
||||
if(isalien(target))
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target.drop_location(), splatter_dir)
|
||||
else
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir)
|
||||
var/splatter_color = null
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
splatter_color = carbon_target.dna.blood_type.color
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir, splatter_color)
|
||||
|
||||
//organs go everywhere
|
||||
if(target_part && prob(10 * drill_level))
|
||||
|
||||
@@ -83,25 +83,11 @@
|
||||
|
||||
//Add "bloodiness" of this blood's type, to the human's shoes
|
||||
//This is on /cleanable because fuck this ancient mess
|
||||
/obj/effect/decal/cleanable/Crossed(atom/movable/O)
|
||||
..()
|
||||
if(ishuman(O))
|
||||
var/mob/living/carbon/human/H = O
|
||||
if(H.shoes && blood_state && bloodiness && !HAS_TRAIT(H, TRAIT_LIGHT_STEP))
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
if(!istype(S) || !S.can_be_bloody)
|
||||
return
|
||||
var/add_blood = 0
|
||||
if(bloodiness >= BLOOD_GAIN_PER_STEP)
|
||||
add_blood = BLOOD_GAIN_PER_STEP
|
||||
else
|
||||
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())
|
||||
S.blood_state = blood_state
|
||||
update_appearance(UPDATE_ICON)
|
||||
H.update_inv_shoes()
|
||||
/obj/effect/decal/cleanable/proc/on_entered(datum/source, atom/movable/AM)
|
||||
SIGNAL_HANDLER
|
||||
if(iscarbon(AM) && blood_state && bloodiness > 40)
|
||||
SEND_SIGNAL(AM, COMSIG_STEP_ON_BLOOD, src)
|
||||
update_icon()
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
blood_state = BLOOD_STATE_XENO
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/Initialize(mapload)
|
||||
add_blood_DNA(list("UNKNOWN DNA" = get_blood_type("X"))) // Needs to happen before ..()
|
||||
. = ..()
|
||||
add_blood_DNA(list("UNKNOWN DNA" = "X*"))
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xsplatter
|
||||
random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5")
|
||||
@@ -71,10 +71,6 @@
|
||||
icon_state = "xgiblarvatorso"
|
||||
random_icon_states = list("xgiblarvahead", "xgiblarvatorso")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/xtracks
|
||||
/obj/effect/decal/cleanable/xenoblood/xtracks
|
||||
icon_state = "xtracks"
|
||||
random_icon_states = null
|
||||
|
||||
/obj/effect/decal/cleanable/blood/xtracks/Initialize(mapload)
|
||||
. = ..()
|
||||
add_blood_DNA(list("Unknown DNA" = "X*"))
|
||||
|
||||
@@ -1,44 +1,57 @@
|
||||
/obj/effect/decal/cleanable/blood
|
||||
name = "blood"
|
||||
desc = "It's red and gooey. Perhaps it's the chef's cooking?"
|
||||
desc = "It's weird and gooey. Perhaps it's the chef's cooking?"
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "floor1"
|
||||
color = COLOR_BLOOD
|
||||
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
|
||||
blood_state = BLOOD_STATE_HUMAN
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
|
||||
var/dryname = "dried blood" //when the blood lasts long enough, it becomes dry and gets a new name
|
||||
var/drydesc = "Looks like it's been here a while. Eew." //as above
|
||||
var/drytime = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/Initialize(mapload)
|
||||
. = ..()
|
||||
if(bloodiness)
|
||||
start_drying()
|
||||
else
|
||||
dry()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/process()
|
||||
if(world.time > drytime)
|
||||
dry()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/proc/get_timer()
|
||||
drytime = world.time + 3 MINUTES
|
||||
|
||||
/obj/effect/decal/cleanable/blood/proc/start_drying()
|
||||
get_timer()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/proc/dry()
|
||||
if(bloodiness > 20)
|
||||
bloodiness -= BLOOD_AMOUNT_PER_DECAL
|
||||
get_timer()
|
||||
else
|
||||
name = dryname
|
||||
desc = drydesc
|
||||
bloodiness = 0
|
||||
var/temp_color = ReadHSV(RGBtoHSV(color || COLOR_WHITE))
|
||||
color = HSVtoRGB(hsv(temp_color[1], temp_color[2], max(temp_color[3] - 100,min(temp_color[3],10))))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/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
|
||||
C.bloodiness = min((C.bloodiness + bloodiness), BLOOD_AMOUNT_PER_DECAL)
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/whiteblood
|
||||
name = "\"blood\""
|
||||
desc = "It's an unsettling colour. Maybe it's the chef's cooking?"
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "genericsplatter1"
|
||||
random_icon_states = list("genericsplatter1", "genericsplatter2", "genericsplatter3", "genericsplatter4", "genericsplatter5", "genericsplatter6")
|
||||
|
||||
/obj/effect/decal/cleanable/whiteblood/ethereal
|
||||
name = "glowing \"blood\""
|
||||
desc = "It has a fading glow. Surely it's just the chef's cooking?"
|
||||
light_power = 1
|
||||
light_range = 2
|
||||
light_color = "#eef442"
|
||||
|
||||
/obj/effect/decal/cleanable/whiteblood/ethereal/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
add_atom_colour(light_color, FIXED_COLOUR_PRIORITY)
|
||||
addtimer(CALLBACK(src, PROC_REF(Fade)), 1 MINUTES)
|
||||
|
||||
/obj/effect/decal/cleanable/whiteblood/ethereal/proc/Fade()
|
||||
name = "faded \"blood\""
|
||||
light_power = 0
|
||||
light_range = 0
|
||||
update_light()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/old
|
||||
name = "dried blood"
|
||||
desc = "Looks like it's been here a while. Eew."
|
||||
@@ -56,6 +69,8 @@
|
||||
/obj/effect/decal/cleanable/blood/splatter
|
||||
icon_state = "gibbl1"
|
||||
random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
|
||||
dryname = "dried tracks"
|
||||
drydesc = "Some old bloody tracks left by wheels. Machines are evil, perhaps."
|
||||
|
||||
/obj/effect/decal/cleanable/blood/splatter/over_window // special layer/plane set to appear on windows
|
||||
layer = ABOVE_WINDOW_LAYER
|
||||
@@ -69,25 +84,23 @@
|
||||
icon_state = "tracks"
|
||||
random_icon_states = null
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
|
||||
/obj/effect/decal/cleanable/blood/trail_holder //not a child of blood on purpose //nice fucking descriptive comment jackass, fuck you //hello fikou //this is cowbot
|
||||
name = "blood"
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
desc = "Your instincts say you shouldn't be following these."
|
||||
icon_state = null
|
||||
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/proc/Etherealify()
|
||||
/obj/effect/decal/cleanable/blood/proc/Etherealify()
|
||||
name = "glowing \"blood\""
|
||||
light_power = 1
|
||||
light_range = 2
|
||||
light_range = 1
|
||||
light_color = "#eef442"
|
||||
update_light()
|
||||
add_atom_colour(light_color, FIXED_COLOUR_PRIORITY)
|
||||
addtimer(CALLBACK(src, PROC_REF(Fade)), 1 MINUTES)
|
||||
addtimer(CALLBACK(src, PROC_REF(Fade)), 3 MINUTES)
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/proc/Fade()
|
||||
/obj/effect/decal/cleanable/blood/proc/Fade()
|
||||
name = "faded \"blood\""
|
||||
light_power = 0
|
||||
light_range = 0
|
||||
@@ -102,21 +115,17 @@
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
|
||||
mergeable_decal = FALSE
|
||||
|
||||
var/already_rotting = FALSE
|
||||
dryname = "rotting gibs"
|
||||
drydesc = "They look bloody and gruesome while some terrible smell fills the air."
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
reagents.add_reagent(/datum/reagent/liquidgibs, 5)
|
||||
if(already_rotting)
|
||||
start_rotting(rename=FALSE)
|
||||
else
|
||||
addtimer(CALLBACK(src, PROC_REF(start_rotting)), 2 MINUTES)
|
||||
var/mutable_appearance/gib_overlay = mutable_appearance(icon, "[icon_state]-overlay", appearance_flags = RESET_COLOR)
|
||||
add_overlay(gib_overlay)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/proc/start_rotting(rename=TRUE)
|
||||
if(rename)
|
||||
name = "rotting [initial(name)]"
|
||||
desc += " They smell terrible."
|
||||
AddComponent(/datum/component/rot/gibs)
|
||||
/obj/effect/decal/cleanable/blood/gibs/dry()
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
|
||||
return
|
||||
@@ -131,11 +140,13 @@
|
||||
var/list/diseases = list()
|
||||
SEND_SIGNAL(src, COMSIG_GIBS_STREAK, directions, diseases)
|
||||
var/direction = pick(directions)
|
||||
for(var/i in 0 to pick(0, 200; 1, 150; 2, 50))
|
||||
for(var/i in 0 to pick(0, 1, 2))
|
||||
if (!mapload)
|
||||
sleep(0.2 SECONDS)
|
||||
if(i > 0)
|
||||
new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
|
||||
var/obj/effect/decal/cleanable/blood/splatter/splat = new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
|
||||
if(!QDELETED(splat) && HAS_BLOOD_DNA(src))
|
||||
splat.add_blood_DNA(src.return_blood_DNA())
|
||||
if(!step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
@@ -166,13 +177,14 @@
|
||||
/obj/effect/decal/cleanable/blood/gibs/old
|
||||
name = "old rotting gibs"
|
||||
desc = "Space Jesus, why didn't anyone clean this up? They smell terrible."
|
||||
icon_state = "gib1-old"
|
||||
bloodiness = 0
|
||||
already_rotting = TRUE
|
||||
dryname = "old rotting gibs"
|
||||
drydesc = "Space Jesus, why didn't anyone clean this up? They smell terrible."
|
||||
|
||||
/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" = random_blood_type()))
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip
|
||||
@@ -182,6 +194,8 @@
|
||||
random_icon_states = list("drip1","drip2","drip3","drip4","drip5")
|
||||
bloodiness = 0
|
||||
var/drips = 1
|
||||
dryname = "drips of blood"
|
||||
drydesc = "It's red."
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
@@ -198,32 +212,13 @@
|
||||
blood_state = BLOOD_STATE_HUMAN //the icon state to load images from
|
||||
var/entered_dirs = 0
|
||||
var/exited_dirs = 0
|
||||
/// List of shoe or other clothing that covers feet types that have made footprints here.
|
||||
var/list/shoe_types = list()
|
||||
/// List of species that have made footprints here.
|
||||
var/list/species_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])
|
||||
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))
|
||||
entered_dirs |= H.dir
|
||||
update_appearance(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 && istype(S) && S.bloody_shoes[blood_state])
|
||||
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
|
||||
shoe_types |= S.type
|
||||
if (!(exited_dirs & H.dir))
|
||||
exited_dirs |= H.dir
|
||||
update_appearance(UPDATE_ICON)
|
||||
|
||||
dryname = "dried footprints"
|
||||
drydesc = "HMM... SOMEONE WAS HERE!"
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/update_overlays()
|
||||
. = ..()
|
||||
@@ -240,21 +235,32 @@
|
||||
GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]2", dir = Ddir)
|
||||
. += bloodstep_overlay
|
||||
|
||||
alpha = BLOODY_FOOTPRINT_BASE_ALPHA + bloodiness
|
||||
alpha = min(BLOODY_FOOTPRINT_BASE_ALPHA + (255 - BLOODY_FOOTPRINT_BASE_ALPHA) * bloodiness / (BLOOD_ITEM_MAX / 2), 255)
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/examine(mob/user)
|
||||
. = ..()
|
||||
if(shoe_types.len)
|
||||
. += "You recognise the footprints as belonging to:\n"
|
||||
for(var/shoe in shoe_types)
|
||||
var/obj/item/clothing/shoes/S = shoe
|
||||
. += "[icon2html(initial(S.icon), user)] Some <B>[initial(S.name)]</B>.\n"
|
||||
if((shoe_types.len + species_types.len) > 0)
|
||||
. += "You recognise the footprints as belonging to:"
|
||||
for(var/sole in shoe_types)
|
||||
var/obj/item/clothing/item = sole
|
||||
var/article = initial(item.gender) == PLURAL ? "Some" : "A"
|
||||
. += "[icon2html(initial(item.icon), user, initial(item.icon_state))] [article] <B>[initial(item.name)]</B>."
|
||||
for(var/species in species_types)
|
||||
// god help me
|
||||
if(species == "unknown")
|
||||
. += "Some <B>feet</B>."
|
||||
else if(species == "monkey")
|
||||
. += "[icon2html('icons/mob/monkey.dmi', user, "monkey1")] Some <B>monkey feet</B>."
|
||||
else if(species == "human")
|
||||
. += "[icon2html('icons/mob/human_parts.dmi', user, "default_human_l_leg")] Some <B>human feet</B>."
|
||||
else
|
||||
. += "[icon2html('icons/mob/human_parts.dmi', user, "[species]_l_leg")] Some <B>[species] feet</B>."
|
||||
|
||||
/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
|
||||
..()
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/can_bloodcrawl_in()
|
||||
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
|
||||
@@ -277,9 +283,11 @@
|
||||
/// Insurance so that we don't keep moving once we hit a stoppoint
|
||||
var/hit_endpoint = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/hitsplatter/Initialize(mapload, splatter_strength)
|
||||
/obj/effect/decal/cleanable/blood/hitsplatter/Initialize(mapload, splatter_strength, set_color)
|
||||
. = ..()
|
||||
prev_loc = loc //Just so we are sure prev_loc exists
|
||||
if(set_color)
|
||||
color = set_color
|
||||
if(splatter_strength)
|
||||
src.splatter_strength = splatter_strength
|
||||
|
||||
@@ -343,6 +351,7 @@
|
||||
land_on_window(bumped_atom)
|
||||
else
|
||||
var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new(prev_loc)
|
||||
final_splatter.color = color
|
||||
final_splatter.pixel_x = (dir == EAST ? 32 : (dir == WEST ? -32 : 0))
|
||||
final_splatter.pixel_y = (dir == NORTH ? 32 : (dir == SOUTH ? -32 : 0))
|
||||
else // This will only happen if prev_loc is not even a turf, which is highly unlikely.
|
||||
@@ -354,6 +363,7 @@
|
||||
if(!the_window.fulltile)
|
||||
return
|
||||
var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new
|
||||
final_splatter.color = color
|
||||
final_splatter.forceMove(the_window)
|
||||
the_window.vis_contents += final_splatter
|
||||
the_window.bloodied = TRUE
|
||||
|
||||
@@ -34,12 +34,29 @@
|
||||
/obj/effect/turf_decal
|
||||
icon = 'icons/turf/decals.dmi'
|
||||
icon_state = "warningline"
|
||||
plane = FLOOR_PLANE
|
||||
layer = TURF_DECAL_LAYER
|
||||
var/detail_overlay
|
||||
var/detail_color
|
||||
|
||||
// This is with the intent of optimizing mapload
|
||||
// See spawners for more details since we use the same pattern
|
||||
// Basically rather then creating and deleting ourselves, why not just do the bare minimum?
|
||||
/obj/effect/turf_decal/Initialize(mapload)
|
||||
. = ..()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
if(flags_1 & INITIALIZED_1)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
flags_1 |= INITIALIZED_1
|
||||
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.AddComponent(/datum/component/decal, icon, icon_state, dir, FALSE, color, null, null, alpha)
|
||||
T.AddElement(/datum/element/decal, icon, icon_state, dir, FALSE, color, null, null, alpha, FALSE)
|
||||
if(detail_overlay)
|
||||
T.AddElement(/datum/element/decal, icon, detail_overlay, dir, FALSE, detail_color, null, null, alpha, appearance_flags)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/turf_decal/Destroy(force)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
moveToNullspace()
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
duration = 0.5 SECONDS
|
||||
randomdir = FALSE
|
||||
layer = BELOW_MOB_LAYER
|
||||
color = COLOR_BLOOD
|
||||
var/splatter_type = "splatter"
|
||||
|
||||
/obj/effect_temp_visual/dir_setting/tentacle
|
||||
@@ -11,12 +12,14 @@
|
||||
icon_state = "Goliath_tentacle_spawn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir)
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir, set_color)
|
||||
if(set_dir in GLOB.diagonals)
|
||||
icon_state = "[splatter_type][pick(1, 2, 6)]"
|
||||
else
|
||||
icon_state = "[splatter_type][pick(3, 4, 5)]"
|
||||
. = ..()
|
||||
if(set_color)
|
||||
color = set_color
|
||||
var/target_pixel_x = 0
|
||||
var/target_pixel_y = 0
|
||||
switch(set_dir)
|
||||
@@ -47,6 +50,7 @@
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter
|
||||
splatter_type = "xsplatter"
|
||||
color = null
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/genericsplatter
|
||||
splatter_type = "genericsplatter"
|
||||
|
||||
@@ -427,7 +427,7 @@ GENE SCANNER
|
||||
if(H.is_bleeding())
|
||||
combined_msg += span_danger("Subject is losing blood at a rate of [H.get_total_bleed_rate() * H.physiology?.bleed_mod] cl per process!")
|
||||
var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL(C))*100)
|
||||
var/blood_type = C.dna.blood_type
|
||||
var/blood_type = C.dna.blood_type.name
|
||||
if(blood_id != /datum/reagent/blood)//special blood substance
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
|
||||
if(R)
|
||||
|
||||
@@ -662,3 +662,13 @@ GLOBAL_LIST_EMPTY(station_turfs)
|
||||
/// Called when attempting to set fire to a turf
|
||||
/turf/proc/IgniteTurf(power, fire_color="red")
|
||||
return
|
||||
|
||||
/turf/proc/on_turf_saved()
|
||||
// This is all we can do. I'm sorry mappers, but there's no way to get any more details.
|
||||
var/first = TRUE
|
||||
for(var/datum/element/decal/decal as anything in GetComponents(/datum/element/decal))
|
||||
if(!first)
|
||||
. += ",\n"
|
||||
. += "[/obj/effect/turf_decal]{\n\ticon = '[decal.pic.icon]';\n\ticon_state = \"[decal.pic.icon_state]\";\n\tdir = [decal.pic.dir];\n\tcolor = \"[decal.pic.color]\"\n\t}"
|
||||
first = FALSE
|
||||
return
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
dat += "<table cellspacing=5><tr><th>Name</th><th>DNA</th><th>Blood Type</th></tr>"
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
if(H.ckey)
|
||||
dat += "<tr><td>[H]</td><td>[H.dna.unique_enzymes]</td><td>[H.dna.blood_type]</td></tr>"
|
||||
dat += "<tr><td>[H]</td><td>[H.dna.unique_enzymes]</td><td>[H.dna.blood_type.name]</td></tr>"
|
||||
dat += "</table>"
|
||||
dat += "</BODY></HTML>"
|
||||
mob_user << browse(dat, "window=DNA;size=440x410")
|
||||
|
||||
@@ -763,12 +763,8 @@
|
||||
temp += max((B.bloodiness**2)/800,1)
|
||||
new /obj/effect/temp_visual/cult/turf/floor(get_turf(B))
|
||||
qdel(B)
|
||||
for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2))
|
||||
for(var/obj/effect/decal/cleanable/blood/trail_holder/TH in view(T, 2))
|
||||
qdel(TH)
|
||||
var/obj/item/clothing/shoes/shoecheck = user.shoes
|
||||
if(shoecheck && istype(shoecheck) && shoecheck.bloody_shoes[/datum/reagent/blood])
|
||||
temp += shoecheck.bloody_shoes[/datum/reagent/blood]/20
|
||||
shoecheck.bloody_shoes[/datum/reagent/blood] = 0
|
||||
if(temp)
|
||||
user.Beam(T,icon_state="drainbeam",time=15)
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(user))
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
var/clothing_flags = NONE
|
||||
|
||||
var/can_be_bloody = TRUE
|
||||
|
||||
/// What items can be consumed to repair this clothing (must by an /obj/item/stack)
|
||||
var/repairable_by = /obj/item/stack/sheet/cloth
|
||||
|
||||
@@ -61,6 +63,8 @@
|
||||
. = ..()
|
||||
if(ispath(pocket_storage_component_path))
|
||||
LoadComponent(pocket_storage_component_path)
|
||||
if(can_be_bloody && ((body_parts_covered & FEET) || (flags_inv & HIDESHOES)))
|
||||
LoadComponent(/datum/component/bloodysoles)
|
||||
|
||||
/obj/item/clothing/MouseDrop(atom/over_object)
|
||||
. = ..()
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands")
|
||||
var/mutable_appearance/bloody_hands = mutable_appearance('icons/effects/blood.dmi', "bloodyhands")
|
||||
bloody_hands.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_hands
|
||||
|
||||
/obj/item/clothing/gloves/update_clothes_damaged_state()
|
||||
..()
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood")
|
||||
|
||||
var/mutable_appearance/bloody_helmet = mutable_appearance('icons/effects/blood.dmi', "helmetblood")
|
||||
bloody_helmet.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_helmet
|
||||
|
||||
/obj/item/clothing/head/update_clothes_damaged_state()
|
||||
..()
|
||||
if(ismob(loc))
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "maskblood")
|
||||
var/mutable_appearance/bloody_mask = mutable_appearance('icons/effects/blood.dmi', "maskblood")
|
||||
bloody_mask.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_mask
|
||||
|
||||
/obj/item/clothing/mask/update_clothes_damaged_state()
|
||||
..()
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "maskblood")
|
||||
var/mutable_appearance/bloody_mask = mutable_appearance('icons/effects/blood.dmi', "maskblood")
|
||||
bloody_mask.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_mask
|
||||
|
||||
/obj/item/clothing/neck/tie
|
||||
name = "tie"
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
slot_flags = ITEM_SLOT_FEET
|
||||
|
||||
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/offset = 0
|
||||
var/equipped_before_drop = FALSE
|
||||
var/can_be_bloody = TRUE
|
||||
var/xenoshoe = NO_DIGIT // Check for if shoes can be worn by straight legs (NO_DIGIT) which is default, both / hybrid (EITHER_STYLE), or digitigrade only (YES_DIGIT)
|
||||
var/mutantrace_variation = NO_MUTANTRACE_VARIATION // Assigns shoes to have variations for if worn clothing doesn't enforce straight legs (such as cursed jumpskirts)
|
||||
var/adjusted = NORMAL_STYLE // Default needed to make the above work
|
||||
@@ -41,16 +39,13 @@
|
||||
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE)
|
||||
. = list()
|
||||
if(!isinhands)
|
||||
var/bloody = FALSE
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
bloody = TRUE
|
||||
else
|
||||
bloody = bloody_shoes[BLOOD_STATE_HUMAN]
|
||||
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
|
||||
if(bloody)
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "shoeblood")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
var/mutable_appearance/bloody_shoes
|
||||
bloody_shoes = mutable_appearance('icons/effects/blood.dmi', "shoeblood")
|
||||
bloody_shoes.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_shoes
|
||||
|
||||
/obj/item/clothing/shoes/equipped(mob/user, slot)
|
||||
if(adjusted)
|
||||
@@ -89,16 +84,5 @@
|
||||
var/mob/M = loc
|
||||
M.update_inv_shoes()
|
||||
|
||||
/obj/item/clothing/shoes/wash(clean_types)
|
||||
. = ..()
|
||||
if(!(clean_types & CLEAN_TYPE_BLOOD) || blood_state == BLOOD_STATE_NOT_BLOODY)
|
||||
return
|
||||
bloody_shoes = list(BLOOD_STATE_HUMAN = 0,BLOOD_STATE_XENO = 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()
|
||||
return TRUE
|
||||
|
||||
/obj/item/proc/negates_gravity()
|
||||
return FALSE
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
. = list()
|
||||
if(!isinhands)
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood")
|
||||
var/mutable_appearance/bloody_armor = mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood")
|
||||
bloody_armor.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_armor
|
||||
var/mob/living/carbon/human/M = loc
|
||||
if(ishuman(M) && M.w_uniform)
|
||||
var/obj/item/clothing/under/U = M.w_uniform
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
if(damaged_clothes)
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
|
||||
if(HAS_BLOOD_DNA(src))
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood")
|
||||
var/mutable_appearance/bloody_uniform = mutable_appearance('icons/effects/blood.dmi', "uniformblood")
|
||||
bloody_uniform.color = get_blood_dna_color(return_blood_DNA())
|
||||
. += bloody_uniform
|
||||
if(accessory_overlay)
|
||||
. += accessory_overlay
|
||||
|
||||
|
||||
@@ -77,8 +77,9 @@
|
||||
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
|
||||
if(!QDELETED(B))
|
||||
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)
|
||||
@@ -96,6 +97,11 @@
|
||||
update_inv_gloves() //handles bloody hands overlays and updating
|
||||
return TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/add_blood_DNA(list/blood_dna, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
if(blood_dna)
|
||||
color = get_blood_dna_color(blood_dna)
|
||||
|
||||
/atom/proc/transfer_fingerprints_to(atom/A)
|
||||
A.add_fingerprint_list(return_fingerprints())
|
||||
A.add_hiddenprint_list(return_hiddenprints())
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
|
||||
var/list/data = null
|
||||
if(rid == /datum/reagent/blood) // Hack to make blood in plants always O-
|
||||
data = list("blood_type" = "O-")
|
||||
data = list("blood_type" = get_blood_type("O-"))
|
||||
if(rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin)
|
||||
// apple tastes of apple.
|
||||
if(istype(T, /obj/item/reagent_containers/food/snacks/grown))
|
||||
|
||||
@@ -1376,7 +1376,7 @@ GLOBAL_LIST_EMPTY(aide_list)
|
||||
if(target == user)
|
||||
continue
|
||||
for(var/obj/effect/decal/cleanable/decal in range(0, target))
|
||||
if(istype(decal, /obj/effect/decal/cleanable/blood )|| istype(decal, /obj/effect/decal/cleanable/trail_holder))
|
||||
if(istype(decal, /obj/effect/decal/cleanable/blood )|| istype(decal, /obj/effect/decal/cleanable/blood/trail_holder))
|
||||
valid_reaching = TRUE
|
||||
target.apply_status_effect(STATUS_EFFECT_KNUCKLED)
|
||||
if(!valid_reaching)
|
||||
|
||||
@@ -238,7 +238,8 @@
|
||||
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)))
|
||||
var/datum/blood_type/blood_type = blood_data["blood_type"]
|
||||
if(!(blood_type.type in C.dna.blood_type.compatible_types))
|
||||
C.reagents.add_reagent(/datum/reagent/toxin, amount * 0.5)
|
||||
return TRUE
|
||||
|
||||
@@ -317,47 +318,25 @@
|
||||
return
|
||||
return /datum/reagent/blood
|
||||
|
||||
// This is has more potential uses, and is probably faster than the old proc.
|
||||
/proc/get_safe_blood(bloodtype)
|
||||
. = list()
|
||||
if(!bloodtype)
|
||||
return
|
||||
/proc/random_blood_type()
|
||||
return get_blood_type(pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+"))
|
||||
|
||||
var/static/list/bloodtypes_safe = list(
|
||||
"A-" = list("A-", "O-", "U"),
|
||||
"A+" = list("A-", "A+", "O-", "O+", "U"),
|
||||
"B-" = list("B-", "O-", "U"),
|
||||
"B+" = list("B-", "B+", "O-", "O+", "U"),
|
||||
"AB-" = list("A-", "B-", "O-", "AB-", "U"),
|
||||
"AB+" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "U"),
|
||||
"O-" = list("O-", "U"),
|
||||
"O+" = list("O-", "O+", "U"),
|
||||
"L" = list("L", "U"),
|
||||
"U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U") //literally universal
|
||||
)
|
||||
/proc/get_blood_type(type)
|
||||
return GLOB.blood_types[type]
|
||||
|
||||
var/safe = bloodtypes_safe[bloodtype]
|
||||
if(safe)
|
||||
. = safe
|
||||
/proc/get_blood_dna_color(list/blood_dna)
|
||||
if(!blood_dna)
|
||||
return null
|
||||
var/blood_print = blood_dna[length(blood_dna)]
|
||||
var/datum/blood_type/blood_type = blood_dna[blood_print]
|
||||
if(!blood_type)
|
||||
return null
|
||||
return blood_type.color
|
||||
|
||||
//to add a splatter of blood or other mob liquid.
|
||||
/mob/living/proc/add_splatter_floor(turf/T, small_drip)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
if(ispolysmorph(src)) //polysmorphs bleed green blood
|
||||
var/obj/effect/decal/cleanable/xenoblood/B = locate() in T.contents
|
||||
if(!B)
|
||||
B = new(T)
|
||||
B.transfer_mob_blood_dna(src)
|
||||
return
|
||||
if(isethereal(src))
|
||||
var/obj/effect/decal/cleanable/whiteblood/ethereal/B = locate() in T.contents
|
||||
if(!B)
|
||||
B = new(T)
|
||||
B.transfer_mob_blood_dna(src)
|
||||
return
|
||||
if(get_blood_id() != /datum/reagent/blood)
|
||||
return
|
||||
var/list/temp_blood_DNA
|
||||
if(small_drip)
|
||||
// Only a certain number of drips (or one large splatter) can be on a given turf.
|
||||
@@ -367,6 +346,8 @@
|
||||
drop.drips++
|
||||
drop.add_overlay(pick(drop.random_icon_states))
|
||||
drop.transfer_mob_blood_dna(src)
|
||||
if(isethereal(src))
|
||||
drop.Etherealify()
|
||||
return
|
||||
else
|
||||
temp_blood_DNA = drop.return_blood_DNA() //we transfer the dna from the drip to the splatter
|
||||
@@ -374,17 +355,20 @@
|
||||
else
|
||||
drop = new(T, get_static_viruses())
|
||||
drop.transfer_mob_blood_dna(src)
|
||||
if(isethereal(src))
|
||||
drop.Etherealify()
|
||||
return
|
||||
|
||||
// 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.bloodiness = min((B.bloodiness + BLOOD_AMOUNT_PER_DECAL), BLOOD_POOL_MAX)
|
||||
B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
|
||||
if(temp_blood_DNA)
|
||||
B.add_blood_DNA(temp_blood_DNA)
|
||||
if(isethereal(src))
|
||||
B.Etherealify()
|
||||
|
||||
/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
|
||||
if(!(NOBLOOD in dna.species.species_traits))
|
||||
|
||||
@@ -1272,7 +1272,15 @@
|
||||
/mob/living/carbon/proc/spray_blood(splatter_direction, splatter_strength = 3)
|
||||
if(!isturf(loc))
|
||||
return
|
||||
var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc)
|
||||
var/splatter_color = null
|
||||
if(dna?.blood_type)
|
||||
splatter_color = dna.blood_type.color
|
||||
else
|
||||
var/blood_id = get_blood_id()
|
||||
if(blood_id != /datum/reagent/blood)//special blood substance
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
|
||||
splatter_color = R.color
|
||||
var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc, splatter_strength, splatter_color)
|
||||
our_splatter.add_blood_DNA(return_blood_DNA())
|
||||
our_splatter.blood_dna_info = get_blood_dna_list()
|
||||
var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength)
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
if(with_bodyparts)
|
||||
switch(dna.species.species_gibs)
|
||||
if("human")
|
||||
new /obj/effect/gibspawner/human(get_turf(src), dna, get_static_viruses())
|
||||
new /obj/effect/gibspawner/human(get_turf(src), src, get_static_viruses())
|
||||
if("robotic")
|
||||
new /obj/effect/gibspawner/robot(get_turf(src))
|
||||
else
|
||||
switch(dna.species.species_gibs)
|
||||
if("human")
|
||||
new /obj/effect/gibspawner/human(get_turf(src), dna, get_static_viruses())
|
||||
new /obj/effect/gibspawner/human(get_turf(src), src, get_static_viruses())
|
||||
if("robotic")
|
||||
new /obj/effect/gibspawner/robot(get_turf(src))
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(clean_face))
|
||||
AddComponent(/datum/component/personal_crafting)
|
||||
AddElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6)
|
||||
AddComponent(/datum/component/bloodysoles/feet)
|
||||
|
||||
/mob/living/carbon/human/proc/setup_human_dna()
|
||||
//initialize dna. for spawned humans; overwritten by other code
|
||||
|
||||
@@ -198,8 +198,6 @@
|
||||
if(I.force && I.damtype != STAMINA && affecting.status == BODYPART_ROBOTIC) // Bodpart_robotic sparks when hit, but only when it does real damage
|
||||
if(I.force >= 5)
|
||||
do_sparks(1, FALSE, loc)
|
||||
if(prob(25))
|
||||
new /obj/effect/decal/cleanable/oil(loc)
|
||||
|
||||
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
|
||||
|
||||
@@ -59,32 +59,10 @@
|
||||
/mob/living/carbon/human/Move(NewLoc, direct)
|
||||
. = ..()
|
||||
|
||||
if(shoes)
|
||||
if(mobility_flags & MOBILITY_STAND)
|
||||
if(loc == NewLoc)
|
||||
if(!has_gravity(loc))
|
||||
return
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
|
||||
//Bloody footprints
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(S) && S.bloody_shoes && S.bloody_shoes[S.blood_state])
|
||||
for(var/obj/effect/decal/cleanable/blood/footprints/oldFP in T)
|
||||
if (oldFP.blood_state == S.blood_state)
|
||||
return
|
||||
//No oldFP or they're all a different kind of blood
|
||||
S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
if (S.bloody_shoes[S.blood_state] > BLOOD_LOSS_IN_SPREAD)
|
||||
var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
|
||||
FP.blood_state = S.blood_state
|
||||
FP.entered_dirs |= dir
|
||||
FP.bloodiness = S.bloody_shoes[S.blood_state] - BLOOD_LOSS_IN_SPREAD
|
||||
FP.add_blood_DNA(S.return_blood_DNA())
|
||||
FP.update_appearance(UPDATE_ICON)
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
if(istype(S))
|
||||
S.step_action()
|
||||
if(shoes && (mobility_flags & MOBILITY_STAND) && loc == NewLoc && has_gravity(loc))
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
S.step_action()
|
||||
|
||||
if(wear_neck)
|
||||
if(mobility_flags & MOBILITY_STAND)
|
||||
if(loc == NewLoc)
|
||||
|
||||
@@ -169,6 +169,10 @@
|
||||
if(!not_handled)
|
||||
I.equipped(src, slot, initial)
|
||||
|
||||
// Send a signal for when we equip an item that used to cover our feet/shoes. Used for bloody feet
|
||||
if((I.body_parts_covered & FEET) || (I.flags_inv | I.transparent_protection) & HIDESHOES)
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_SHOECOVER, I, slot, initial)
|
||||
|
||||
return not_handled //For future deeper overrides
|
||||
|
||||
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
|
||||
@@ -251,6 +255,10 @@
|
||||
if(!QDELETED(src))
|
||||
update_inv_s_store()
|
||||
|
||||
// Send a signal for when we unequip an item that used to cover our feet/shoes. Used for bloody feet
|
||||
if((I.body_parts_covered & FEET) || (I.flags_inv | I.transparent_protection) & HIDESHOES)
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_UNEQUIP_SHOECOVER, I, force, newloc, no_move, invdrop, silent)
|
||||
|
||||
/mob/living/carbon/human/toggle_internals(obj/item/tank, is_external = FALSE)
|
||||
// Just close the tank if it's the one the mob already has open.
|
||||
var/obj/item/existing_tank = is_external ? external : internal
|
||||
|
||||
@@ -204,6 +204,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
//Should we preload this species's organs?
|
||||
var/preload = TRUE
|
||||
|
||||
///Does our species have colors for its' damage overlays?
|
||||
var/use_damage_color = TRUE
|
||||
|
||||
///////////
|
||||
// PROCS //
|
||||
///////////
|
||||
@@ -435,7 +438,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
regenerate_organs(C,old_species)
|
||||
|
||||
if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype)
|
||||
C.dna.blood_type = exotic_bloodtype
|
||||
C.dna.blood_type = get_blood_type(exotic_bloodtype)
|
||||
|
||||
if(old_species.mutanthands)
|
||||
for(var/obj/item/I in C.held_items)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
mutantheart = /obj/item/organ/heart/ethereal
|
||||
mutanteyes = /obj/item/organ/eyes/ethereal
|
||||
exotic_blood = /datum/reagent/consumable/liquidelectricity //Liquid Electricity. fuck you think of something better gamer
|
||||
exotic_bloodtype = "E" //this isn't used for anything other than bloodsplatter colours
|
||||
siemens_coeff = 0.5 //They thrive on energy
|
||||
brutemod = 1.25 //Don't rupture their membranes
|
||||
burnmod = 0.8 //Bodies are resilient to heat and energy
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
inherent_traits = list(TRAIT_ACIDBLOOD, TRAIT_SKINNY)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
exotic_blood = /datum/reagent/toxin/acid //Hell yeah sulphuric acid blood
|
||||
exotic_bloodtype = "X" //this isn't used for anything other than bloodsplatter colours
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
|
||||
liked_food = GROSS | MEAT | MICE
|
||||
disliked_food = GRAIN | DAIRY | VEGETABLES | FRUIT
|
||||
|
||||
@@ -182,6 +182,7 @@ There are several things that need to be remembered:
|
||||
bloody_overlay.icon_state = "bloodyhands_left"
|
||||
else if(has_right_hand(FALSE))
|
||||
bloody_overlay.icon_state = "bloodyhands_right"
|
||||
bloody_overlay.color = get_blood_dna_color(return_blood_DNA())
|
||||
|
||||
overlays_standing[GLOVES_LAYER] = bloody_overlay
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
create_dna(src)
|
||||
dna.initialize_dna(random_blood_type())
|
||||
AddComponent(/datum/component/bloodysoles/feet)
|
||||
|
||||
/mob/living/carbon/monkey/Destroy()
|
||||
SSmobs.cubemonkeys -= src
|
||||
|
||||
@@ -114,7 +114,10 @@
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.dmg_overlay_type)
|
||||
if(BP.brutestate)
|
||||
damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0") //we're adding icon_states of the base image as overlays
|
||||
var/image/brute_overlay = image('icons/mob/dam_mob.dmi', "[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0")
|
||||
if(BP.use_damage_color)
|
||||
brute_overlay.color = BP.damage_color
|
||||
damage_overlay.add_overlay(brute_overlay)
|
||||
if(BP.burnstate)
|
||||
damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]")
|
||||
|
||||
|
||||
@@ -669,7 +669,7 @@
|
||||
/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction)
|
||||
if(!has_gravity() || !isturf(start) || !blood_volume)
|
||||
return
|
||||
var/blood_exists = locate(/obj/effect/decal/cleanable/trail_holder) in start
|
||||
var/blood_exists = locate(/obj/effect/decal/cleanable/blood/trail_holder) in start
|
||||
|
||||
var/trail_type = getTrail()
|
||||
if(!trail_type)
|
||||
@@ -691,15 +691,15 @@
|
||||
if((newdir in GLOB.cardinals) && (prob(50)))
|
||||
newdir = turn(get_dir(target_turf, start), 180)
|
||||
if(!blood_exists)
|
||||
var/obj/effect/decal/cleanable/trail_holder/TH = new(start, get_static_viruses())
|
||||
if(isethereal(src))//ethereal blood glows
|
||||
TH.Etherealify()
|
||||
new /obj/effect/decal/cleanable/blood/trail_holder(start, get_static_viruses())
|
||||
|
||||
for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
|
||||
for(var/obj/effect/decal/cleanable/blood/trail_holder/TH in start)
|
||||
if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
|
||||
TH.existing_dirs += newdir
|
||||
TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
|
||||
TH.transfer_mob_blood_dna(src)
|
||||
if(isethereal(src))//ethereal blood glows
|
||||
TH.Etherealify()
|
||||
|
||||
/mob/living/carbon/human/makeTrail(turf/T)
|
||||
if((NOBLOOD in dna.species.species_traits) || !is_bleeding() || bleedsuppress)
|
||||
@@ -720,16 +720,8 @@
|
||||
|
||||
/mob/living/proc/getTrail()
|
||||
if(getBruteLoss() < 300)
|
||||
if(ispolysmorph(src))
|
||||
return pick("xltrails_1", "xltrails_2")
|
||||
if(isethereal(src))
|
||||
return pick("wltrails_1", "wltrails_2")
|
||||
return pick("ltrails_1", "ltrails_2")
|
||||
else
|
||||
if(ispolysmorph(src))
|
||||
return pick("xttrails_1", "xttrails_2")
|
||||
if(isethereal(src))
|
||||
return pick("wttrails_1", "wttrails_2")
|
||||
return pick("trails_1", "trails_2")
|
||||
|
||||
/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
if(blood)
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood
|
||||
target_types += /obj/effect/decal/cleanable/blood
|
||||
target_types += /obj/effect/decal/cleanable/trail_holder
|
||||
target_types += /obj/effect/decal/cleanable/blood/trail_holder
|
||||
|
||||
if(pests)
|
||||
target_types += /mob/living/simple_animal/cockroach
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
Changing this around would probably require a good look-over the pre-existing code.
|
||||
*/
|
||||
|
||||
///How many legs does this mob currently have. Should only be changed through set_num_legs()
|
||||
var/num_legs = 2
|
||||
|
||||
/// The zone this mob is currently targeting
|
||||
var/zone_selected = BODY_ZONE_CHEST
|
||||
|
||||
|
||||
@@ -242,8 +242,11 @@
|
||||
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)
|
||||
var/splatter_color = null
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/carbon_target = L
|
||||
splatter_color = carbon_target.dna.blood_type.color
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, splatter_color)
|
||||
if(prob(33))
|
||||
L.add_splatter_floor(target_loca)
|
||||
else if(impact_effect_type && !hitscan)
|
||||
|
||||
@@ -761,9 +761,10 @@
|
||||
if(reac_volume < 3)
|
||||
return
|
||||
|
||||
var/obj/effect/decal/cleanable/whiteblood/ethereal/B = locate() in T //find some blood here
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in T
|
||||
if(!B)
|
||||
B = new(T)
|
||||
B = new /obj/effect/decal/cleanable/blood/splatter(T)
|
||||
B.Etherealify()
|
||||
|
||||
/datum/reagent/consumable/liquidelectricity/on_mob_life(mob/living/carbon/M)
|
||||
if(HAS_TRAIT(M, TRAIT_POWERHUNGRY))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/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,"quirks"=null)
|
||||
name = "Blood"
|
||||
color = "#C80000" // rgb: 200, 0, 0
|
||||
color = COLOR_BLOOD
|
||||
metabolization_rate = 5 //fast rate so it disappears fast.
|
||||
taste_description = "iron"
|
||||
taste_mult = 1.3
|
||||
@@ -30,17 +30,22 @@
|
||||
L.ForceContractDisease(D)
|
||||
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
if(C.get_blood_id() == /datum/reagent/blood && ((methods & INJECT) || ((methods & 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)) && !IS_BLOODSUCKER(C))
|
||||
C.reagents.add_reagent(/datum/reagent/toxin, reac_volume * 0.5)
|
||||
else
|
||||
C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM(C))
|
||||
var/mob/living/carbon/exposed_carbon = L
|
||||
if(exposed_carbon.get_blood_id() == /datum/reagent/blood && (methods == INJECT || (methods == INGEST && exposed_carbon.dna && exposed_carbon.dna.species && (DRINKSBLOOD in exposed_carbon.dna.species.species_traits))))
|
||||
if(data && data["blood_type"])
|
||||
var/datum/blood_type/blood_type = data["blood_type"]
|
||||
if(blood_type.type in exposed_carbon.dna.blood_type.compatible_types)
|
||||
exposed_carbon.blood_volume = min(exposed_carbon.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM(L))
|
||||
return
|
||||
exposed_carbon.reagents.add_reagent(/datum/reagent/toxin, reac_volume * 0.5)
|
||||
|
||||
|
||||
/datum/reagent/blood/on_new(list/data)
|
||||
if(istype(data))
|
||||
SetViruses(src, data)
|
||||
var/datum/blood_type/blood_type = data["blood_type"]
|
||||
if(blood_type)
|
||||
color = blood_type.color
|
||||
|
||||
/datum/reagent/blood/on_merge(list/mix_data)
|
||||
if(data && mix_data)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
icon = 'icons/obj/bloodpack.dmi'
|
||||
icon_state = "bloodpack"
|
||||
volume = 200
|
||||
var/blood_type = null
|
||||
var/datum/blood_type/blood_type = null
|
||||
var/unique_blood = null
|
||||
var/labelled = 0
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
/obj/item/reagent_containers/blood/Initialize(mapload)
|
||||
. = ..()
|
||||
if(blood_type != null)
|
||||
if(!istype(blood_type, /datum/blood_type) && get_blood_type(blood_type))
|
||||
blood_type = get_blood_type(blood_type)
|
||||
reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
|
||||
update_appearance(UPDATE_ICON)
|
||||
|
||||
@@ -74,7 +76,7 @@
|
||||
if(B && B.data && B.data["blood_type"])
|
||||
blood_type = B.data["blood_type"]
|
||||
else if(reagents.has_reagent(/datum/reagent/consumable/liquidelectricity))
|
||||
blood_type = "LE"
|
||||
blood_type = "E"
|
||||
else
|
||||
blood_type = null
|
||||
update_pack_name()
|
||||
@@ -83,7 +85,7 @@
|
||||
/obj/item/reagent_containers/blood/proc/update_pack_name()
|
||||
if(!labelled)
|
||||
if(blood_type)
|
||||
name = "blood pack - [blood_type]"
|
||||
name = "blood pack[blood_type ? " - [unique_blood ? blood_type : blood_type.name]" : null]"
|
||||
else
|
||||
name = "blood pack"
|
||||
|
||||
@@ -127,12 +129,15 @@
|
||||
blood_type = "L"
|
||||
|
||||
/obj/item/reagent_containers/blood/ethereal
|
||||
blood_type = "LE"
|
||||
blood_type = "E"
|
||||
unique_blood = /datum/reagent/consumable/liquidelectricity
|
||||
|
||||
/obj/item/reagent_containers/blood/universal
|
||||
blood_type = "U"
|
||||
|
||||
/obj/item/reagent_containers/blood/gorilla
|
||||
blood_type = "G"
|
||||
|
||||
/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())
|
||||
|
||||
@@ -408,7 +408,7 @@ GLOBAL_LIST_EMPTY(bluespace_slime_crystals)
|
||||
blood_amt = max_blood_amt
|
||||
break
|
||||
qdel(B)
|
||||
else if (istype(B, /obj/effect/decal/cleanable/trail_holder))
|
||||
else if (istype(B, /obj/effect/decal/cleanable/blood/trail_holder))
|
||||
blood_amt += 3
|
||||
if(blood_amt > max_blood_amt)
|
||||
blood_amt = max_blood_amt
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
var/status = BODYPART_ORGANIC
|
||||
var/sub_status = BODYPART_SUBTYPE_ORGANIC
|
||||
var/needs_processing = FALSE
|
||||
|
||||
///This is effectively the icon_state prefix for limbs.
|
||||
var/limb_id
|
||||
var/body_zone //BODY_ZONE_CHEST, BODY_ZONE_L_ARM, etc , used for def_zone
|
||||
var/aux_zone // used for hands
|
||||
var/aux_layer
|
||||
@@ -56,6 +57,10 @@
|
||||
var/species_color = ""
|
||||
var/mutation_color = ""
|
||||
var/no_update = 0
|
||||
/// The colour of damage done to this bodypart
|
||||
var/damage_color = ""
|
||||
/// Should we even use a color?
|
||||
var/use_damage_color = FALSE
|
||||
|
||||
var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
|
||||
var/dismemberable = 1 //whether it can be dismembered with a weapon.
|
||||
@@ -848,6 +853,7 @@
|
||||
|
||||
body_gender = H.gender
|
||||
should_draw_gender = S.sexes
|
||||
use_damage_color = S.use_damage_color
|
||||
|
||||
if((MUTCOLORS in S.species_traits) || (DYNCOLORS in S.species_traits))
|
||||
if(S.fixed_mut_color)
|
||||
@@ -897,7 +903,10 @@
|
||||
image_dir = SOUTH
|
||||
if(dmg_overlay_type)
|
||||
if(brutestate)
|
||||
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
|
||||
var/image/bruteoverlay = image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
|
||||
if(use_damage_color)
|
||||
bruteoverlay.color = damage_color
|
||||
. += bruteoverlay
|
||||
if(burnstate)
|
||||
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir)
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 148 KiB |
@@ -423,6 +423,7 @@
|
||||
#include "code\datums\ai_laws.dm"
|
||||
#include "code\datums\armor.dm"
|
||||
#include "code\datums\beam.dm"
|
||||
#include "code\datums\blood_types.dm"
|
||||
#include "code\datums\browser.dm"
|
||||
#include "code\datums\callback.dm"
|
||||
#include "code\datums\chatmessage.dm"
|
||||
@@ -506,6 +507,7 @@
|
||||
#include "code\datums\components\bakeable.dm"
|
||||
#include "code\datums\components\bane.dm"
|
||||
#include "code\datums\components\beetlejuice.dm"
|
||||
#include "code\datums\components\bloodysoles.dm"
|
||||
#include "code\datums\components\butchering.dm"
|
||||
#include "code\datums\components\caltrop.dm"
|
||||
#include "code\datums\components\chasm.dm"
|
||||
@@ -579,7 +581,6 @@
|
||||
#include "code\datums\components\crafting\recipes.dm"
|
||||
#include "code\datums\components\crafting\tailoring.dm"
|
||||
#include "code\datums\components\crafting\weapons.dm"
|
||||
#include "code\datums\components\decals\blood.dm"
|
||||
#include "code\datums\components\fantasy\_fantasy.dm"
|
||||
#include "code\datums\components\fantasy\affix.dm"
|
||||
#include "code\datums\components\fantasy\prefixes.dm"
|
||||
@@ -675,6 +676,8 @@
|
||||
#include "code\datums\elements\rust.dm"
|
||||
#include "code\datums\elements\squish.dm"
|
||||
#include "code\datums\elements\update_icon_blocker.dm"
|
||||
#include "code\datums\elements\decals\_decals.dm"
|
||||
#include "code\datums\elements\decals\blood.dm"
|
||||
#include "code\datums\helper_datums\events.dm"
|
||||
#include "code\datums\helper_datums\getrev.dm"
|
||||
#include "code\datums\helper_datums\icon_snapshot.dm"
|
||||
@@ -2118,8 +2121,8 @@
|
||||
#include "code\modules\client\preferences\assets.dm"
|
||||
#include "code\modules\client\preferences\auto_fit_viewport.dm"
|
||||
#include "code\modules\client\preferences\balloon_alerts.dm"
|
||||
#include "code\modules\client\preferences\clerk_choice.dm"
|
||||
#include "code\modules\client\preferences\chapel_choice.dm"
|
||||
#include "code\modules\client\preferences\clerk_choice.dm"
|
||||
#include "code\modules\client\preferences\clothing.dm"
|
||||
#include "code\modules\client\preferences\credits.dm"
|
||||
#include "code\modules\client\preferences\donor.dm"
|
||||
@@ -4261,7 +4264,6 @@
|
||||
#include "yogstation\code\modules\reagents\chemistry\reagents\food_reagents.dm"
|
||||
#include "yogstation\code\modules\reagents\chemistry\reagents\other_reagents.dm"
|
||||
#include "yogstation\code\modules\reagents\chemistry\recipes\slime_extracts.dm"
|
||||
#include "yogstation\code\modules\reagents\reagent_containers\blood_pack.dm"
|
||||
#include "yogstation\code\modules\reagents\reagent_containers\bottle.dm"
|
||||
#include "yogstation\code\modules\reagents\reagent_containers\gummies.dm"
|
||||
#include "yogstation\code\modules\reagents\reagent_containers\hypospray.dm"
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
////////////BLOODCRAWL
|
||||
/datum/component/crawl/blood
|
||||
crawling_types = list(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/xenoblood, /obj/effect/decal/cleanable/trail_holder)
|
||||
crawling_types = list(/obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/xenoblood, /obj/effect/decal/cleanable/blood/trail_holder)
|
||||
gain_message = span_boldnotice("You can now bloodcrawl! Alt-click blood or gibs to phase in and out.")
|
||||
loss_message = span_warning("You can no longer bloodcrawl.")
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
if (mode)
|
||||
if (!guardian.Adjacent(target))
|
||||
return ..()
|
||||
if (istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder))
|
||||
if (istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/blood/trail_holder))
|
||||
guardian.visible_message(span_notice("[guardian] swirls it's finger around in [target] for a bit, before shaking it off."))
|
||||
var/obj/effect/decal/D = target
|
||||
var/list/blood = D.return_blood_DNA()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
attack_verb = "assault"
|
||||
skinned_type = /obj/item/stack/sheet/plasteel{amount = 5} //coated in plasteel
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/synthmeat
|
||||
exotic_bloodtype = "U" //synthetic blood that works for literally everyone
|
||||
exotic_bloodtype = "Synthetic" //synthetic blood
|
||||
toxic_food = NONE
|
||||
liked_food = FRIED | SUGAR | JUNKFOOD
|
||||
disliked_food = GROSS | VEGETABLES
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/obj/item/reagent_containers/blood/gorilla
|
||||
blood_type = "G"
|
||||
Reference in New Issue
Block a user