mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 07:08:00 +01:00
Merge pull request #16586 from RemieRichards/alternate_appearances
Adds a framework for alternate appearances (override images)
This commit is contained in:
@@ -12,3 +12,4 @@ var/global/list/mob_list = list() //all mobs, including clientless
|
||||
var/global/list/living_mob_list = list() //all alive mobs, including clientless. Excludes /mob/new_player
|
||||
var/global/list/dead_mob_list = list() //all dead mobs, including clientless. Excludes /mob/new_player
|
||||
var/global/list/joined_player_list = list() //all clients that have joined the game at round-start or as a latejoin.
|
||||
var/global/list/silicon_mobs = list() //all silicon mobs
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Alternate Appearances! By RemieRichards
|
||||
A framework for replacing an atom (and it's overlays) with an override = 1 image, that's less shit!
|
||||
Example uses:
|
||||
* hallucinating all mobs looking like skeletons
|
||||
* people wearing cardborg suits appearing as Standard Cyborgs to the other Silicons
|
||||
* !!use your imagination!!
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//This datum is built on-the-fly by some of the procs below
|
||||
//no need to instantiate it
|
||||
/datum/alternate_appearance
|
||||
var/key = ""
|
||||
var/image/img
|
||||
var/list/viewers = list()
|
||||
var/atom/owner = null
|
||||
|
||||
|
||||
/*
|
||||
Displays the alternate_appearance
|
||||
displayTo - a list of MOBS to show this appearance to
|
||||
*/
|
||||
/datum/alternate_appearance/proc/display_to(list/displayTo)
|
||||
if(!displayTo || !displayTo.len)
|
||||
return
|
||||
for(var/m in displayTo)
|
||||
var/mob/M = m
|
||||
if(!M.viewing_alternate_appearances)
|
||||
M.viewing_alternate_appearances = list()
|
||||
viewers |= M
|
||||
M.viewing_alternate_appearances[key] = src
|
||||
if(M.client)
|
||||
M.client.images |= img
|
||||
|
||||
/*
|
||||
Hides the alternate_appearance
|
||||
hideFrom - optional list of MOBS to hide it from the list's mobs specifically
|
||||
*/
|
||||
/datum/alternate_appearance/proc/hide(list/hideFrom)
|
||||
var/list/hiding = viewers
|
||||
if(hideFrom)
|
||||
hiding = hideFrom
|
||||
|
||||
for(var/m in hiding)
|
||||
var/mob/M = m
|
||||
if(M.client)
|
||||
M.client.images -= img
|
||||
if(M.viewing_alternate_appearances && M.viewing_alternate_appearances.len)
|
||||
M.viewing_alternate_appearances -= key
|
||||
if(!M.viewing_alternate_appearances.len)
|
||||
M.viewing_alternate_appearances = null
|
||||
viewers -= M
|
||||
|
||||
|
||||
/*
|
||||
Removes the alternate_appearance from its owner's alternate_appearances list, hiding it also
|
||||
*/
|
||||
/datum/alternate_appearance/proc/remove()
|
||||
hide()
|
||||
if(owner && owner.alternate_appearances)
|
||||
owner.alternate_appearances -= key
|
||||
if(!owner.alternate_appearances.len)
|
||||
owner.alternate_appearances = null
|
||||
|
||||
|
||||
/datum/alternate_appearance/Destroy()
|
||||
remove()
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
/atom
|
||||
var/list/alternate_appearances //the alternate appearances we own
|
||||
var/list/viewing_alternate_appearances //the alternate appearances we're viewing, stored here to reestablish them after Logout()s
|
||||
//these lists are built/destroyed as necessary, so atoms aren't all lugging around lists full of datums
|
||||
|
||||
/*
|
||||
Builds an alternate_appearance datum for the supplied args, optionally displaying it straight away
|
||||
key - the key to the assoc list of key = /datum/alternate_appearances
|
||||
img - the image file to be the "alternate appearance"
|
||||
WORKS BEST IF:
|
||||
* it has override = 1 set
|
||||
* the image's loc is the atom that will use the appearance (otherwise... it's not exactly an alt appearance of this atom is it?)
|
||||
displayTo - optional list of MOBS to display to immediately
|
||||
|
||||
Example:
|
||||
var/image/I = image(icon = 'disguise.dmi', icon_state = "disguise", loc = src)
|
||||
I.override = 1
|
||||
add_alt_appearance("super_secret_disguise", I, players)
|
||||
|
||||
*/
|
||||
/atom/proc/add_alt_appearance(key, img, list/displayTo = list())
|
||||
if(!key || !img)
|
||||
return
|
||||
if(!alternate_appearances)
|
||||
alternate_appearances = list()
|
||||
|
||||
var/datum/alternate_appearance/AA = new()
|
||||
AA.img = img
|
||||
AA.key = key
|
||||
AA.owner = src
|
||||
|
||||
alternate_appearances[key] = AA
|
||||
if(displayTo && displayTo.len)
|
||||
display_alt_appearance(key, displayTo)
|
||||
|
||||
|
||||
//////////////
|
||||
// WRAPPERS //
|
||||
//////////////
|
||||
|
||||
/*
|
||||
Removes an alternate_appearance from src's alternate_appearances list
|
||||
Wrapper for: alternate_appearance/remove()
|
||||
key - the key to the assoc list of key = /datum/alternate_appearance
|
||||
*/
|
||||
/atom/proc/remove_alt_appearance(key)
|
||||
if(alternate_appearances)
|
||||
if(alternate_appearances[key])
|
||||
var/datum/alternate_appearance/AA = alternate_appearances[key]
|
||||
qdel(AA)
|
||||
|
||||
|
||||
/*
|
||||
Displays an alternate appearance from src's alternate_appearances list
|
||||
Wrapper for: alternate_appearance/display_to()
|
||||
key - the key to the assoc list of key = /datum/alternate_appearance
|
||||
displayTo - a list of MOBS to show this appearance to
|
||||
*/
|
||||
/atom/proc/display_alt_appearance(key, list/displayTo)
|
||||
if(!alternate_appearances || !key)
|
||||
return
|
||||
var/datum/alternate_appearance/AA = alternate_appearances[key]
|
||||
if(!AA || !AA.img)
|
||||
return
|
||||
AA.display_to(displayTo)
|
||||
|
||||
|
||||
/*
|
||||
Hides an alternate appearance from src's alternate_appearances list
|
||||
Wrapper for: alternate_appearance/hide()
|
||||
key - the key to the assoc list of key = /datum/alternate_appearance
|
||||
hideFrom - optional list of MOBS to hide it from the list's mobs specifically
|
||||
*/
|
||||
/atom/proc/hide_alt_appearance(key, list/hideFrom)
|
||||
if(!alternate_appearances || !key)
|
||||
return
|
||||
var/datum/alternate_appearance/AA = alternate_appearances[key]
|
||||
if(!AA)
|
||||
return
|
||||
AA.hide(hideFrom)
|
||||
|
||||
|
||||
+404
-393
@@ -1,393 +1,404 @@
|
||||
/atom
|
||||
layer = 2
|
||||
var/level = 2
|
||||
var/flags = 0
|
||||
var/list/fingerprints
|
||||
var/list/fingerprintshidden
|
||||
var/fingerprintslast = null
|
||||
var/list/blood_DNA
|
||||
|
||||
///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
|
||||
|
||||
//Value used to increment ex_act() if reactionary_explosions is on
|
||||
var/explosion_block = 0
|
||||
|
||||
/atom/proc/onCentcom()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return 0
|
||||
|
||||
if(T.z != ZLEVEL_CENTCOM)//if not, don't bother
|
||||
return 0
|
||||
|
||||
//check for centcomm shuttles
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == ENDGAME_LAUNCHED && 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(T.z != ZLEVEL_CENTCOM)//if not, don't bother
|
||||
return 0
|
||||
|
||||
if(istype(T.loc,/area/shuttle/syndicate) || istype(T.loc,/area/syndicate_mothership))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0)
|
||||
if(do_attack_animation)
|
||||
hulk.changeNext_move(CLICK_CD_MELEE)
|
||||
add_logs(hulk, src, "punched", "hulk powers")
|
||||
hulk.do_attack_animation(src)
|
||||
return
|
||||
|
||||
/atom/proc/CheckParts()
|
||||
return
|
||||
|
||||
/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/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.
|
||||
|
||||
/atom/proc/can_subract_container()
|
||||
return flags & EXTRACT_CONTAINER
|
||||
|
||||
/atom/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(severity)
|
||||
return
|
||||
|
||||
/atom/proc/bullet_act(obj/item/projectile/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 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/examine(mob/user)
|
||||
//This reformat names to get a/an properly working on item descriptions when they are bloody
|
||||
var/f_name = "\a [src]."
|
||||
if(src.blood_DNA && !istype(src, /obj/effect/decal))
|
||||
if(gender == PLURAL)
|
||||
f_name = "some "
|
||||
else
|
||||
f_name = "a "
|
||||
f_name += "<span class='danger'>blood-stained</span> [name]!"
|
||||
|
||||
user << "\icon[src] That's [f_name]"
|
||||
|
||||
if(desc)
|
||||
user << desc
|
||||
// *****RM
|
||||
//user << "[name]: Dn:[density] dir:[dir] cont:[contents] icon:[icon] is:[icon_state] loc:[loc]"
|
||||
|
||||
if(reagents && is_open_container()) //is_open_container() isn't really the right proc for this, but w/e
|
||||
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)
|
||||
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
|
||||
user << "[total_volume] units of various reagents"
|
||||
else
|
||||
user << "Nothing."
|
||||
|
||||
/atom/proc/relaymove()
|
||||
return
|
||||
|
||||
/atom/proc/contents_explosion(severity, target)
|
||||
for(var/atom/A in contents)
|
||||
A.ex_act(severity, target)
|
||||
CHECK_TICK
|
||||
|
||||
/atom/proc/ex_act(severity, target)
|
||||
contents_explosion(severity, target)
|
||||
|
||||
/atom/proc/blob_act()
|
||||
return
|
||||
|
||||
/atom/proc/fire_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...).
|
||||
spawn(2) //very short wait, so we can actually see the impact.
|
||||
if(AM && isturf(AM.loc))
|
||||
step(AM, turn(AM.dir, 180))
|
||||
|
||||
var/list/blood_splatter_icons = list()
|
||||
|
||||
/atom/proc/blood_splatter_index()
|
||||
return "\ref[initial(icon)]-[initial(icon_state)]"
|
||||
|
||||
/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.
|
||||
blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
|
||||
return 1
|
||||
|
||||
//returns 1 if made bloody, returns 0 otherwise
|
||||
/atom/proc/add_blood(mob/living/carbon/M)
|
||||
if(!M || !M.has_dna() || rejects_blood())
|
||||
return 0
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(NOBLOOD in H.dna.species.specflags)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
return add_blood_list(M)
|
||||
|
||||
/obj/item/add_blood(mob/living/carbon/M)
|
||||
var/blood_count = !blood_DNA ? 0 : blood_DNA.len
|
||||
if(!..())
|
||||
return 0
|
||||
//apply the blood-splatter overlay if it isn't already in there
|
||||
if(!blood_count && initial(icon) && initial(icon_state))
|
||||
//try to find a pre-processed blood-splatter. otherwise, make a new one
|
||||
var/index = blood_splatter_index()
|
||||
var/icon/blood_splatter_icon = blood_splatter_icons[index]
|
||||
if(!blood_splatter_icon)
|
||||
blood_splatter_icon = icon(initial(icon), initial(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('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
|
||||
blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
|
||||
blood_splatter_icons[index] = blood_splatter_icon
|
||||
overlays += blood_splatter_icon
|
||||
return 1 //we applied blood to the item
|
||||
|
||||
/obj/item/clothing/gloves/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
transfer_blood = rand(2, 4)
|
||||
bloody_hands_mob = M
|
||||
return 1
|
||||
|
||||
/turf/add_blood(mob/living/carbon/human/M)
|
||||
if(!..())
|
||||
return 0
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter
|
||||
if(!B)
|
||||
blood_splatter(src,M.get_blood(M.vessel),1)
|
||||
B = locate(/obj/effect/decal/cleanable/blood) in contents
|
||||
B.add_blood_list(M)
|
||||
return 1 //we bloodied the floor
|
||||
|
||||
/mob/living/carbon/human/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
add_blood_list(M)
|
||||
bloody_hands = rand(2, 4)
|
||||
bloody_hands_mob = M
|
||||
update_inv_gloves() //handles bloody hands overlays and updating
|
||||
return 1 //we applied blood to the item
|
||||
|
||||
/atom/proc/rejects_blood()
|
||||
return 0
|
||||
|
||||
// Only adds blood on the floor -- Skie
|
||||
/atom/proc/add_blood_floor(mob/living/carbon/M)
|
||||
if(istype(src, /turf))
|
||||
if(M.has_dna()) //mobs with dna = (monkeys + humans at time of writing)
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in contents
|
||||
if(!B)
|
||||
blood_splatter(src,M,1)
|
||||
B = locate(/obj/effect/decal/cleanable/blood) in contents
|
||||
B.blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
|
||||
else if(istype(M, /mob/living/carbon/alien))
|
||||
var/obj/effect/decal/cleanable/xenoblood/B = locate() in contents
|
||||
if(!B)
|
||||
B = new(src)
|
||||
B.blood_DNA["UNKNOWN BLOOD"] = "X*"
|
||||
else if(istype(M, /mob/living/silicon/robot))
|
||||
var/obj/effect/decal/cleanable/oil/B = locate() in contents
|
||||
if(!B)
|
||||
B = new(src)
|
||||
|
||||
/atom/proc/clean_blood()
|
||||
if(istype(blood_DNA, /list))
|
||||
blood_DNA = null
|
||||
return 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
|
||||
// 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/isinspace()
|
||||
if(istype(get_turf(src), /turf/open/space))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
/atom/proc/handle_fall()
|
||||
return
|
||||
|
||||
/atom/proc/handle_slip()
|
||||
return
|
||||
/atom/proc/singularity_act()
|
||||
return
|
||||
|
||||
/atom/proc/singularity_pull()
|
||||
return
|
||||
|
||||
/atom/proc/acid_act(acidpwr, toxpwr, acid_volume)
|
||||
return
|
||||
|
||||
/atom/proc/emag_act()
|
||||
return
|
||||
|
||||
/atom/proc/narsie_act()
|
||||
return
|
||||
|
||||
/atom/proc/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
|
||||
return 0
|
||||
|
||||
//This proc is called on the location of an atom when the atom is Destroy()'d
|
||||
/atom/proc/handle_atom_del(atom/A)
|
||||
|
||||
// Byond seemingly calls stat, each tick.
|
||||
// Calling things each tick can get expensive real quick.
|
||||
// So we slow this down a little.
|
||||
// See: http://www.byond.com/docs/ref/info.html#/client/proc/Stat
|
||||
/atom/Stat()
|
||||
. = ..()
|
||||
sleep(1)
|
||||
stoplag()
|
||||
|
||||
//This is called just before maps and objects are initialized, use it to spawn other mobs/objects
|
||||
//effects at world start up without causing runtimes
|
||||
/atom/proc/spawn_atom_to_world()
|
||||
|
||||
//This will be called after the map and objects are loaded
|
||||
/atom/proc/initialize()
|
||||
return
|
||||
|
||||
//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
|
||||
|
||||
/atom/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = 0)
|
||||
if(istype(src,/turf) )
|
||||
var/obj/effect/decal/cleanable/vomit/V = PoolOrNew(/obj/effect/decal/cleanable/vomit, src)
|
||||
// Make toxins vomit look different
|
||||
if(toxvomit)
|
||||
V.icon_state = "vomittox_[pick(1,4)]"
|
||||
if(M.reagents)
|
||||
clear_reagents_to_vomit_pool(M,V)
|
||||
|
||||
/atom/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
|
||||
M.reagents.trans_to(V, M.reagents.total_volume / 10)
|
||||
for(var/datum/reagent/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food
|
||||
if(istype(R, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = R
|
||||
if(nutri_check.nutriment_factor >0)
|
||||
M.reagents.remove_reagent(R.id,R.volume)
|
||||
/atom
|
||||
layer = 2
|
||||
var/level = 2
|
||||
var/flags = 0
|
||||
var/list/fingerprints
|
||||
var/list/fingerprintshidden
|
||||
var/fingerprintslast = null
|
||||
var/list/blood_DNA
|
||||
|
||||
///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
|
||||
|
||||
//Value used to increment ex_act() if reactionary_explosions is on
|
||||
var/explosion_block = 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
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/atom/proc/onCentcom()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return 0
|
||||
|
||||
if(T.z != ZLEVEL_CENTCOM)//if not, don't bother
|
||||
return 0
|
||||
|
||||
//check for centcomm shuttles
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == ENDGAME_LAUNCHED && 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(T.z != ZLEVEL_CENTCOM)//if not, don't bother
|
||||
return 0
|
||||
|
||||
if(istype(T.loc,/area/shuttle/syndicate) || istype(T.loc,/area/syndicate_mothership))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0)
|
||||
if(do_attack_animation)
|
||||
hulk.changeNext_move(CLICK_CD_MELEE)
|
||||
add_logs(hulk, src, "punched", "hulk powers")
|
||||
hulk.do_attack_animation(src)
|
||||
return
|
||||
|
||||
/atom/proc/CheckParts()
|
||||
return
|
||||
|
||||
/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/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.
|
||||
|
||||
/atom/proc/can_subract_container()
|
||||
return flags & EXTRACT_CONTAINER
|
||||
|
||||
/atom/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(severity)
|
||||
return
|
||||
|
||||
/atom/proc/bullet_act(obj/item/projectile/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 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/examine(mob/user)
|
||||
//This reformat names to get a/an properly working on item descriptions when they are bloody
|
||||
var/f_name = "\a [src]."
|
||||
if(src.blood_DNA && !istype(src, /obj/effect/decal))
|
||||
if(gender == PLURAL)
|
||||
f_name = "some "
|
||||
else
|
||||
f_name = "a "
|
||||
f_name += "<span class='danger'>blood-stained</span> [name]!"
|
||||
|
||||
user << "\icon[src] That's [f_name]"
|
||||
|
||||
if(desc)
|
||||
user << desc
|
||||
// *****RM
|
||||
//user << "[name]: Dn:[density] dir:[dir] cont:[contents] icon:[icon] is:[icon_state] loc:[loc]"
|
||||
|
||||
if(reagents && is_open_container()) //is_open_container() isn't really the right proc for this, but w/e
|
||||
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)
|
||||
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
|
||||
user << "[total_volume] units of various reagents"
|
||||
else
|
||||
user << "Nothing."
|
||||
|
||||
/atom/proc/relaymove()
|
||||
return
|
||||
|
||||
/atom/proc/contents_explosion(severity, target)
|
||||
for(var/atom/A in contents)
|
||||
A.ex_act(severity, target)
|
||||
CHECK_TICK
|
||||
|
||||
/atom/proc/ex_act(severity, target)
|
||||
contents_explosion(severity, target)
|
||||
|
||||
/atom/proc/blob_act()
|
||||
return
|
||||
|
||||
/atom/proc/fire_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...).
|
||||
spawn(2) //very short wait, so we can actually see the impact.
|
||||
if(AM && isturf(AM.loc))
|
||||
step(AM, turn(AM.dir, 180))
|
||||
|
||||
var/list/blood_splatter_icons = list()
|
||||
|
||||
/atom/proc/blood_splatter_index()
|
||||
return "\ref[initial(icon)]-[initial(icon_state)]"
|
||||
|
||||
/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.
|
||||
blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
|
||||
return 1
|
||||
|
||||
//returns 1 if made bloody, returns 0 otherwise
|
||||
/atom/proc/add_blood(mob/living/carbon/M)
|
||||
if(!M || !M.has_dna() || rejects_blood())
|
||||
return 0
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(NOBLOOD in H.dna.species.specflags)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
return add_blood_list(M)
|
||||
|
||||
/obj/item/add_blood(mob/living/carbon/M)
|
||||
var/blood_count = !blood_DNA ? 0 : blood_DNA.len
|
||||
if(!..())
|
||||
return 0
|
||||
//apply the blood-splatter overlay if it isn't already in there
|
||||
if(!blood_count && initial(icon) && initial(icon_state))
|
||||
//try to find a pre-processed blood-splatter. otherwise, make a new one
|
||||
var/index = blood_splatter_index()
|
||||
var/icon/blood_splatter_icon = blood_splatter_icons[index]
|
||||
if(!blood_splatter_icon)
|
||||
blood_splatter_icon = icon(initial(icon), initial(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('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
|
||||
blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
|
||||
blood_splatter_icons[index] = blood_splatter_icon
|
||||
overlays += blood_splatter_icon
|
||||
return 1 //we applied blood to the item
|
||||
|
||||
/obj/item/clothing/gloves/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
transfer_blood = rand(2, 4)
|
||||
bloody_hands_mob = M
|
||||
return 1
|
||||
|
||||
/turf/add_blood(mob/living/carbon/human/M)
|
||||
if(!..())
|
||||
return 0
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter
|
||||
if(!B)
|
||||
blood_splatter(src,M.get_blood(M.vessel),1)
|
||||
B = locate(/obj/effect/decal/cleanable/blood) in contents
|
||||
B.add_blood_list(M)
|
||||
return 1 //we bloodied the floor
|
||||
|
||||
/mob/living/carbon/human/add_blood(mob/living/carbon/M)
|
||||
if(!..())
|
||||
return 0
|
||||
add_blood_list(M)
|
||||
bloody_hands = rand(2, 4)
|
||||
bloody_hands_mob = M
|
||||
update_inv_gloves() //handles bloody hands overlays and updating
|
||||
return 1 //we applied blood to the item
|
||||
|
||||
/atom/proc/rejects_blood()
|
||||
return 0
|
||||
|
||||
// Only adds blood on the floor -- Skie
|
||||
/atom/proc/add_blood_floor(mob/living/carbon/M)
|
||||
if(istype(src, /turf))
|
||||
if(M.has_dna()) //mobs with dna = (monkeys + humans at time of writing)
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in contents
|
||||
if(!B)
|
||||
blood_splatter(src,M,1)
|
||||
B = locate(/obj/effect/decal/cleanable/blood) in contents
|
||||
B.blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
|
||||
else if(istype(M, /mob/living/carbon/alien))
|
||||
var/obj/effect/decal/cleanable/xenoblood/B = locate() in contents
|
||||
if(!B)
|
||||
B = new(src)
|
||||
B.blood_DNA["UNKNOWN BLOOD"] = "X*"
|
||||
else if(istype(M, /mob/living/silicon/robot))
|
||||
var/obj/effect/decal/cleanable/oil/B = locate() in contents
|
||||
if(!B)
|
||||
B = new(src)
|
||||
|
||||
/atom/proc/clean_blood()
|
||||
if(istype(blood_DNA, /list))
|
||||
blood_DNA = null
|
||||
return 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
|
||||
// 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/isinspace()
|
||||
if(istype(get_turf(src), /turf/open/space))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
/atom/proc/handle_fall()
|
||||
return
|
||||
|
||||
/atom/proc/handle_slip()
|
||||
return
|
||||
/atom/proc/singularity_act()
|
||||
return
|
||||
|
||||
/atom/proc/singularity_pull()
|
||||
return
|
||||
|
||||
/atom/proc/acid_act(acidpwr, toxpwr, acid_volume)
|
||||
return
|
||||
|
||||
/atom/proc/emag_act()
|
||||
return
|
||||
|
||||
/atom/proc/narsie_act()
|
||||
return
|
||||
|
||||
/atom/proc/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
|
||||
return 0
|
||||
|
||||
//This proc is called on the location of an atom when the atom is Destroy()'d
|
||||
/atom/proc/handle_atom_del(atom/A)
|
||||
|
||||
// Byond seemingly calls stat, each tick.
|
||||
// Calling things each tick can get expensive real quick.
|
||||
// So we slow this down a little.
|
||||
// See: http://www.byond.com/docs/ref/info.html#/client/proc/Stat
|
||||
/atom/Stat()
|
||||
. = ..()
|
||||
sleep(1)
|
||||
stoplag()
|
||||
|
||||
//This is called just before maps and objects are initialized, use it to spawn other mobs/objects
|
||||
//effects at world start up without causing runtimes
|
||||
/atom/proc/spawn_atom_to_world()
|
||||
|
||||
//This will be called after the map and objects are loaded
|
||||
/atom/proc/initialize()
|
||||
return
|
||||
|
||||
//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
|
||||
|
||||
/atom/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = 0)
|
||||
if(istype(src,/turf) )
|
||||
var/obj/effect/decal/cleanable/vomit/V = PoolOrNew(/obj/effect/decal/cleanable/vomit, src)
|
||||
// Make toxins vomit look different
|
||||
if(toxvomit)
|
||||
V.icon_state = "vomittox_[pick(1,4)]"
|
||||
if(M.reagents)
|
||||
clear_reagents_to_vomit_pool(M,V)
|
||||
|
||||
/atom/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
|
||||
M.reagents.trans_to(V, M.reagents.total_volume / 10)
|
||||
for(var/datum/reagent/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food
|
||||
if(istype(R, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = R
|
||||
if(nutri_check.nutriment_factor >0)
|
||||
M.reagents.remove_reagent(R.id,R.volume)
|
||||
|
||||
@@ -388,7 +388,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s
|
||||
/obj/item/proc/on_found(mob/finder)
|
||||
return
|
||||
|
||||
// called after an item is placed in an equipment slot
|
||||
// called after an item is placed in an equipment slot //NOPE, for example, if you put a helmet in slot_head, it is NOT in user's head variable yet, how stupid.
|
||||
// user is mob that equipped it
|
||||
// slot uses the slot_X defines found in setup.dm
|
||||
// for items that can be placed in multiple slots
|
||||
|
||||
@@ -62,14 +62,6 @@
|
||||
desc = "A plastic replica of a Syndicate agent's space helmet. You'll look just like a real murderous Syndicate agent in this! This is a toy, it is not made for use in space!"
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
|
||||
|
||||
/obj/item/clothing/head/cardborg
|
||||
name = "cardborg helmet"
|
||||
desc = "A helmet made out of a box."
|
||||
icon_state = "cardborg_h"
|
||||
item_state = "cardborg_h"
|
||||
flags_cover = HEADCOVERSEYES
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
|
||||
|
||||
/obj/item/clothing/head/snowman
|
||||
name = "Snowman Head"
|
||||
desc = "A ball of white styrofoam. So festive."
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Ushanka
|
||||
* Pumpkin head
|
||||
* Kitty ears
|
||||
*
|
||||
* Cardborg disguise
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -147,3 +147,24 @@
|
||||
flags_inv = 0
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
brightness_on = 1 //luminosity when on
|
||||
|
||||
|
||||
/obj/item/clothing/head/cardborg
|
||||
name = "cardborg helmet"
|
||||
desc = "A helmet made out of a box."
|
||||
icon_state = "cardborg_h"
|
||||
item_state = "cardborg_h"
|
||||
flags_cover = HEADCOVERSEYES
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
|
||||
|
||||
/obj/item/clothing/head/cardborg/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(ishuman(user) && slot == slot_head)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.wear_suit, /obj/item/clothing/suit/cardborg))
|
||||
var/obj/item/clothing/suit/cardborg/CB = H.wear_suit
|
||||
CB.disguise(user, src)
|
||||
|
||||
/obj/item/clothing/head/cardborg/dropped(mob/living/user)
|
||||
..()
|
||||
user.remove_alt_appearance("standard_borg_disguise")
|
||||
@@ -155,7 +155,6 @@
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
|
||||
|
||||
/obj/item/clothing/suit/cardborg
|
||||
name = "cardborg suit"
|
||||
desc = "An ordinary cardboard box with holes cut in the sides."
|
||||
@@ -164,6 +163,26 @@
|
||||
body_parts_covered = CHEST|GROIN
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
|
||||
/obj/item/clothing/suit/cardborg/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_wear_suit)
|
||||
disguise(user)
|
||||
|
||||
/obj/item/clothing/suit/cardborg/dropped(mob/living/user)
|
||||
..()
|
||||
user.remove_alt_appearance("standard_borg_disguise")
|
||||
|
||||
/obj/item/clothing/suit/cardborg/proc/disguise(mob/living/carbon/human/H, obj/item/clothing/head/cardborg/borghead)
|
||||
if(istype(H))
|
||||
if(!borghead)
|
||||
borghead = H.head
|
||||
if(istype(borghead, /obj/item/clothing/head/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY
|
||||
var/image/I = image(icon = 'icons/mob/robots.dmi' , icon_state = "robot", loc = H)
|
||||
I.override = 1
|
||||
I.overlays += image(icon = 'icons/mob/robots.dmi' , icon_state = "eyes-standard") //gotta look realistic
|
||||
H.add_alt_appearance("standard_borg_disguise", I, silicon_mobs+H) //you look like a robot to robots! (including yourself because you're totally a robot)
|
||||
|
||||
|
||||
/obj/item/clothing/suit/snowman
|
||||
name = "snowman outfit"
|
||||
desc = "Two white spheres covered in white glitter. 'Tis the season."
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
/mob/living/silicon/New()
|
||||
..()
|
||||
silicon_mobs |= src
|
||||
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
|
||||
diag_hud.add_to_hud(src)
|
||||
diag_hud_set_status()
|
||||
@@ -43,6 +44,7 @@
|
||||
/mob/living/silicon/Destroy()
|
||||
radio = null
|
||||
aicamera = null
|
||||
silicon_mobs -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/contents_explosion(severity, target)
|
||||
|
||||
@@ -64,3 +64,9 @@
|
||||
winset(src, null, "mainwindow.macro=[macro_hotkeys] mapwindow.map.focus=true input.background-color=#e0e0e0")
|
||||
else
|
||||
winset(src, null, "mainwindow.macro=[macro_default] input.focus=true input.background-color=#d3b5b5")
|
||||
|
||||
if(viewing_alternate_appearances && viewing_alternate_appearances.len)
|
||||
for(var/aakey in viewing_alternate_appearances)
|
||||
var/datum/alternate_appearance/AA = viewing_alternate_appearances[aakey]
|
||||
if(AA)
|
||||
AA.display_to(list(src))
|
||||
|
||||
@@ -233,6 +233,7 @@
|
||||
#include "code\datums\wires\syndicatebomb.dm"
|
||||
#include "code\datums\wires\vending.dm"
|
||||
#include "code\datums\wires\wires.dm"
|
||||
#include "code\game\alternate_appearance.dm"
|
||||
#include "code\game\asteroid.dm"
|
||||
#include "code\game\atoms.dm"
|
||||
#include "code\game\atoms_movable.dm"
|
||||
|
||||
Reference in New Issue
Block a user