mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-23 15:17:43 +01:00
fb81ffbe83
* Fixes necrosis steps setting bone Makes it so you the 'cut away' step doesn't set bones to open. This is entirely a non-internal fix (you're working on the flesh, not the organs inside) so you don't need the bone retracted. * Update other.dm * Crowbar Augment * descriptors * Update carbon.dm * no typecasting * removes unused proc * Limb status * Makes butchering take time Gives a warning as well when starting it. * Update organ.dm * Update organ.dm * Closing surgical stages and desc. Opened organs have descriptions that they're opened. Organs inform you that they have SPECIAL MECHANICS THAT'VE BEEN IN FOR 10 YEARS that you can do to them. Allows fixing amputated organs A BUNCH of stuff * Update organ.dm * Keep the washing * Update external_repair.dm * Update other.dm * Organizes surgeries * fix a typo * Update surgery.dm * More surgery * Nerve Surgery Adds template for nerve surgery * Prevents pain from limbs that feel no pain * Update external_repair.dm
643 lines
20 KiB
Plaintext
643 lines
20 KiB
Plaintext
/**
|
|
* The base type for nearly all physical objects in SS13
|
|
|
|
* Lots and lots of functionality lives here, although in general we are striving to move
|
|
* as much as possible to the components/elements system
|
|
*/
|
|
/atom
|
|
layer = TURF_LAYER //This was here when I got here. Why though?
|
|
var/level = 2
|
|
var/flags = NONE
|
|
var/was_bloodied
|
|
var/blood_color
|
|
var/pass_flags = 0
|
|
var/throwpass = 0
|
|
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
|
|
var/simulated = TRUE //filter for actions - used by lighting overlays
|
|
var/atom_say_verb = "says"
|
|
var/bubble_icon = "normal" ///what icon the atom uses for speechbubbles
|
|
var/datum/forensics_crime/forensic_data
|
|
var/fluorescent // Shows up under a UV light.
|
|
|
|
var/last_bumped = 0
|
|
|
|
///Chemistry.
|
|
var/datum/reagents/reagents = null
|
|
|
|
//var/chem_is_open_container = 0
|
|
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
|
|
///Chemistry.
|
|
|
|
// Overlays
|
|
///Our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate
|
|
var/list/our_overlays
|
|
///Overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
|
|
var/list/priority_overlays
|
|
///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
|
|
var/list/managed_vis_overlays
|
|
|
|
//Detective Work, used for the duplicate data points kept in the scanners
|
|
var/list/original_atom
|
|
// Track if we are already had initialize() called to prevent double-initialization.
|
|
//var/initialized = FALSE // using the atom flags
|
|
|
|
/// Last name used to calculate a color for the chatmessage overlays
|
|
var/chat_color_name
|
|
/// Last color calculated for the the chatmessage overlays
|
|
var/chat_color
|
|
/// A luminescence-shifted value of the last color calculated for chatmessage overlays
|
|
var/chat_color_darkened
|
|
/// The chat color var, without alpha.
|
|
var/chat_color_hover
|
|
//! Colors
|
|
/**
|
|
* used to store the different colors on an atom
|
|
*
|
|
* its inherent color, the colored paint applied on it, special color effect etc...
|
|
*/
|
|
var/list/atom_colours
|
|
/// Lazylist of all images to update when we change z levels
|
|
/// You will need to manage adding/removing from this yourself, but I'll do the updating for you
|
|
var/list/image/update_on_z
|
|
|
|
/atom/Destroy()
|
|
if(reagents)
|
|
QDEL_NULL(reagents)
|
|
if(light)
|
|
QDEL_NULL(light)
|
|
if(forensic_data)
|
|
QDEL_NULL(forensic_data)
|
|
// Checking length(overlays) before cutting has significant speed benefits
|
|
if (length(overlays))
|
|
overlays.Cut()
|
|
if (length(our_overlays))
|
|
our_overlays.Cut()
|
|
if (length(priority_overlays))
|
|
priority_overlays.Cut()
|
|
if (length(managed_vis_overlays))
|
|
managed_vis_overlays.Cut()
|
|
if (length(original_atom))
|
|
original_atom.Cut()
|
|
return ..()
|
|
|
|
/atom/proc/reveal_blood()
|
|
return
|
|
|
|
/atom/proc/assume_air(datum/gas_mixture/giver)
|
|
return null
|
|
|
|
/atom/proc/remove_air(amount)
|
|
return null
|
|
|
|
/atom/proc/return_air()
|
|
if(loc)
|
|
return loc.return_air()
|
|
else
|
|
return null
|
|
|
|
/atom/proc/Bumped(AM as mob|obj)
|
|
set waitfor = FALSE
|
|
|
|
SEND_SIGNAL(src, COMSIG_ATOM_BUMPED, AM)
|
|
|
|
// Convenience proc to see if a container is open for chemistry handling
|
|
// returns true if open
|
|
// false if closed
|
|
/atom/proc/is_open_container()
|
|
return flags & OPENCONTAINER
|
|
|
|
/*//Convenience proc to see whether a container can be accessed in a certain way.
|
|
|
|
proc/can_subract_container()
|
|
return flags & EXTRACT_CONTAINER
|
|
|
|
proc/can_add_container()
|
|
return flags & INSERT_CONTAINER
|
|
*/
|
|
|
|
// Used to be for the PROXMOVE flag, but that was terrible, so instead it's just here as a stub for
|
|
// all the atoms that still have the proc, but get events other ways.
|
|
/atom/proc/HasProximity(turf/T, datum/weakref/WF, old_loc)
|
|
SIGNAL_HANDLER
|
|
return
|
|
|
|
//Register listeners on turfs in a certain range
|
|
/atom/proc/sense_proximity(var/range = 1, var/callback)
|
|
ASSERT(callback)
|
|
ASSERT(isturf(loc))
|
|
var/list/turfs = trange(range, src)
|
|
for(var/turf/T as anything in turfs)
|
|
RegisterSignal(T, COMSIG_OBSERVER_TURF_ENTERED, callback)
|
|
|
|
//Unregister from prox listening in a certain range. You should do this BEFORE you move, but if you
|
|
// really can't, then you can set the center where you moved from.
|
|
/atom/proc/unsense_proximity(var/range = 1, var/callback, var/center)
|
|
ASSERT(isturf(center) || isturf(loc))
|
|
var/list/turfs = trange(range, center ? center : src)
|
|
for(var/turf/T as anything in turfs)
|
|
UnregisterSignal(T, COMSIG_OBSERVER_TURF_ENTERED)
|
|
|
|
|
|
/atom/proc/emp_act(severity, recursive)
|
|
recursive++
|
|
if(recursive > 5) //After a certain depth, we're just going to assume that it's too insulated to be EMP'd.
|
|
return
|
|
for(var/atom/A in contents)
|
|
if(isbelly(A)) //Prey are protected
|
|
continue
|
|
A.emp_act(severity, recursive)
|
|
return
|
|
|
|
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
|
|
if(SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) & COMPONENT_CANCEL_ATTACK_CHAIN)
|
|
return
|
|
|
|
P.on_hit(src, 0, def_zone)
|
|
. = 0
|
|
|
|
// Called when a blob expands onto the tile the atom occupies.
|
|
/atom/proc/blob_act()
|
|
return
|
|
|
|
/atom/proc/in_contents_of(container)//can take class or object instance as argument
|
|
if(ispath(container))
|
|
if(istype(src.loc, container))
|
|
return 1
|
|
else if(src in container)
|
|
return 1
|
|
return
|
|
|
|
/*
|
|
* atom/proc/search_contents_for(path,list/filter_path=null)
|
|
* Recursevly searches all atom contens (including contents contents and so on).
|
|
*
|
|
* ARGS: path - search atom contents for atoms of this type
|
|
* list/filter_path - if set, contents of atoms not of types in this list are excluded from search.
|
|
*
|
|
* RETURNS: list of found atoms
|
|
*/
|
|
|
|
/atom/proc/search_contents_for(path,list/filter_path=null)
|
|
var/list/found = list()
|
|
for(var/atom/A in src)
|
|
if(istype(A, path))
|
|
found += A
|
|
if(filter_path)
|
|
var/pass = 0
|
|
for(var/type in filter_path)
|
|
pass |= istype(A, type)
|
|
if(!pass)
|
|
continue
|
|
if(A.contents.len)
|
|
found += A.search_contents_for(path,filter_path)
|
|
return found
|
|
|
|
/atom/proc/get_examine_desc()
|
|
return desc
|
|
|
|
//All atoms
|
|
/atom/proc/examine(mob/user, var/infix = "", var/suffix = "")
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
//This reformat names to get a/an properly working on item descriptions when they are bloody
|
|
var/f_name = "\a [src][infix]."
|
|
if(forensic_data?.has_blooddna() && !istype(src, /obj/effect/decal))
|
|
if(gender == PLURAL)
|
|
f_name = "some "
|
|
else
|
|
f_name = "a "
|
|
if(blood_color != SYNTH_BLOOD_COLOUR)
|
|
f_name += "[span_danger("blood-stained")] [name][infix]!"
|
|
else
|
|
f_name += "oil-stained [name][infix]."
|
|
|
|
var/borg = "" // Borg grippers say if the item can be gripped
|
|
if(isrobot(user) && isitem(src))
|
|
borg = "None of your grippers can hold this."
|
|
var/mob/living/silicon/robot/R = user
|
|
if(R.module?.modules)
|
|
for(var/obj/item/gripper/G in R.module.modules)
|
|
if(is_type_in_list(src,G.can_hold))
|
|
borg = span_boldnotice("\The [G]") + span_notice(" can hold this.")
|
|
break
|
|
|
|
var/list/output = list("[icon2html(src,user.client)] That's [f_name] [suffix] [borg]", get_examine_desc())
|
|
|
|
SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, output)
|
|
return output
|
|
|
|
// Don't make these call bicon or anything, these are what bicon uses. They need to return an icon.
|
|
/atom/proc/examine_icon()
|
|
return src // 99% of the time just returning src will be sufficient. More complex examine icon things are available where they are needed
|
|
|
|
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.
|
|
// see code/modules/mob/mob_movement.dm for more.
|
|
/atom/proc/relaymove()
|
|
return
|
|
|
|
//called to set the atom's dir and used to add behaviour to dir-changes
|
|
/atom/proc/set_dir(new_dir)
|
|
SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, new_dir)
|
|
. = new_dir != dir
|
|
dir = new_dir
|
|
|
|
// Called to set the atom's density and used to add behavior to density changes.
|
|
/atom/proc/set_density(var/new_density)
|
|
if(density == new_density)
|
|
return FALSE
|
|
density = !!new_density // Sanitize to be strictly 0 or 1
|
|
return TRUE
|
|
|
|
// Called to set the atom's invisibility and usd to add behavior to invisibility changes.
|
|
/atom/proc/set_invisibility(var/new_invisibility)
|
|
if(invisibility == new_invisibility)
|
|
return FALSE
|
|
invisibility = new_invisibility
|
|
return TRUE
|
|
|
|
/atom/proc/ex_act(var/strength = 3)
|
|
return (SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, strength, src) & COMPONENT_IGNORE_EXPLOSION)
|
|
|
|
/atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source)
|
|
return -1
|
|
|
|
/**
|
|
* Respond to fire being used on our atom
|
|
*
|
|
* Default behaviour is to send [COMSIG_ATOM_FIRE_ACT] and return
|
|
*/
|
|
/atom/proc/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, air, exposed_temperature, exposed_volume)
|
|
return FALSE
|
|
|
|
/**
|
|
* Sends [COMSIG_ATOM_EXTINGUISH] signal, which properly removes burning component if it is present.
|
|
*
|
|
* Default behaviour is to send [COMSIG_ATOM_ACID_ACT] and return
|
|
*/
|
|
/atom/proc/extinguish()
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
return SEND_SIGNAL(src, COMSIG_ATOM_EXTINGUISH)
|
|
|
|
// Returns an assoc list of RCD information.
|
|
// Example would be: list(RCD_VALUE_MODE = RCD_DECONSTRUCT, RCD_VALUE_DELAY = 50, RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 4)
|
|
// This occurs before rcd_act() is called, and it won't be called if it returns FALSE.
|
|
/atom/proc/rcd_values(mob/living/user, obj/item/rcd/the_rcd, passed_mode)
|
|
return FALSE
|
|
|
|
/atom/proc/rcd_act(mob/living/user, obj/item/rcd/the_rcd, passed_mode)
|
|
return
|
|
|
|
/atom/proc/occult_act(mob/living/user)
|
|
return
|
|
|
|
/atom/proc/melt()
|
|
return
|
|
|
|
// Previously this was defined both on /obj/ and /turf/ seperately. And that's bad.
|
|
/atom/proc/update_icon()
|
|
return
|
|
|
|
|
|
/atom/proc/hitby(atom/movable/source, datum/thrownthing/throwingdatum)
|
|
SEND_SIGNAL(src, COMSIG_ATOM_HITBY, source)
|
|
return
|
|
|
|
//returns 1 if made bloody, returns 0 otherwise
|
|
/atom/proc/add_blood(mob/living/carbon/human/M as mob)
|
|
|
|
if(flags & NOBLOODY)
|
|
return 0
|
|
|
|
was_bloodied = TRUE
|
|
if(!blood_color)
|
|
blood_color = "#A10808"
|
|
if(istype(M))
|
|
if (!istype(M.dna, /datum/dna))
|
|
M.dna = new /datum/dna(null)
|
|
M.dna.real_name = M.real_name
|
|
M.check_dna()
|
|
blood_color = M.species.get_blood_colour(M)
|
|
. = 1
|
|
return 1
|
|
|
|
/atom/proc/on_rag_wipe(var/obj/item/reagent_containers/glass/rag/R)
|
|
wash(CLEAN_WASH)
|
|
R.reagents.splash(src, 1)
|
|
|
|
/atom/proc/get_global_map_pos()
|
|
if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map)) return
|
|
var/cur_x = null
|
|
var/cur_y = null
|
|
var/list/y_arr = null
|
|
for(cur_x = 1, cur_x <= GLOB.global_map.len, cur_x++)
|
|
y_arr = GLOB.global_map[cur_x]
|
|
cur_y = y_arr.Find(src.z)
|
|
if(cur_y)
|
|
break
|
|
// to_world("X = [cur_x]; Y = [cur_y]")
|
|
if(cur_x && cur_y)
|
|
return list("x"=cur_x,"y"=cur_y)
|
|
else
|
|
return 0
|
|
|
|
/atom/proc/checkpass(passflag)
|
|
return (pass_flags&passflag)
|
|
|
|
/atom/proc/isinspace()
|
|
if(istype(get_turf(src), /turf/space))
|
|
return 1
|
|
else
|
|
return 0
|
|
|
|
// Show a message to all mobs and objects in sight of this atom
|
|
// Use for objects performing visible actions
|
|
// message is output to anyone who can see, e.g. "The [src] does something!"
|
|
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
|
/atom/proc/visible_message(var/message, var/blind_message, var/list/exclude_mobs, var/range = world.view, var/runemessage = "<span style='font-size: 1.5em'>👁</span>")
|
|
|
|
//VOREStation Edit
|
|
var/list/see
|
|
if(isbelly(loc))
|
|
var/obj/belly/B = loc
|
|
see = B.get_mobs_and_objs_in_belly()
|
|
else
|
|
see = get_mobs_and_objs_in_view_fast(get_turf(src), range, remote_ghosts = FALSE)
|
|
//VOREStation Edit End
|
|
|
|
var/list/seeing_mobs = see["mobs"]
|
|
var/list/seeing_objs = see["objs"]
|
|
if(LAZYLEN(exclude_mobs))
|
|
seeing_mobs -= exclude_mobs
|
|
|
|
for(var/obj/O as anything in seeing_objs)
|
|
O.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE)
|
|
for(var/mob/M as anything in seeing_mobs)
|
|
if(M.see_invisible >= invisibility && MOB_CAN_SEE_PLANE(M, plane))
|
|
M.show_message(message, VISIBLE_MESSAGE, blind_message, AUDIBLE_MESSAGE)
|
|
if(runemessage != -1)
|
|
M.create_chat_message(src, "[runemessage]", FALSE, list("emote"), audible = FALSE)
|
|
else if(blind_message)
|
|
M.show_message(blind_message, AUDIBLE_MESSAGE)
|
|
|
|
// Show a message to all mobs and objects in earshot of this atom
|
|
// Use for objects performing audible actions
|
|
// message is the message output to anyone who can hear.
|
|
// deaf_message (optional) is what deaf people will see.
|
|
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
|
|
/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance, var/radio_message, var/runemessage)
|
|
|
|
var/range = hearing_distance || world.view
|
|
var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
|
|
|
|
var/list/hearing_mobs = hear["mobs"]
|
|
var/list/hearing_objs = hear["objs"]
|
|
|
|
if(radio_message)
|
|
for(var/obj/O as anything in hearing_objs)
|
|
O.hear_talk(src, list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], radio_message)), null)
|
|
else
|
|
for(var/obj/O as anything in hearing_objs)
|
|
O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
|
|
|
|
for(var/mob/M as anything in hearing_mobs)
|
|
var/msg = message
|
|
M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
|
|
if(runemessage != -1)
|
|
M.create_chat_message(src, "[runemessage || message]", FALSE, list("emote"))
|
|
|
|
/atom/movable/proc/dropInto(var/atom/destination)
|
|
while(istype(destination))
|
|
var/atom/drop_destination = destination.onDropInto(src)
|
|
if(!istype(drop_destination) || drop_destination == destination)
|
|
return forceMove(destination)
|
|
destination = drop_destination
|
|
return moveToNullspace()
|
|
|
|
/atom/proc/onDropInto(var/atom/movable/AM)
|
|
return // If onDropInto returns null, then dropInto will forceMove AM into us.
|
|
|
|
/atom/movable/onDropInto(var/atom/movable/AM)
|
|
return loc // If onDropInto returns something, then dropInto will attempt to drop AM there.
|
|
|
|
/atom/proc/InsertedContents()
|
|
return contents
|
|
|
|
/atom/proc/get_gravity(turf/T)
|
|
if(!T || !isturf(T))
|
|
T = get_turf(src)
|
|
if(istype(T, /turf/space)) // Turf never has gravity
|
|
return FALSE
|
|
var/area/A = get_area(T)
|
|
if(A && A.get_gravity())
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/atom/proc/is_incorporeal()
|
|
return FALSE
|
|
|
|
/atom/proc/drop_location()
|
|
var/atom/L = loc
|
|
if(!L)
|
|
return null
|
|
return L.AllowDrop() ? L : L.drop_location()
|
|
|
|
/atom/proc/AllowDrop()
|
|
return FALSE
|
|
|
|
/atom/proc/get_nametag_name(mob/user)
|
|
return name
|
|
|
|
/atom/proc/get_nametag_desc(mob/user)
|
|
return "" //Desc itself is often too long to use
|
|
|
|
/atom/proc/atom_say(message)
|
|
if(!message)
|
|
return
|
|
var/list/speech_bubble_hearers = list()
|
|
for(var/mob/M in get_mobs_in_view(7, src))
|
|
M.show_message(span_npc_say(span_name("[src]") + " [atom_say_verb], \"[message]\""), 2, null, 1)
|
|
if(M.client)
|
|
speech_bubble_hearers += M.client
|
|
|
|
if(length(speech_bubble_hearers))
|
|
var/image/I = generate_speech_bubble(src, "[bubble_icon][say_test(message)]", FLY_LAYER)
|
|
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
|
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), I, speech_bubble_hearers, 30)
|
|
|
|
/atom/proc/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
|
|
return
|
|
|
|
/atom/Entered(atom/movable/AM, atom/old_loc)
|
|
. = ..()
|
|
SEND_SIGNAL(AM, COMSIG_MOVABLE_ATTEMPTED_MOVE, old_loc, AM.loc)
|
|
SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, old_loc)
|
|
SEND_SIGNAL(AM, COMSIG_ATOM_ENTERING, src, old_loc)
|
|
|
|
/atom/Exit(atom/movable/AM, atom/new_loc)
|
|
. = ..()
|
|
if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, new_loc) & COMPONENT_ATOM_BLOCK_EXIT)
|
|
return FALSE
|
|
|
|
/atom/Exited(atom/movable/AM, atom/new_loc)
|
|
. = ..()
|
|
SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, new_loc)
|
|
|
|
/atom/proc/interact(mob/user)
|
|
return
|
|
|
|
// Purpose: Determines if the object can pass this atom.
|
|
// Called by: Movement.
|
|
// Inputs: The moving atom, target turf.
|
|
// Outputs: Boolean if can pass.
|
|
// Airflow and ZAS zones now uses CanZASPass() instead of this proc.
|
|
/atom/proc/CanPass(atom/movable/mover, turf/target)
|
|
return !density
|
|
|
|
|
|
//! ## Atom Colour Priority System
|
|
/**
|
|
* A System that gives finer control over which atom colour to colour the atom with.
|
|
* The "highest priority" one is always displayed as opposed to the default of
|
|
* "whichever was set last is displayed"
|
|
*/
|
|
|
|
/// Adds an instance of colour_type to the atom's atom_colours list
|
|
/atom/proc/add_atom_colour(coloration, colour_priority)
|
|
if(!atom_colours || !atom_colours.len)
|
|
atom_colours = list()
|
|
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
|
if(!coloration)
|
|
return
|
|
if(colour_priority > atom_colours.len)
|
|
return
|
|
atom_colours[colour_priority] = coloration
|
|
update_atom_colour()
|
|
|
|
/// Removes an instance of colour_type from the atom's atom_colours list
|
|
/atom/proc/remove_atom_colour(colour_priority, coloration)
|
|
if(!atom_colours)
|
|
atom_colours = list()
|
|
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
|
if(colour_priority > atom_colours.len)
|
|
return
|
|
if(coloration && atom_colours[colour_priority] != coloration)
|
|
return //if we don't have the expected color (for a specific priority) to remove, do nothing
|
|
atom_colours[colour_priority] = null
|
|
update_atom_colour()
|
|
|
|
/// Resets the atom's color to null, and then sets it to the highest priority colour available
|
|
/atom/proc/update_atom_colour()
|
|
if(!atom_colours)
|
|
atom_colours = list()
|
|
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
|
color = null
|
|
for(var/C in atom_colours)
|
|
if(islist(C))
|
|
var/list/L = C
|
|
if(L.len)
|
|
color = L
|
|
return
|
|
else if(C)
|
|
color = C
|
|
return
|
|
|
|
///Passes Stat Browser Panel clicks to the game and calls client click on an atom
|
|
/atom/Topic(href, list/href_list)
|
|
. = ..()
|
|
if(!usr?.client)
|
|
return
|
|
var/client/usr_client = usr.client
|
|
var/list/paramslist = list()
|
|
|
|
if(href_list["statpanel_item_click"])
|
|
switch(href_list["statpanel_item_click"])
|
|
if("left")
|
|
paramslist["left"] = "1"
|
|
if("right")
|
|
paramslist["right"] = "1"
|
|
if("middle")
|
|
paramslist["middle"] = "1"
|
|
else
|
|
return
|
|
|
|
if(href_list["statpanel_item_shiftclick"])
|
|
paramslist["shift"] = "1"
|
|
if(href_list["statpanel_item_ctrlclick"])
|
|
paramslist["ctrl"] = "1"
|
|
if(href_list["statpanel_item_altclick"])
|
|
paramslist["alt"] = "1"
|
|
|
|
var/mouseparams = list2params(paramslist)
|
|
usr_client.Click(src, loc, null, mouseparams)
|
|
return TRUE
|
|
|
|
GLOBAL_LIST_EMPTY(icon_dimensions)
|
|
|
|
/atom/proc/get_oversized_icon_offsets()
|
|
if (pixel_x == 0 && pixel_y == 0)
|
|
return list("x" = 0, "y" = 0)
|
|
var/list/icon_dimensions = get_icon_dimensions(icon)
|
|
var/icon_width = icon_dimensions["width"]
|
|
var/icon_height = icon_dimensions["height"]
|
|
return list(
|
|
"x" = icon_width > world.icon_size && pixel_x != 0 ? (icon_width - world.icon_size) * 0.5 : 0,
|
|
"y" = icon_height > world.icon_size /*&& pixel_y != 0*/ ? (icon_height - world.icon_size) * 0.5 : 0, // we don't have pixel_y in use
|
|
)
|
|
|
|
/// Returns the src and all recursive contents as a list.
|
|
/atom/proc/get_all_contents(ignore_flag_1)
|
|
. = list(src)
|
|
var/i = 0
|
|
while(i < length(.))
|
|
var/atom/checked_atom = .[++i]
|
|
if(checked_atom.flags & ignore_flag_1)
|
|
continue
|
|
. += checked_atom.contents
|
|
|
|
/// Identical to get_all_contents but returns a list of atoms of the type passed in the argument.
|
|
/atom/proc/get_all_contents_type(type)
|
|
var/list/processing_list = list(src)
|
|
. = list()
|
|
while(length(processing_list))
|
|
var/atom/checked_atom = processing_list[1]
|
|
processing_list.Cut(1, 2)
|
|
processing_list += checked_atom.contents
|
|
if(istype(checked_atom, type))
|
|
. += checked_atom
|
|
|
|
/**
|
|
* Respond to our atom being checked by a virus extrapolator.
|
|
*
|
|
* Default behaviour is to send COMSIG_ATOM_EXTRAPOLATOR_ACT and return an empty list (which may be populated by the signal)
|
|
*
|
|
* Returns a list of viruses in the atom.
|
|
* Include EXTRAPOLATOR_SPECIAL_HANDLED in the list if the extrapolation act has been handled by this proc or a signal, and should not be handled by the extrapolator itself.
|
|
*/
|
|
/atom/proc/extrapolator_act(mob/living/user, obj/item/extrapolator/extrapolator, dry_run = FALSE)
|
|
. = list(EXTRAPOLATOR_RESULT_DISEASES = list())
|
|
SEND_SIGNAL(src, COMSIG_ATOM_EXTRAPOLATOR_ACT, user, extrapolator, dry_run, .)
|
|
|
|
/**
|
|
* Wash this atom
|
|
*
|
|
* This will clean it off any temporary stuff like blood. Override this in your item to add custom cleaning behavior.
|
|
* Returns true if any washing was necessary and thus performed
|
|
* Arguments:
|
|
* clean_types: any of the CLEAN_ constants
|
|
*/
|
|
/atom/proc/wash(clean_types)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
. = FALSE
|
|
if(SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, clean_types))
|
|
. = TRUE
|
|
|
|
// Basically "if has washable coloration"
|
|
if(length(atom_colours) >= WASHABLE_COLOUR_PRIORITY && atom_colours[WASHABLE_COLOUR_PRIORITY])
|
|
remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
|
|
|
|
forensic_data?.wash(clean_types)
|
|
blood_color = null
|
|
germ_level = 0
|
|
fluorescent = 0
|