Files
Aurora.3/code/game/atoms.dm
Fluffy 955102ef4d More spacemandmm harnessing against bad code (#17376)
* sdfaf

* ssdasd

* dfsd

* try to apply a linter to spot violations of editorconfig

* sfdas

* asf

* sadfas

* sfasf

* asfsda

* sdaf

* sfsad

* totally not for testing

* aaaaaaaaaaaaaaa

* asfsadf

* saf

* sdfaf
2023-09-23 13:46:26 +00:00

755 lines
25 KiB
Plaintext

/atom
layer = 2
var/level = 2
var/flags = 0
var/init_flags = 0
var/list/fingerprints
var/list/fingerprintshidden
var/fingerprintslast = null
var/list/blood_DNA
var/list/other_DNA
var/other_DNA_type = null
var/was_bloodied
var/blood_color
var/last_bumped = 0
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 = 1 // Filter for actions. Used by lighting overlays.
var/fluorescent // Shows up under a UV light.
/// Chemistry.
var/datum/reagents/reagents = null
var/list/reagents_to_add
var/list/reagent_data
var/list/atom_colours // Used to store the different colors on an atom, such as its inherent color, the colored paint applied on it, special color effect, and so on.
// Detective work, used for the duplicate data points kept in the scanners.
var/list/original_atom
var/gfi_layer_rotation = GFI_ROTATION_DEFAULT
// Extra descriptions.
var/desc_extended = null // Regular text about the atom's extended description, if any exists.
var/desc_info = null // Blue text (SPAN_NOTICE()), informing the user about how to use the item or about game controls.
var/desc_antag = null // Red text (SPAN_ALERT()), informing the user about how they can use an object to antagonize.
/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()
// Returns src and all recursive contents in a list.
/atom/proc/GetAllContents()
. = list(src)
var/i = 0
while(i < length(.))
var/atom/A = .[++i]
. += A.contents
// identical to GetAllContents but returns a list of atoms of the type passed in the argument
/atom/proc/get_all_contents_of_type(type)
var/list/processing_list = list(src)
. = list()
while(length(processing_list))
var/atom/A = processing_list[1]
processing_list.Cut(1, 2)
processing_list += A.contents
if(istype(A, type))
. += A
// Returns a list of all locations (except the area) the movable is within
/proc/get_nested_locs(atom/movable/atom_on_location, include_turf = FALSE)
. = list()
var/atom/location = atom_on_location.loc
var/turf/our_turf = get_turf(atom_on_location)
while (location && location != our_turf)
. += location
location = location.loc
if(our_turf && include_turf)
. += our_turf
// Return flags that should be added to the viewer's sight variable.
// Otherwise return a negative number to indicate that the view should be cancelled.
/atom/proc/check_eye(user as mob)
if (istype(user, /mob/living/silicon/ai))
return 0
return -1
/// Primarily used on machinery, when this returns TRUE, equipment that helps with vision, such as prescription glasses for nearsighted characters, have an effect despite the client eye not being on the mob
/atom/proc/grants_equipment_vision(var/mob/user)
return
/atom/proc/additional_sight_flags()
return 0
/atom/proc/additional_see_invisible()
return 0
/atom/proc/on_reagent_change()
return
// This is called when AM collides with us.
/atom/proc/CollidedWith(atom/movable/AM)
set waitfor = FALSE
return
// 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
/atom/proc/is_pour_container()
return flags & POURCONTAINER
/atom/proc/CheckExit()
return 1
// If you want to use this, the atom must have the PROXMOVE flag and the moving atom must also have the PROXMOVE flag currently to help with lag. -ComicIronic
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
/atom/proc/emp_act(var/severity)
return
/atom/proc/flash_act(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, ignore_inherent = FALSE, type = /obj/screen/fullscreen/flash, length = 2.5 SECONDS)
return
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
P.on_hit(src, 0, def_zone)
. = 0
/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
/**
* Checks if user can use this object. Set use_flags to customize what checks are done
* Returns 0 (FALSE) if they can use it, a value representing why they can't if not
* See `code\__defines\misc.dm` for the list of flags and return codes
*
* * user - The `mob` to check against, if it can perform said use
* * use_flags - The flags to modify the check behavior, eg. `USE_ALLOW_NON_ADJACENT`, see `code\__defines\misc.dm` for the list of flags
* * show_messages - A boolean, to indicate if a feedback message should be shown, about the reason why someone can't use the atom
*/
/atom/proc/use_check(mob/user, use_flags = 0, show_messages = FALSE)
. = USE_SUCCESS
if(NOT_FLAG(use_flags, USE_ALLOW_NONLIVING) && !isliving(user)) // No message for ghosts.
return USE_FAIL_NONLIVING
if(NOT_FLAG(use_flags, USE_ALLOW_NON_ADJACENT) && !Adjacent(user))
if (show_messages)
to_chat(user, SPAN_NOTICE("You're too far away from [src] to do that."))
return USE_FAIL_NON_ADJACENT
if(NOT_FLAG(use_flags, USE_ALLOW_DEAD) && user.stat == DEAD)
if (show_messages)
to_chat(user, SPAN_NOTICE("How do you expect to do that when you're dead?"))
return USE_FAIL_DEAD
if(NOT_FLAG(use_flags, USE_ALLOW_INCAPACITATED) && (user.incapacitated()))
if (show_messages)
to_chat(user, SPAN_NOTICE("You cannot do that in your current state."))
return USE_FAIL_INCAPACITATED
if(NOT_FLAG(use_flags, USE_ALLOW_NON_ADV_TOOL_USR) && !user.IsAdvancedToolUser())
if (show_messages)
to_chat(user, SPAN_NOTICE("You don't know how to operate [src]."))
return USE_FAIL_NON_ADV_TOOL_USR
if(HAS_FLAG(use_flags, USE_DISALLOW_SILICONS) && issilicon(user))
if (show_messages)
to_chat(user, SPAN_NOTICE("How do you propose doing that without hands?"))
return USE_FAIL_IS_SILICON
if(HAS_FLAG(use_flags, USE_DISALLOW_SPECIALS) && is_mob_special(user))
if (show_messages)
to_chat(user, SPAN_NOTICE("Your current mob type prevents you from doing this."))
return USE_FAIL_IS_MOB_SPECIAL
if(HAS_FLAG(use_flags, USE_FORCE_SRC_IN_USER) && !(src in user))
if (show_messages)
to_chat(user, SPAN_NOTICE("You need to be holding [src] to do that."))
return USE_FAIL_NOT_IN_USER
/**
* Checks if a mob can use an atom, message the user if not with an appropriate reason
* Returns 0 (FALSE) if they can use it, a value representing why they can't if not
* See `code\__defines\misc.dm` for the list of flags and return codes
*
* * user - The `mob` to check against, if it can perform said use
* * use_flags - The flags to modify the check behavior, eg. `USE_ALLOW_NON_ADJACENT`, see `code\__defines\misc.dm` for the list of flags
*/
/atom/proc/use_check_and_message(mob/user, use_flags = 0)
. = use_check(user, use_flags, TRUE)
/atom/proc/get_light_and_color(var/atom/origin)
if(origin)
color = origin.color
set_light(origin.light_range, origin.light_power, origin.light_color)
// This function will recurse up the hierarchy containing src, in search of the target. It will stop when it reaches an area, as areas have no loc.
/atom/proc/find_up_hierarchy(var/atom/target)
var/x = 0 // As a safety, we'll crawl up a maximum of ten layers.
var/atom/a = src
while (x < 10)
x++
if (isnull(a))
return 0
if (a == target) // We found it!
return 1
if (istype(a, /area))
return 0 // Can't recurse any higher than this.
a = a.loc
return 0 // If we get here, we must be buried many layers deep in nested containers, which shouldn't happen.
// Recursively searches all atom contents (including the contents' contents and so on).
//
// ARGS: path - Search atom contents for atoms of this type.
// 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
// Examination code for all atoms.
// Returns TRUE, the caller always expects TRUE
// This is used rather than SHOULD_CALL_PARENT as it enforces that subtypes of a type that explicitly returns still call parent
/atom/proc/examine(mob/user, distance, is_adjacent, infix = "", suffix = "")
var/f_name = "\a [src]. [infix]"
if(src.blood_DNA && !istype(src, /obj/effect/decal))
if(gender == PLURAL)
f_name = "some "
else
f_name = "a "
if(blood_color != COLOR_IPC_BLOOD && blood_color != COLOR_OIL)
f_name += "<span class='danger'>blood-stained</span> [name][infix]!"
else
f_name += "oil-stained [name][infix]."
to_chat(user, "[icon2html(src, user)] That's [f_name] [suffix]") // Object name. I.e. "This is an Object. It is a normal-sized item."
if(src.desc)
to_chat(user, src.desc) // Object description.
// Extra object descriptions examination code.
if(desc_extended || desc_info || (desc_antag && player_is_antag(user.mind))) // Checks if the object has a extended description, a mechanics description, and/or an antagonist description (and if the user is an antagonist).
to_chat(user, FONT_SMALL(SPAN_NOTICE("\[?\] This object has additional examine information available. <a href=?src=\ref[src];examine_fluff=1>\[Show In Chat\]</a>"))) // If any of the above are true, show that the object has more information available.
if(desc_extended) // If the item has a extended description, show that it is available.
to_chat(user, FONT_SMALL("- This object has an extended description."))
if(desc_info) // If the item has a description regarding game mechanics, show that it is available.
to_chat(user, FONT_SMALL(SPAN_NOTICE("- This object has additional information about mechanics.")))
if(desc_antag && player_is_antag(user.mind)) // If the item has an antagonist description and the user is an antagonist, show that it is available.
to_chat(user, FONT_SMALL(SPAN_ALERT("- This object has additional information for antagonists.")))
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.glasses)
H.glasses.glasses_examine_atom(src, H)
return TRUE
// Same as examine(), but without the "this object has more info" thing and with the extra information instead.
/atom/proc/examine_fluff(mob/user, distance, is_adjacent, infix = "", suffix = "")
var/f_name = "\a [src][infix]."
if(src.blood_DNA && !istype(src, /obj/effect/decal))
if(gender == PLURAL)
f_name = "some "
else
f_name = "a "
if(blood_color != "#030303")
f_name += "<span class='danger'>blood-stained</span> [name][infix]!"
else
f_name += "oil-stained [name][infix]."
to_chat(user, "[icon2html(src, user)] That's [f_name] [suffix]") // Object name. I.e. "This is an Object."
to_chat(user, desc) // Object description.
if(desc_extended) // If the item has a extended description, show it.
to_chat(user, desc_extended)
if(desc_info) // If the item has a description regarding game mechanics, show it.
to_chat(user, FONT_SMALL(SPAN_NOTICE("- [desc_info]")))
if(desc_antag && player_is_antag(user.mind)) // If the item has an antagonist description and the user is an antagonist, show it.
to_chat(user, FONT_SMALL(SPAN_ALERT("- [desc_antag]")))
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.glasses)
H.glasses.glasses_examine_atom(src, H)
return TRUE
// Used to check if "examine_fluff" from the HTML link in examine() is true, i.e. if it was clicked.
/atom/Topic(href, href_list)
. = ..()
if (.)
return
if(href_list["examine_fluff"])
examinate(usr, src, show_extended = TRUE)
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_CLICK] = "1"
if("right")
paramslist[RIGHT_CLICK] = "1"
if("middle")
paramslist[MIDDLE_CLICK] = "1"
else
return
if(href_list["statpanel_item_shiftclick"])
paramslist[SHIFT_CLICK] = "1"
if(href_list["statpanel_item_ctrlclick"])
paramslist[CTRL_CLICK] = "1"
if(href_list["statpanel_item_altclick"])
paramslist[ALT_CLICK] = "1"
var/mouseparams = list2params(paramslist)
usr_client.Click(src, loc, null, mouseparams)
return TRUE
// Called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled_to 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)
. = new_dir != dir
var/old_dir = dir
dir = new_dir
// Lighting.
if (.)
var/datum/light_source/L
for (var/thing in light_sources)
L = thing
if (L.light_angle)
L.source_atom.update_light()
dir_set_event.raise_event(src, old_dir, dir)
/atom/proc/ex_act()
set waitfor = FALSE
return
/atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source)
return NO_EMAG_ACT
/atom/proc/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/atom/proc/melt()
return
/atom/proc/hitby(atom/movable/AM as mob|obj, var/speed = THROWFORCE_SPEED_DIVISOR)
if(density)
AM.throwing = 0
return
/atom/proc/add_hiddenprint(mob/living/M)
if(isnull(M)) return
if(!istype(M, /mob)) return
if(isnull(M.key)) return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if (!istype(H.dna, /datum/dna))
return 0
if (H.gloves)
if(src.fingerprintslast != H.key)
src.fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key)
src.fingerprintslast = H.key
return 0
if (!( src.fingerprints ))
if(src.fingerprintslast != H.key)
src.fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",H.real_name, H.key)
src.fingerprintslast = H.key
return 1
else
if(src.fingerprintslast != M.key)
src.fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",M.real_name, M.key)
src.fingerprintslast = M.key
return
/atom/proc/add_fingerprint(mob/living/M, ignoregloves = 0)
if(isnull(M)) return
if(!istype(M, /mob)) return
if(issilicon(M)) return
if(isnull(M.key)) return
if (ishuman(M))
// Add the list if it does not exist.
if(!fingerprintshidden)
fingerprintshidden = list()
// Fibers.
add_fibers(M)
// They have no prints.
if (HAS_FLAG(M.mutations, mFingerprints))
if(fingerprintslast != M.key)
fingerprintshidden += "(Has no fingerprints) Real name: [M.real_name], Key: [M.key]"
fingerprintslast = M.key
return 0 //Now, lets get to the dirty work.
// First, make sure their DNA makes sense.
var/mob/living/carbon/human/H = M
if (!istype(H.dna, /datum/dna) || !H.dna.uni_identity || (length(H.dna.uni_identity) != 32))
if(!istype(H.dna, /datum/dna))
H.dna = new /datum/dna(null)
H.dna.real_name = H.real_name
H.check_dna()
// Now, deal with gloves.
if (H.gloves && H.gloves != src)
if(fingerprintslast != H.key)
fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []",time_stamp(), H.real_name, H.key)
fingerprintslast = H.key
H.gloves.add_fingerprint(M)
// Deal with gloves that pass finger/palm prints.
if(!ignoregloves)
if(istype(H.gloves, /obj/item/clothing/gloves) && H.gloves != src)
var/obj/item/clothing/gloves/G = H.gloves
if(!prob(G.fingerprint_chance))
return 0
// Admin related.
if(fingerprintslast != H.key)
fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), H.real_name, H.key)
fingerprintslast = H.key
// Make the list if it does not exist.
if(!fingerprints)
fingerprints = list()
// Hash it.
var/full_print = H.get_full_print()
// Add the fingerprints.
if(fingerprints[full_print])
switch(stringpercent(fingerprints[full_print])) // Tells us how many stars are in the current prints.
if(28 to 32)
if(prob(1))
fingerprints[full_print] = full_print // You rolled a one buddy.
else
fingerprints[full_print] = stars(full_print, rand(0,40)) // 24 to 32.
if(24 to 27)
if(prob(3))
fingerprints[full_print] = full_print // Sucks to be you.
else
fingerprints[full_print] = stars(full_print, rand(15, 55)) // 20 to 29.
if(20 to 23)
if(prob(5))
fingerprints[full_print] = full_print // Had a good run didn't ya.
else
fingerprints[full_print] = stars(full_print, rand(30, 70)) // 15 to 25.
if(16 to 19)
if(prob(5))
fingerprints[full_print] = full_print // Welp.
else
fingerprints[full_print] = stars(full_print, rand(40, 100)) // 0 to 21.
if(0 to 15)
if(prob(5))
fingerprints[full_print] = stars(full_print, rand(0,50)) // Small chance you can smudge.
else
fingerprints[full_print] = full_print
else
fingerprints[full_print] = stars(full_print, rand(0, 20)) // Initial touch, not leaving much evidence the first time.
return 1
else
// Smudge up the prints a bit.
if(fingerprintslast != M.key)
fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), M.real_name, M.key)
fingerprintslast = M.key
// Cleaning up.
if(fingerprints && !fingerprints.len)
qdel(fingerprints)
return
/atom/proc/transfer_fingerprints_to(var/atom/A)
if(!istype(A.fingerprints,/list))
A.fingerprints = list()
if(!istype(A.fingerprintshidden,/list))
A.fingerprintshidden = list()
if(!istype(fingerprintshidden, /list))
fingerprintshidden = list()
if(A.fingerprints && fingerprints)
A.fingerprints |= fingerprints.Copy() // Detective.
if(A.fingerprintshidden && fingerprintshidden)
A.fingerprintshidden |= fingerprintshidden.Copy() // Admin. (A.fingerprintslast = fingerprintslast)
// Returns 1 if made bloody, returns 0 otherwise.
/atom/proc/add_blood(mob/living/carbon/human/M)
if(flags & NOBLOODY)
return 0
if(!blood_DNA || !istype(blood_DNA, /list)) // If our list of DNA doesn't exist yet (or isn't a list), initialise it.
blood_DNA = list()
was_bloodied = 1
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()
if (M.species)
blood_color = M.species.blood_color
. = 1
return 1
// For any objects that may require additional handling when swabbed, e.g. a beaker may need to provide information about its contents, not just itself.
// Children must return additional_evidence list.
/atom/proc/get_additional_forensics_swab_info()
SHOULD_CALL_PARENT(TRUE)
var/list/additional_evidence = list(
"type" = "",
"dna" = list(),
"gsr" = "",
"sample_type" = "",
"sample_message" = ""
)
return additional_evidence
/atom/proc/add_vomit_floor(var/mob/living/carbon/M, var/toxvomit = 0, var/datum/reagents/inject_reagents)
if(istype(src, /turf/simulated))
var/obj/effect/decal/cleanable/vomit/this = new /obj/effect/decal/cleanable/vomit(src)
if(istype(inject_reagents) && inject_reagents.total_volume)
inject_reagents.trans_to_obj(this, min(15, inject_reagents.total_volume))
this.reagents.add_reagent(/singleton/reagent/acid/stomach, 5)
// Make toxins related vomit look different.
if(toxvomit)
this.icon_state = "vomittox_[pick(1,4)]"
/mob/living/proc/handle_additional_vomit_reagents(var/obj/effect/decal/cleanable/vomit/vomit)
vomit.reagents.add_reagent(/singleton/reagent/acid/stomach, 5)
/atom/proc/clean_blood()
if(!simulated)
return
fluorescent = 0
src.germ_level = 0
if(istype(blood_DNA, /list))
blood_DNA = null
return TRUE
/atom/proc/on_rag_wipe(var/obj/item/reagent_containers/glass/rag/R)
clean_blood()
R.reagents.splash(src, 1)
/atom/proc/get_global_map_pos()
if(!islist(global_map) || isemptylist(global_map)) return
var/cur_x = null
var/cur_y = null
var/list/y_arr = null
for(cur_x=1,cur_x<=global_map.len,cur_x++)
y_arr = global_map[cur_x]
cur_y = y_arr.Find(src.z)
if(cur_y)
break
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.
// The 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/range = world.view, var/intent_message = null, var/intent_range = 7)
set waitfor = FALSE
var/list/hearers = get_hearers_in_view(range, src)
for(var/atom/movable/AM as anything in hearers)
if(ismob(AM))
var/mob/M = AM
if(M.see_invisible < invisibility)
M.show_message(blind_message, 2)
continue
AM.show_message(message, 1, blind_message, 2)
if(intent_message)
intent_message(intent_message, intent_range, hearers) // pass our hearers list through to intent_message so it doesn't have to call get_hearers again
// 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/intent_message = null, var/intent_range = 7)
set waitfor = FALSE
if(!hearing_distance)
hearing_distance = world.view
var/list/hearers = get_hearers_in_view(hearing_distance, src)
for(var/atom/movable/AM as anything in hearers)
AM.show_message(message, 2, deaf_message, 1)
if(intent_message)
intent_message(intent_message, intent_range, hearers) // pass our hearers list through to intent_message so it doesn't have to call get_hearers again
/atom/proc/intent_message(var/message, var/range = 7, var/list/hearers = list())
set waitfor = FALSE
if(air_sound(src))
if(!hearers.len)
hearers = get_hearers_in_view(range, src)
for(var/mob/living/carbon/human/H as anything in intent_listener)
if(!(H in hearers))
if(src.z == H.z && get_dist(src, H) <= range)
H.intent_listen(src, message)
/atom/proc/change_area(var/area/oldarea, var/area/newarea)
change_area_name(oldarea.name, newarea.name)
/atom/proc/change_area_name(var/oldname, var/newname)
name = replacetext(name,oldname,newname)
/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 forceMove(null)
/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.
// This proc is used by ghost spawners to assign a player to a specific atom.
// It receives the current mob of the player's argument and MUST return the mob the player has been assigned.
/atom/proc/assign_player(var/mob/user)
return
/atom/proc/get_contained_external_atoms()
. = contents
/atom/proc/dump_contents()
for(var/thing in get_contained_external_atoms())
var/atom/movable/AM = thing
AM.dropInto(loc)
if(ismob(AM))
var/mob/M = AM
if(M.client)
M.client.eye = M.client.mob
M.client.perspective = MOB_PERSPECTIVE
/atom/proc/check_add_to_late_firers()
if(SSticker.current_state == GAME_STATE_PLAYING)
do_late_fire()
return
LAZYADD(SSatoms.late_misc_firers, src)
/atom/proc/do_late_fire()
return
/atom/proc/set_angle(degrees)
var/matrix/M = matrix()
M.Turn(degrees)
// If we aren't 0, make it NN transform.
if(degrees)
appearance_flags |= PIXEL_SCALE
transform = M
/atom/proc/handle_middle_mouse_click(var/mob/user)
return FALSE
/atom/proc/get_standard_pixel_x()
return initial(pixel_x)
/atom/proc/get_standard_pixel_y()
return initial(pixel_y)
/atom/proc/handle_pointed_at(var/mob/pointer)
return
/atom/proc/create_bullethole(obj/item/projectile/Proj)
var/p_x = Proj.p_x + rand(-6, 6)
var/p_y = Proj.p_y + rand(-6, 6)
var/obj/effect/overlay/bmark/bullet_mark = new(src)
bullet_mark.pixel_x = p_x
bullet_mark.pixel_y = p_y
//Offset correction
bullet_mark.pixel_x--
bullet_mark.pixel_y--
if(Proj.damage_flags & DAMAGE_FLAG_BULLET)
bullet_mark.icon_state = "dent"
else if(Proj.damage_flags & DAMAGE_FLAG_LASER)
bullet_mark.name = "scorch mark"
if(Proj.damage >= 20)
bullet_mark.icon_state = "scorch"
bullet_mark.set_dir(pick(NORTH,SOUTH,EAST,WEST)) // Pick random scorch design
else
bullet_mark.icon_state = "light_scorch"
/atom/proc/clear_bulletholes()
for(var/obj/effect/overlay/bmark/bullet_mark in src)
qdel(bullet_mark)