mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-21 11:07:12 +01:00
This commit ports /tg/'s move refactor. The throwing system has been replaced entirely, removing the necessity of throw_at_fast and resolving multiple outstanding issues, such as crossbows being unusable. Spacedrifting has also been upgraded to function with the new throwing system. It is now it's own process. Tickcomp has been killed, and the config values have been adjusted to more or less match live Paradise. All mobs now share a common Bump() proc. There are only four mobtypes which do not, including humans and simple animals. With the exception of mob types that do not ever want to Bump() or be Bumped(), they should call the parent proc. Human movement slowdown has been moderately tweaked in how it stacks effects; It shouldn't be significantly different from a player perspective. Mobs will now spread fire if they bump into another mob. I don't want to set the world on fiiiire, I just want start a flame in your heart~ For player facing changes: Input delay has been reduced by roughly ~50ms for any direction keys, by advantage of a previously unknown flag on byond verbs which allow them to operate independently from the tick rate of the server. You may need to clear your interface.dmf file if you have a custom skin for this change to function.
472 lines
13 KiB
Plaintext
472 lines
13 KiB
Plaintext
/atom
|
|
layer = 2
|
|
var/level = 2
|
|
var/flags = 0
|
|
var/list/fingerprints
|
|
var/list/fingerprintshidden
|
|
var/fingerprintslast = null
|
|
var/list/blood_DNA
|
|
var/blood_color
|
|
var/last_bumped = 0
|
|
var/pass_flags = 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/atom_say_verb = "says"
|
|
var/dont_save = 0 // For atoms that are temporary by necessity - like lighting overlays
|
|
|
|
///Chemistry.
|
|
var/datum/reagents/reagents = null
|
|
|
|
//This atom's HUD (med/sec, etc) images. Associative list.
|
|
var/list/image/hud_list = list()
|
|
//HUD images that this atom can provide.
|
|
var/list/hud_possible
|
|
|
|
|
|
//var/chem_is_open_container = 0
|
|
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
|
|
///Chemistry.
|
|
|
|
|
|
//Value used to increment ex_act() if reactionary_explosions is on
|
|
var/explosion_block = 0
|
|
|
|
//Detective Work, used for the duplicate data points kept in the scanners
|
|
var/list/original_atom
|
|
|
|
var/allow_spin = 1 //Set this to 1 for a _target_ that is being thrown at; if an atom has this set to 1 then atoms thrown AT it will not spin; currently used for the singularity. -Fox
|
|
|
|
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
|
|
|
|
/atom/proc/onCentcom()
|
|
var/turf/T = get_turf(src)
|
|
if(!T)
|
|
return 0
|
|
|
|
if(!is_admin_level(T.z))//if not, don't bother
|
|
return 0
|
|
|
|
//check for centcomm shuttles
|
|
for(var/centcom_shuttle in list("emergency", "pod1", "pod2", "pod3", "pod4", "ferry"))
|
|
var/obj/docking_port/mobile/M = shuttle_master.getShuttle(centcom_shuttle)
|
|
if(T in M.areaInstance)
|
|
return 1
|
|
|
|
//finally check for centcom itself
|
|
return istype(T.loc,/area/centcom)
|
|
|
|
/atom/proc/onSyndieBase()
|
|
var/turf/T = get_turf(src)
|
|
if(!T)
|
|
return 0
|
|
|
|
if(!is_admin_level(T.z))//if not, don't bother
|
|
return 0
|
|
|
|
if(istype(T.loc, /area/shuttle/syndicate_elite) || istype(T.loc, /area/syndicate_mothership))
|
|
return 1
|
|
|
|
return 0
|
|
|
|
/atom/Destroy()
|
|
if(alternate_appearances)
|
|
for(var/aakey in alternate_appearances)
|
|
var/datum/alternate_appearance/AA = alternate_appearances[aakey]
|
|
qdel(AA)
|
|
alternate_appearances = null
|
|
|
|
QDEL_NULL(reagents)
|
|
invisibility = 101
|
|
return ..()
|
|
|
|
//Hook for running code when a dir change occurs
|
|
/atom/proc/setDir(newdir)
|
|
dir = newdir
|
|
|
|
/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(istype(A, /atom/movable))
|
|
var/atom/movable/M = A
|
|
if(istype(M.loc, /mob/living))
|
|
var/mob/living/L = M.loc
|
|
L.unEquip(M)
|
|
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(user as mob)
|
|
if(istype(user, /mob/living/silicon/ai)) // WHYYYY
|
|
return 1
|
|
return
|
|
|
|
/atom/proc/on_reagent_change()
|
|
return
|
|
|
|
/atom/proc/Bumped(AM as mob|obj)
|
|
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
|
|
|
|
/*//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
|
|
*/
|
|
|
|
|
|
|
|
/atom/proc/allow_drop()
|
|
return 1
|
|
|
|
/atom/proc/CheckExit()
|
|
return 1
|
|
|
|
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
|
|
return
|
|
|
|
/atom/proc/emp_act(var/severity)
|
|
return
|
|
|
|
/atom/proc/bullet_act(var/obj/item/projectile/Proj, def_zone)
|
|
Proj.on_hit(src, 0, def_zone)
|
|
return 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
|
|
|
|
/*
|
|
* 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
|
|
|
|
|
|
//All atoms
|
|
/atom/proc/examine(mob/user, var/distance = -1, var/infix = "", var/suffix = "")
|
|
//This reformat names to get a/an properly working on item descriptions when they are bloody
|
|
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, "[bicon(src)] That's [f_name] [suffix]")
|
|
if(desc)
|
|
to_chat(user, desc)
|
|
|
|
if(reagents && is_open_container()) //is_open_container() isn't really the right proc for this, but w/e
|
|
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
|
|
if(reagents && reagents.reagent_list.len)
|
|
to_chat(user, "[reagents.total_volume] units of various reagents.")
|
|
else
|
|
to_chat(user, "Nothing.")
|
|
|
|
return distance == -1 || (get_dist(src, user) <= distance) || isobserver(user) //observers do not have a range limit
|
|
|
|
/atom/proc/relaymove()
|
|
return
|
|
|
|
/atom/proc/ex_act()
|
|
return
|
|
|
|
/atom/proc/blob_act()
|
|
return
|
|
|
|
/atom/proc/fire_act()
|
|
return
|
|
|
|
/atom/proc/emag_act()
|
|
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(src, "hitby_react", 2, TRUE, AM)
|
|
|
|
/atom/proc/hitby_react(atom/movable/AM)
|
|
if(AM && isturf(AM.loc))
|
|
step(AM, turn(AM.dir, 180))
|
|
|
|
/atom/proc/add_hiddenprint(mob/living/M as mob)
|
|
if(isnull(M)) 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(fingerprintslast != H.ckey)
|
|
//Add the list if it does not exist.
|
|
if(!fingerprintshidden)
|
|
fingerprintshidden = list()
|
|
fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key)
|
|
fingerprintslast = H.ckey
|
|
return 0
|
|
if(!( fingerprints ))
|
|
if(fingerprintslast != H.ckey)
|
|
//Add the list if it does not exist.
|
|
if(!fingerprintshidden)
|
|
fingerprintshidden = list()
|
|
fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",H.real_name, H.key)
|
|
fingerprintslast = H.ckey
|
|
return 1
|
|
else
|
|
if(fingerprintslast != M.ckey)
|
|
//Add the list if it does not exist.
|
|
if(!fingerprintshidden)
|
|
fingerprintshidden = list()
|
|
fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",M.real_name, M.key)
|
|
fingerprintslast = M.ckey
|
|
return
|
|
|
|
|
|
//Set ignoregloves to add prints irrespective of the mob having gloves on.
|
|
/atom/proc/add_fingerprint(mob/living/M as mob, ignoregloves = 0)
|
|
if(isnull(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)
|
|
|
|
//He has no prints!
|
|
if(FINGERPRINTS in M.mutations)
|
|
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()
|
|
|
|
//Check if the gloves (if any) hide fingerprints
|
|
if(H.gloves)
|
|
var/obj/item/clothing/gloves/G = H.gloves
|
|
if(G.transfer_prints)
|
|
ignoregloves = 1
|
|
|
|
//Now, deal with gloves.
|
|
if(!ignoregloves)
|
|
if(H.gloves && H.gloves != src)
|
|
if(fingerprintslast != H.ckey)
|
|
fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []",time_stamp(), H.real_name, H.key)
|
|
fingerprintslast = H.ckey
|
|
H.gloves.add_fingerprint(M)
|
|
return 0
|
|
|
|
//More adminstuffz
|
|
if(fingerprintslast != H.ckey)
|
|
fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), H.real_name, H.key)
|
|
fingerprintslast = H.ckey
|
|
|
|
//Make the list if it does not exist.
|
|
if(!fingerprints)
|
|
fingerprints = list()
|
|
|
|
//Hash this shit.
|
|
var/full_print = H.get_full_print()
|
|
|
|
// Add the fingerprints
|
|
fingerprints[full_print] = full_print
|
|
|
|
return 1
|
|
else
|
|
//Smudge up dem prints some
|
|
if(fingerprintslast != M.ckey)
|
|
fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), M.real_name, M.key)
|
|
fingerprintslast = M.ckey
|
|
|
|
return
|
|
|
|
|
|
/atom/proc/transfer_fingerprints_to(var/atom/A)
|
|
|
|
// Make sure everything are lists.
|
|
if(!islist(A.fingerprints))
|
|
A.fingerprints = list()
|
|
if(!islist(A.fingerprintshidden))
|
|
A.fingerprintshidden = list()
|
|
|
|
if(!islist(fingerprints))
|
|
fingerprints = list()
|
|
if(!islist(fingerprintshidden))
|
|
fingerprintshidden = list()
|
|
|
|
// Transfer
|
|
if(fingerprints)
|
|
A.fingerprints |= fingerprints.Copy() //detective
|
|
if(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 as mob)
|
|
|
|
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()
|
|
|
|
blood_color = "#A10808"
|
|
if(istype(M))
|
|
if(M.species.flags & NO_BLOOD)
|
|
return 0
|
|
M.check_dna()
|
|
blood_color = M.species.blood_color
|
|
|
|
. = 1
|
|
return 1
|
|
|
|
/atom/proc/add_blood_list(mob/living/carbon/M)
|
|
// Returns 0 if we have that blood already
|
|
if(!istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
|
|
blood_DNA = list()
|
|
//if this blood isn't already in the list, add it
|
|
if(blood_DNA[M.dna.unique_enzymes])
|
|
return 0 //already bloodied with this blood. Cannot add more.
|
|
var/blood_type = "X*"
|
|
if(ishuman(M))
|
|
var/mob/living/carbon/human/H = M
|
|
blood_type = H.b_type
|
|
blood_DNA[M.dna.unique_enzymes] = blood_type
|
|
return 1
|
|
|
|
// Only adds blood on the floor -- Skie
|
|
/atom/proc/add_blood_floor(mob/living/carbon/M)
|
|
return //why the fuck this is at an atom level but only works on simulated turfs I don't know
|
|
|
|
/atom/proc/clean_blood()
|
|
src.germ_level = 0
|
|
if(istype(blood_DNA, /list))
|
|
qdel(blood_DNA)
|
|
return 1
|
|
|
|
/atom/proc/add_vomit_floor(mob/living/carbon/M as mob, var/toxvomit = 0)
|
|
if( istype(src, /turf/simulated) )
|
|
var/obj/effect/decal/cleanable/vomit/this = new /obj/effect/decal/cleanable/vomit(src)
|
|
|
|
// Make toxins vomit look different
|
|
if(toxvomit)
|
|
this.icon_state = "vomittox_[pick(1,4)]"
|
|
|
|
|
|
/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
|
|
// to_chat(world, "X = [cur_x]; Y = [cur_y]")
|
|
if(cur_x && cur_y)
|
|
return list("x"=cur_x,"y"=cur_y)
|
|
else
|
|
return 0
|
|
|
|
// Used to provide overlays when using this atom as a viewing focus
|
|
// (cameras, locker tint, etc.)
|
|
/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
|
|
|
|
/atom/proc/checkpass(passflag)
|
|
return pass_flags&passflag
|
|
|
|
/atom/proc/isinspace()
|
|
if(istype(get_turf(src), /turf/space))
|
|
return 1
|
|
else
|
|
return 0
|
|
|
|
/atom/proc/handle_fall()
|
|
return
|
|
|
|
/atom/proc/singularity_act()
|
|
return
|
|
|
|
/atom/proc/singularity_pull()
|
|
return
|
|
|
|
/atom/proc/narsie_act()
|
|
return
|
|
|
|
/atom/proc/atom_say(message)
|
|
if(!message)
|
|
return
|
|
audible_message("<span class='game say'><span class='name'>[src]</span> [atom_say_verb], \"[message]\"</span>")
|
|
|
|
/atom/proc/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
|
|
return
|
|
|
|
/atom/on_varedit(modified_var)
|
|
if(!Debug2)
|
|
admin_spawned = TRUE
|
|
..() |