/atom layer = TURF_LAYER plane = GAME_PLANE var/level = 2 var/article // If non-null, overrides a/an/some in all cases var/flags_1 = NONE var/interaction_flags_atom = NONE var/container_type = NONE var/datum/reagents/reagents = null //This atom's HUD (med/sec, etc) images. Associative list. var/list/image/hud_list = null //HUD images that this atom can provide. var/list/hud_possible //Value used to increment ex_act() if reactionary_explosions is on var/explosion_block = 0 var/list/atom_colours //used to store the different colors on an atom //its inherent color, the colored paint applied on it, special color effect etc... var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. var/list/remove_overlays // a very temporary list of overlays to remove var/list/add_overlays // a very temporary list of overlays to add var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays var/datum/proximity_monitor/proximity_monitor var/buckle_message_cooldown = 0 var/fingerprintslast var/list/filter_data //For handling persistent filters var/rad_flags = NONE // Will move to flags_1 when i can be arsed to var/rad_insulation = RAD_NO_INSULATION /atom/New(loc, ...) //atom creation method that preloads variables at creation if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() GLOB._preloader.load(src) if(datum_flags & DF_USE_TAG) GenerateTag() var/do_initialize = SSatoms.initialized if(do_initialize != INITIALIZATION_INSSATOMS) args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD if(SSatoms.InitAtom(src, args)) //we were deleted return //Called after New if the map is being loaded. mapload = TRUE //Called from base of New if the map is not being loaded. mapload = FALSE //This base must be called or derivatives must set initialized to TRUE //must not sleep //Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE //Must return an Initialize hint. Defined in __DEFINES/subsystems.dm //Note: the following functions don't call the base for optimization and must copypasta: // /turf/Initialize // /turf/open/space/Initialize /atom/proc/Initialize(mapload, ...) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 //atom color stuff if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) if (light_power && light_range) update_light() if (opacity && isturf(loc)) var/turf/T = loc T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways. if (canSmoothWith) canSmoothWith = typelist("canSmoothWith", canSmoothWith) ComponentInitialize() return INITIALIZE_HINT_NORMAL //called if Initialize returns INITIALIZE_HINT_LATELOAD /atom/proc/LateInitialize() return // Put your AddComponent() calls here /atom/proc/ComponentInitialize() return /atom/Destroy() if(alternate_appearances) for(var/K in alternate_appearances) var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] AA.remove_from_hud(src) if(reagents) qdel(reagents) LAZYCLEARLIST(overlays) LAZYCLEARLIST(priority_overlays) QDEL_NULL(light) return ..() /atom/proc/handle_ricochet(obj/item/projectile/P) return /atom/proc/CanPass(atom/movable/mover, turf/target) return !density /atom/proc/onCentCom() var/turf/T = get_turf(src) if(!T) return FALSE if(is_reserved_level(T.z)) for(var/A in SSshuttle.mobile) var/obj/docking_port/mobile/M = A if(M.launch_status == ENDGAME_TRANSIT) for(var/place in M.shuttle_areas) var/area/shuttle/shuttle_area = place if(T in shuttle_area) return TRUE if(!is_centcom_level(T.z))//if not, don't bother return FALSE //Check for centcom itself if(istype(T.loc, /area/centcom)) return TRUE //Check for centcom shuttles for(var/A in SSshuttle.mobile) var/obj/docking_port/mobile/M = A if(M.launch_status == ENDGAME_LAUNCHED) for(var/place in M.shuttle_areas) var/area/shuttle/shuttle_area = place if(T in shuttle_area) return TRUE /atom/proc/onSyndieBase() var/turf/T = get_turf(src) if(!T) return FALSE if(!is_centcom_level(T.z))//if not, don't bother return FALSE if(istype(T.loc, /area/shuttle/syndicate) || istype(T.loc, /area/syndicate_mothership) || istype(T.loc, /area/shuttle/assault_pod)) return TRUE return FALSE /atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0) SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user) if(does_attack_animation) user.changeNext_move(CLICK_CD_MELEE) log_combat(user, src, "punched", "hulk powers") user.do_attack_animation(src, ATTACK_EFFECT_SMASH) /atom/proc/CheckParts(list/parts_list) for(var/A in parts_list) if(istype(A, /datum/reagent)) if(!reagents) reagents = new() reagents.reagent_list.Add(A) reagents.conditional_update() else if(ismovableatom(A)) var/atom/movable/M = A if(isliving(M.loc)) var/mob/living/L = M.loc L.transferItemToLoc(M, src) else M.forceMove(src) /atom/proc/assume_air(datum/gas_mixture/giver) qdel(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/check_eye(mob/user) return /atom/proc/Bumped(atom/movable/AM) set waitfor = FALSE // Convenience procs to see if a container is open for chemistry handling /atom/proc/is_open_container() return is_refillable() && is_drainable() /atom/proc/is_injectable(allowmobs = TRUE) return reagents && (container_type & (INJECTABLE | REFILLABLE)) /atom/proc/is_drawable(allowmobs = TRUE) return reagents && (container_type & (DRAWABLE | DRAINABLE)) /atom/proc/is_refillable() return reagents && (container_type & REFILLABLE) /atom/proc/is_drainable() return reagents && (container_type & DRAINABLE) /atom/proc/AllowDrop() return FALSE /atom/proc/CheckExit() return 1 /atom/proc/HasProximity(atom/movable/AM as mob|obj) return /atom/proc/emp_act(severity) var/protection = SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) if(!(protection & EMP_PROTECT_WIRES) && istype(wires)) wires.emp_pulse() return protection // Pass the protection value collected here upwards /atom/proc/bullet_act(obj/item/projectile/P, def_zone) SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) . = P.on_hit(src, 0, def_zone) /atom/proc/in_contents_of(container)//can take class or object instance as argument if(ispath(container)) if(istype(src.loc, container)) return TRUE else if(src in container) return TRUE return FALSE /atom/proc/get_examine_name(mob/user) . = "\a [src]" var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]") if(article) . = "[article] [src]" override[EXAMINE_POSITION_ARTICLE] = article if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED) . = override.Join("") /atom/proc/get_examine_string(mob/user, thats = FALSE) . = "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]" /atom/proc/examine(mob/user) to_chat(user, get_examine_string(user, TRUE)) if(desc) to_chat(user, desc) if(reagents) if(container_type & TRANSPARENT) to_chat(user, "It contains:") if(reagents.reagent_list.len) if(user.can_see_reagents()) //Show each individual reagent for(var/datum/reagent/R in reagents.reagent_list) to_chat(user, "[R.volume] units of [R.name]") else //Otherwise, just show the total volume var/total_volume = 0 for(var/datum/reagent/R in reagents.reagent_list) total_volume += R.volume to_chat(user, "[total_volume] units of various reagents") else to_chat(user, "Nothing.") else if(container_type & AMOUNT_VISIBLE) if(reagents.total_volume) to_chat(user, "It has [reagents.total_volume] unit\s left.") else to_chat(user, "It's empty.") SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user) /atom/proc/relaymove(mob/user) if(buckle_message_cooldown <= world.time) buckle_message_cooldown = world.time + 50 to_chat(user, "You can't move while buckled to [src]!") return /atom/proc/contents_explosion(severity, target) return /atom/proc/ex_act(severity, target) set waitfor = FALSE contents_explosion(severity, target) SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target) /atom/proc/blob_act(obj/structure/blob/B) SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, B) return /atom/proc/fire_act(exposed_temperature, exposed_volume) SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume) return /atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked) if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). addtimer(CALLBACK(src, .proc/hitby_react, AM), 2) /atom/proc/hitby_react(atom/movable/AM) if(AM && isturf(AM.loc)) step(AM, turn(AM.dir, 180)) /atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube) return //returns the mob's dna info as a list, to be inserted in an object's blood_DNA list /mob/living/proc/get_blood_dna_list() if(get_blood_id() != "blood") return return list("ANIMAL DNA" = "Y-") /mob/living/carbon/get_blood_dna_list() if(get_blood_id() != "blood") return var/list/blood_dna = list() if(dna) blood_dna[dna.unique_enzymes] = dna.blood_type else blood_dna["UNKNOWN DNA"] = "X*" return blood_dna /mob/living/carbon/alien/get_blood_dna_list() return list("UNKNOWN DNA" = "X*") //to add a mob's dna info into an object's blood_DNA list. /atom/proc/transfer_mob_blood_dna(mob/living/L) // Returns 0 if we have that blood already var/new_blood_dna = L.get_blood_dna_list() if(!new_blood_dna) return FALSE var/old_length = blood_DNA_length() add_blood_DNA(new_blood_dna) if(blood_DNA_length() == old_length) return FALSE return TRUE //to add blood from a mob onto something, and transfer their dna info /atom/proc/add_mob_blood(mob/living/M) var/list/blood_dna = M.get_blood_dna_list() if(!blood_dna) return FALSE return add_blood_DNA(blood_dna) /atom/proc/wash_cream() return TRUE /atom/proc/isinspace() if(isspaceturf(get_turf(src))) return TRUE else return FALSE /atom/proc/handle_fall() return /atom/proc/singularity_act() return /atom/proc/singularity_pull(obj/singularity/S, current_size) SEND_SIGNAL(src, COMSIG_ATOM_SING_PULL, S, current_size) /atom/proc/acid_act(acidpwr, acid_volume) SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume) /atom/proc/emag_act() SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) /atom/proc/rad_act(strength) SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength) /atom/proc/narsie_act() SEND_SIGNAL(src, COMSIG_ATOM_NARSIE_ACT) /atom/proc/ratvar_act() SEND_SIGNAL(src, COMSIG_ATOM_RATVAR_ACT) /atom/proc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) return FALSE /atom/proc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode) return FALSE /atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user) if(GetComponent(/datum/component/storage)) return component_storage_contents_dump_act(src_object, user) return FALSE /atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user) var/list/things = src_object.contents() var/datum/progressbar/progress = new(user, things.len, src) GET_COMPONENT(STR, /datum/component/storage) while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress))) stoplag(1) qdel(progress) to_chat(user, "You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.") STR.orient2hud(user) src_object.orient2hud(user) if(user.active_storage) //refresh the HUD to show the transfered contents user.active_storage.close(user) user.active_storage.show_to(user) return TRUE /atom/proc/get_dumping_location(obj/item/storage/source,mob/user) return null //This proc is called on the location of an atom when the atom is Destroy()'d /atom/proc/handle_atom_del(atom/A) SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, A) //called when the turf the atom resides on is ChangeTurfed /atom/proc/HandleTurfChange(turf/T) for(var/a in src) var/atom/A = a A.HandleTurfChange(T) //the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it) /atom/proc/get_remote_view_fullscreens(mob/user) return //the sight changes to give to the mob whose perspective is set to that atom (e.g. A mob with nightvision loses its nightvision while looking through a normal camera) /atom/proc/update_remote_sight(mob/living/user) return //Hook for running code when a dir change occurs /atom/proc/setDir(newdir) SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) dir = newdir /atom/proc/mech_melee_attack(obj/mecha/M) return //If a mob logouts/logins in side of an object you can use this proc /atom/proc/on_log(login) if(loc) loc.on_log(login) /* 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 /atom/vv_edit_var(var_name, var_value) if(!GLOB.Debug2) flags_1 |= ADMIN_SPAWNED_1 . = ..() switch(var_name) if("color") add_atom_colour(color, ADMIN_COLOUR_PRIORITY) /atom/vv_get_dropdown() . = ..() . += "---" var/turf/curturf = get_turf(src) if (curturf) .["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" .["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]" .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]" .["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]" .["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]" /atom/proc/drop_location() var/atom/L = loc if(!L) return null return L.AllowDrop() ? L : get_turf(L) /atom/Entered(atom/movable/AM, atom/oldLoc) SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc) /atom/Exit(atom/movable/AM, atom/newLoc) . = ..() if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, newLoc) & COMPONENT_ATOM_BLOCK_EXIT) return FALSE /atom/Exited(atom/movable/AM, atom/newLoc) SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, newLoc) /atom/proc/return_temperature() return // Tool behavior procedure. Redirects to tool-specific procs by default. // You can override it to catch all tool interactions, for use in complex deconstruction procs. // Just don't forget to return ..() in the end. /atom/proc/tool_act(mob/living/user, obj/item/I, tool_type) switch(tool_type) if(TOOL_CROWBAR) return crowbar_act(user, I) if(TOOL_MULTITOOL) return multitool_act(user, I) if(TOOL_SCREWDRIVER) return screwdriver_act(user, I) if(TOOL_WRENCH) return wrench_act(user, I) if(TOOL_WIRECUTTER) return wirecutter_act(user, I) if(TOOL_WELDER) return welder_act(user, I) if(TOOL_ANALYZER) return analyzer_act(user, I) // Tool-specific behavior procs. To be overridden in subtypes. /atom/proc/crowbar_act(mob/living/user, obj/item/I) return /atom/proc/multitool_act(mob/living/user, obj/item/I) return /atom/proc/screwdriver_act(mob/living/user, obj/item/I) SEND_SIGNAL(src, COMSIG_ATOM_SCREWDRIVER_ACT, user, I) /atom/proc/wrench_act(mob/living/user, obj/item/I) return /atom/proc/wirecutter_act(mob/living/user, obj/item/I) return /atom/proc/welder_act(mob/living/user, obj/item/I) return /atom/proc/analyzer_act(mob/living/user, obj/item/I) return /atom/proc/GenerateTag() return // Generic logging helper /atom/proc/log_message(message, message_type, color=null, log_globally=TRUE) if(!log_globally) return var/log_text = "[key_name(src)] [message] [loc_name(src)]" switch(message_type) if(LOG_ATTACK) log_attack(log_text) if(LOG_SAY) log_say(log_text) if(LOG_WHISPER) log_whisper(log_text) if(LOG_EMOTE) log_emote(log_text) if(LOG_DSAY) log_dsay(log_text) if(LOG_PDA) log_pda(log_text) if(LOG_CHAT) log_chat(log_text) if(LOG_COMMENT) log_comment(log_text) if(LOG_TELECOMMS) log_telecomms(log_text) if(LOG_OOC) log_ooc(log_text) if(LOG_ADMIN) log_admin(log_text) if(LOG_ADMIN_PRIVATE) log_admin_private(log_text) if(LOG_ASAY) log_adminsay(log_text) if(LOG_OWNERSHIP) log_game(log_text) if(LOG_GAME) log_game(log_text) else stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).") log_game(log_text) // Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements) /atom/proc/log_talk(message, message_type, tag=null, log_globally=TRUE, forced_by=null) var/prefix = tag ? "([tag]) " : "" var/suffix = forced_by ? " FORCED by [forced_by]" : "" log_message("[prefix]\"[message]\"[suffix]", message_type, log_globally=log_globally) // Helper for logging of messages with only one sender and receiver /proc/log_directed_talk(atom/source, atom/target, message, message_type, tag) if(!tag) stack_trace("Unspecified tag for private message") tag = "UNKNOWN" source.log_talk(message, message_type, tag="[tag] to [key_name(target)]") if(source != target) target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE) /* Proc for attack log creation, because really why not 1 argument is the actor performing the action 2 argument is the target of the action 3 is a verb describing the action (e.g. punched, throwed, kicked, etc.) 4 is a tool with which the action was made (usually an item) 5 is any additional text, which will be appended to the rest of the log line */ /proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null) var/ssource = key_name(user) var/starget = key_name(target) var/mob/living/living_target = target var/hp = istype(living_target) ? " (NEWHP: [living_target.health]) " : "" var/sobject = "" if(object) sobject = " with [key_name(object)]" var/saddition = "" if(addition) saddition = " [addition]" var/postfix = "[sobject][saddition][hp]" var/message = "has [what_done] [starget][postfix]" user.log_message(message, LOG_ATTACK, color="red") if(user != target) var/reverse_message = "has been [what_done] by [ssource][postfix]" target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE) // Filter stuff /atom/movable/proc/add_filter(name,priority,list/params) if(!filter_data) filter_data = list() var/list/p = params.Copy() p["priority"] = priority filter_data[name] = p update_filters() /atom/movable/proc/update_filters() filters = null sortTim(filter_data,associative = TRUE) for(var/f in filter_data) var/list/data = filter_data[f] var/list/arguments = data.Copy() arguments -= "priority" filters += filter(arglist(arguments)) /atom/movable/proc/get_filter(name) if(filter_data && filter_data[name]) return filters[filter_data.Find(name)] /atom/movable/proc/remove_filter(name) if(filter_data[name]) filter_data -= name update_filters() return TRUE