Files
vgstation13/code/game/objects/objs.dm

800 lines
27 KiB
Plaintext

var/global/list/reagents_to_log = list(FUEL, PLASMA, PACID, SACID, AMUTATIONTOXIN, MINDBREAKER, SPIRITBREAKER, CYANIDE, IMPEDREZENE, LUBE)
/obj
var/origin_tech = null //Used by R&D to determine what research bonuses it grants.
var/reliability = 100 //Used by SOME devices to determine how reliable they are.
var/crit_fail = 0
animate_movement = 2
var/throwforce = 1
var/siemens_coefficient = 0 // for electrical admittance/conductance (electrocution checks and shit) - 0 is not conductive, 1 is conductive - this is a range, not binary
var/sharpness = 0 //not a binary - rough guide is 0.8 cutting, 1 cutting well, 1.2 specifically sharp (knives, etc) 1.5 really sharp (scalpels, e-weapons)
var/sharpness_flags = 0 //Describe in which way this thing is sharp. Shouldn't sharpness be exclusive to obj/item?
var/heat_production = 0
var/source_temperature = 0
var/price = 0
var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
var/damtype = "brute"
var/force = 0
//Should we alert about reagents that should be logged?
var/log_reagents = 1
var/list/mob/_using // All mobs dicking with us.
// Shit for mechanics. (MECH_*)
var/mech_flags=0
plane = OBJ_PLANE
var/defective = 0
var/quality = B_AVERAGE //What level of quality this object is.
var/datum/material/material_type //What material this thing is made out of
var/sheet_type = /obj/item/stack/sheet/metal
var/sheet_amt = 1
var/can_take_pai = FALSE
var/obj/item/device/paicard/integratedpai = null
var/datum/delay_controller/pAImove_delayer = new(1, ARBITRARILY_LARGE_NUMBER)
var/pAImovement_delay = 0
// Can we wrench/weld this to a turf with a dense /obj on it?
var/can_affix_to_dense_turf=0
var/has_been_invisible_sprayed = FALSE
var/impactsound
var/current_glue_state = GLUE_STATE_NONE
// Does this item have a slime installed?
var/has_slime = 0
// Whether this object can appear in holomaps
/obj/proc/supports_holomap()
return FALSE
/obj/proc/add_self_to_holomap()
var/turf/T = loc
if(istype(T) && ticker && ticker.current_state != GAME_STATE_PLAYING)
T.add_holomap(src)
/obj/Destroy()
for(var/mob/user in _using)
user.unset_machine()
if(src in processing_objects)
processing_objects -= src
if(integratedpai)
qdel(integratedpai)
integratedpai = null
material_type = null //Don't qdel, they're held globally
..()
/obj/item/proc/is_used_on(obj/O, mob/user)
/obj/proc/blocks_doors()
return 0
/obj/proc/install_pai(obj/item/device/paicard/P)
if(!P || !istype(P))
return 0
P.forceMove(src)
integratedpai = P
verbs += /obj/proc/remove_pai
/obj/attackby(obj/item/weapon/W, mob/user)
INVOKE_EVENT(src, /event/attackby, "attacker" = user, "item" = W)
if(can_take_pai && istype(W, /obj/item/device/paicard))
if(integratedpai)
to_chat(user, "<span class = 'notice'>There's already a Personal AI inserted.</span>")
return
if(user.drop_item(W))
to_chat(user, "You insert \the [W] into a slot in \the [src].")
install_pai(W)
state_controls_pai(W)
playsound(src, 'sound/misc/cartridge_in.ogg', 25)
if(W)
if(W.material_type)
W.material_type.on_use(W, src, user)
/obj/proc/state_controls_pai(obj/item/device/paicard/P) //text the pAI receives when is inserted into something. EXAMPLE: to_chat(P.pai, "Welcome to your new body")
if(P.pai)
return 1
return 0
/obj/proc/attack_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI clicks on the object, or uses the attack_self() hotkey
return
/obj/proc/swapkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the swap_hand() hotkey
return
/obj/proc/throwkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the toggle_throw_mode() hotkey
return
/obj/proc/dropkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the drop hotkey
return
/obj/proc/equipkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the equip hotkey
return
/obj/proc/intentright_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the cycle-intent-right hotkey
return
/obj/proc/intentleft_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the cycle-intent-left hotkey
return
/obj/proc/intenthelp_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the help intent hotkey
return
/obj/proc/intentdisarm_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the disarm intent hotkey
return
/obj/proc/intentgrab_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the grab intent hotkey
return
/obj/proc/intenthurt_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the hurt intent hotkey
return
/obj/proc/pAImove(mob/living/silicon/pai/user, dir) //called when integrated pAI attempts to move
if(pAImove_delayer.blocked())
user.last_movement=world.time
return 0
else
delayNextpAIMove(getpAIMovementDelay())
if (user.client.prefs.stumble && ((world.time - user.last_movement) > 5) && getpAIMovementDelay() < 2)
delayNextpAIMove(3) //if set, delays the second step when a mob starts moving to attempt to make precise high ping movement easier
user.last_movement=world.time
return 1
/obj/proc/getpAIMovementDelay()
return pAImovement_delay
/obj/proc/delayNextpAIMove(var/delay, var/additive=0)
pAImove_delayer.delayNext(delay,additive)
/obj/proc/on_integrated_pai_click(mob/living/silicon/pai/user, var/atom/A)
if(istype(A,/obj/machinery)||(istype(A,/mob)&&user.secHUD))
A.attack_pai(user)
/obj/proc/remove_pai()
set name = "Remove pAI"
set category = "Object"
set src in range(1)
var/mob/M = usr
if(!M.Adjacent(src))
return
if(!M.dexterity_check())
to_chat(usr, "You don't have the dexterity to do this!")
return
if(M.incapacitated())
to_chat(M, "You can't do that while you're incapacitated!")
return
to_chat(M, "You eject \the [integratedpai] from \the [src].")
M.put_in_hands(eject_integratedpai_if_present())
playsound(src, 'sound/misc/cartridge_out.ogg', 25)
/obj/proc/eject_integratedpai_if_present()
if(integratedpai)
integratedpai.forceMove(get_turf(src))
verbs -= /obj/proc/remove_pai
var/obj/item/device/paicard/P = integratedpai
integratedpai = null
return P
return 0
/obj/recycle(var/datum/materials/rec)
if(..())
return 1
return w_type
/*
/obj/melt()
var/obj/effect/decal/slag/slag=locate(/obj/effect/decal/slag) in get_turf(src)
if(!slag)
slag = new(get_turf(src))
slag.slaggify(src)
*/
/obj/proc/is_conductor(var/siemens_min = 0.5)
if(src.siemens_coefficient >= siemens_min)
return 1
return
/obj/proc/cultify()
qdel(src)
/obj/proc/clockworkify()
return
/obj/proc/wrenchable()
return 0
/obj/proc/can_wrench_shuttle()
return 0
/obj/proc/is_sharp()
return sharpness
/obj/is_hot() //This returns the temperature of the object if possible
return source_temperature
/obj/thermal_energy_transfer()
if(is_hot())
return heat_production
return 0
/obj/proc/process()
set waitfor = FALSE
processing_objects.Remove(src)
//At some point, this proc should be changed to work like remove_air() below does.
//However, this would likely cause problems, such as CO2 buildup in mechs and spacepods, so I'm not doing it right now.
/obj/assume_air(datum/gas_mixture/giver)
if(loc)
return loc.assume_air(giver)
else
return null
/obj/remove_air(amount)
var/datum/gas_mixture/my_air = return_air()
return my_air?.remove(amount)
/obj/return_air()
if(loc)
return loc.return_air()
else
return null
/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_vol)
if(breath_vol > 0)
var/datum/gas_mixture/G = return_air()
return G.remove_volume(breath_vol)
else
return null
/obj/proc/updateUsrDialog()
if(in_use)
var/is_in_use = 0
if(_using && _using.len)
var/list/nearby = viewers(1, src) + loc //List of nearby things includes the location - allows you to call this proc on items and such
for(var/mob/M in _using) // Only check things actually messing with us.
if (!M || !M.client)
_using.Remove(M)
continue
// AIs/Robots can do shit from afar.
if (isAI(M) || isrobot(M) || isAdminGhost(M))
is_in_use = 1
src.attack_ai(M)
else if(!(M in nearby)) // NOT NEARBY
// check for TK users
if(M.mutations && M.mutations.len)
if(M_TK in M.mutations)
is_in_use = 1
src.attack_hand(M, TRUE) // The second param is to make sure brain damage on the user doesn't cause the UI to not update but the action to still happen.
else
// Remove.
_using.Remove(M)
continue
else // EVERYTHING FROM HERE DOWN MUST BE NEARBY
is_in_use = 1
attack_hand(M, TRUE)
in_use = is_in_use
/obj/proc/updateDialog()
// Check that people are actually using the machine. If not, don't update anymore.
if(in_use)
var/list/nearby = viewers(1, src)
var/is_in_use = 0
for(var/mob/M in _using) // Only check things actually messing with us.
// Not actually using the fucking thing?
if (!M || !M.client || M.machine != src)
_using.Remove(M)
continue
// Not robot or AI, and not nearby?
if(!isAI(M) && !isrobot(M) && !(M in nearby))
_using.Remove(M)
continue
is_in_use = 1
src.interact(M)
in_use = is_in_use
/obj/proc/interact(mob/user)
return
//user: The mob that is suiciding
//damagetype: The type of damage the item will inflict on the user
//SUICIDE_ACT_BRUTELOSS = 1
//SUICIDE_ACT_FIRELOSS = 2
//SUICIDE_ACT_TOXLOSS = 4
//SUICIDE_ACT_OXYLOSS = 8
//Output a creative message and then return the damagetype done
/obj/proc/suicide_act(var/mob/living/user)
if (is_hot())
user.visible_message("<span class='danger'>[user] is immolating \himself on \the [src]! It looks like \he's trying to commit suicide.</span>")
user.IgniteMob()
return SUICIDE_ACT_FIRELOSS
else if (sharpness >= 1)
user.visible_message("<span class='danger'>[user] impales himself on \the [src]! It looks like \he's trying to commit suicide.</span>")
return SUICIDE_ACT_BRUTELOSS
else if (force >= 10)
if (prob(50))
playsound(user, 'sound/items/trayhit1.ogg', 50, 1)
else
playsound(user, 'sound/items/trayhit2.ogg', 50, 1)
user.visible_message("<span class='danger'>[user] strikes his head on \the [src]! It looks like \he's trying to commit suicide.</span>")
return SUICIDE_ACT_BRUTELOSS
/obj/singularity_act()
if(flags & INVULNERABLE)
return
ex_act(1)
if(src)
qdel(src)
return 2
/obj/shuttle_act(datum/shuttle/S)
return qdel(src)
/obj/slime_act(primarytype, mob/user)
if(has_slime)
to_chat(user, "\the [src] already has a slime extract attached.")
return FALSE
/obj/singularity_pull(S, current_size)
INVOKE_EVENT(src, /event/before_move)
if(anchored)
if(current_size >= STAGE_FIVE)
anchored = 0
step_towards(src, S)
else
step_towards(src, S)
INVOKE_EVENT(src, /event/after_move)
/obj/proc/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
return "<b>NO MULTITOOL_MENU!</b>"
/obj/proc/linkWith(var/mob/user, var/obj/buffer, var/list/context)
return 0
/obj/proc/shouldReInitOnMultitoolLink(var/mob/user, var/obj/buffer, var/list/context)
return FALSE
/obj/proc/unlinkFrom(var/mob/user, var/obj/buffer)
return 0
/obj/proc/canLink(var/obj/O, var/list/context)
return 0
/obj/proc/isLinkedWith(var/obj/O)
return 0
/obj/proc/getLink(var/idx)
return null
/obj/proc/canClone(var/obj/O)
return 0
/obj/proc/clone(var/obj/O)
return 0
/obj/proc/linkMenu(var/obj/O)
var/dat=""
if(canLink(O, list()))
dat += " <a href='?src=\ref[src];link=1'>\[Link\]</a> "
return dat
/obj/proc/format_tag(var/label,var/varname, var/act="set_tag")
var/value = vars[varname]
if(!value || value=="")
value="-----"
return "<b>[label]:</b> <a href=\"?src=\ref[src];[act]=[varname]\">[value]</a>"
/obj/proc/update_multitool_menu(mob/user as mob)
var/obj/item/device/multitool/P = get_multitool(user)
if(!istype(P))
return 0
// Cloning stuff goes here.
var/obj/machinery/bufRef = P.buffer?.get();
if(P.clone && bufRef) // Cloning is on.
if(!canClone(bufRef))
to_chat(user, "<span class='attack'>A red light flashes on \the [P]; you cannot clone to this device!</span>")
return
if(!clone(bufRef))
to_chat(user, "<span class='attack'>A red light flashes on \the [P]; something went wrong when cloning to this device!</span>")
return
to_chat(user, "<span class='confirm'>A green light flashes on \the [P], confirming the device was cloned to.</span>")
return
var/dat = {"<html>
<head>
<title>[name] Configuration</title>
<style type="text/css">
html,body {
font-family:courier;
background:#999999;
color:#333333;
}
a {
color:#000000;
text-decoration:none;
border-bottom:1px solid black;
}
</style>
</head>
<body>
<h3>[name]</h3>
"}
dat += multitool_menu(user,P)
if(P)
if(bufRef)
var/id = null
if(istype(bufRef, /obj/machinery/telecomms))
var/obj/machinery/telecomms/buffer = bufRef//Casting is better than using colons
id = buffer.id
else if(bufRef.vars["id_tag"])//not doing in vars here incase the var is empty, it'd show ()
id = bufRef:id_tag//sadly, : is needed
dat += "<p><b>MULTITOOL BUFFER:</b> [bufRef] [id ? "([id])" : ""]"//If you can't into the ? operator, that will make it not display () if there's no ID.
dat += linkMenu(bufRef)
if(bufRef)
dat += "<a href='?src=\ref[src];flush=1'>\[Flush\]</a>"
dat += "</p>"
else
dat += "<p><b>MULTITOOL BUFFER:</b> <a href='?src=\ref[src];buffer=1'>\[Add Machine\]</a></p>"
dat += "</body></html>"
user << browse(dat, "window=mtcomputer")
user.set_machine(src)
onclose(user, "mtcomputer")
/obj/update_icon()
return
/mob/proc/unset_machine()
if(machine)
if(machine._using)
machine._using -= src
if(!machine._using.len)
machine._using = null
machine = null
/mob/proc/set_machine(const/obj/O)
unset_machine()
if(istype(O))
machine = O
if(!machine._using)
machine._using = new
machine._using += src
machine.in_use = 1
/** Returns 1 or 0 depending on whether the machine can be affixed to this position.
* Used to determine whether other density=1 things are on this tile.
* @param user Tool user
* @return bool Can affix here
*/
/obj/proc/canAffixHere(var/mob/user)
if(density==0 || can_affix_to_dense_turf)
return TRUE// Non-dense things just don't care. Same with can_affix_to_dense_turf=TRUE objects.
for(var/obj/other in loc) //ensure multiple things aren't anchored in one place
if(other.anchored == 1 && other.density == 1 && density && !anchored && !(other.flow_flags & ON_BORDER) && !(istype(other,/obj/structure/table)))
to_chat(user, "\The [other] is already anchored in this location.")
return FALSE // NOPE
return TRUE
/** Anchors shit to the deck via wrench.
* @param user The mob doing the wrenching
* @param time_to_wrench The time to complete the wrenchening
* @returns TRUE on success, FALSE on fail
*/
/obj/proc/wrenchAnchor(var/mob/user, var/obj/item/I, var/time_to_wrench = 3 SECONDS) //proc to wrench an object that can be secured
if(!canAffixHere(user))
return FALSE
if(!anchored)
if(!istype(src.loc, /turf/simulated/floor)) //Prevent from anchoring shit to shuttles / space
if(isshuttleturf(src.loc) && !can_wrench_shuttle()) //If on the shuttle and not wrenchable to shuttle
to_chat(user, "<span class = 'notice'>You can't secure \the [src] to this!</span>")
return FALSE
if(istype(src.loc, /turf/space)) //if on a space tile
to_chat(user, "<span class = 'notice'>You can't secure \the [src] to space!</span>")
return FALSE
user.visible_message( "[user] begins to [anchored ? "unbolt" : "bolt"] \the [src] [anchored ? "from" : "to" ] the floor.",
"You begin to [anchored ? "unbolt" : "bolt"] \the [src] [anchored ? "from" : "to" ] the floor.")
if(I)
I.playtoolsound(loc, 50)
if(do_after(user, src, time_to_wrench))
if(!canAffixHere(user))
return FALSE
anchored = !anchored
user.visible_message( "<span class='notice'>[user] [anchored ? "wrench" : "unwrench"]es \the [src] [anchored ? "in place" : "from its fixture"]</span>",
"<span class='notice'>[bicon(src)] You [anchored ? "wrench" : "unwrench"] \the [src] [anchored ? "in place" : "from its fixture"].</span>",
"<span class='notice'>You hear a ratchet.</span>")
return TRUE
return FALSE
/obj/item/proc/updateSelfDialog()
var/mob/M = src.loc
if(istype(M) && M.client && M.machine == src)
src.attack_self(M)
/obj/proc/alter_health()
return 1
/obj/proc/hide(h)
return
/obj/proc/container_resist()
return
/obj/proc/can_pickup(mob/living/user)
return 0
/obj/proc/verb_pickup(mob/living/user)
return 0
/obj/proc/can_quick_store(var/obj/item/I) //proc used to check that the current object can store another through quick equip
return 0
/obj/proc/quick_store(var/obj/item/I) //proc used to handle quick storing
return 0
/**
* Called when a mob inside this obj's contents logs out.
*/
/obj/proc/on_logout(var/mob/M)
if(isobj(loc))
var/obj/location = loc
location.on_logout(M)
/**
* Called when a mob inside this obj's contents logs in.
*/
/obj/proc/on_login(var/mob/M)
if(isobj(loc))
var/obj/location = loc
location.on_login(M)
// Dummy to give items special techlist for the purposes of the Device Analyser, in case you'd ever need them to give them different tech levels depending on special checks.
/obj/proc/give_tech_list()
return null
/obj/acidable()
return !(flags & INVULNERABLE)
/obj/proc/t_scanner_expose()
if (level != LEVEL_BELOW_FLOOR)
return
if (invisibility == 101)
invisibility = 0
spawn(1 SECONDS)
var/turf/U = loc
if(istype(U) && U.intact)
invisibility = 101
/obj/proc/become_defective()
if(!defective)
defective = 1
desc += "\nIt doesn't look to be in the best shape."
/obj/proc/clumsy_check(var/mob/living/user)
if(istype(user))
if(isrobot(user))
var/mob/living/silicon/robot/R = user
return HAS_MODULE_QUIRK(R, MODULE_IS_A_CLOWN)
return (M_CLUMSY in user.mutations) || user.reagents.has_reagent(INCENSE_BANANA)
return 0
//Proc that handles NPCs (gremlins) "tampering" with this object.
//Return NPC_TAMPER_ACT_FORGET if there's no interaction (the NPC won't try to tamper with this again)
//Return NPC_TAMPER_ACT_NOMSG if you don't want to create a visible_message
/obj/proc/npc_tamper_act(mob/living/L)
return NPC_TAMPER_ACT_FORGET
/obj/actual_send_to_future(var/duration)
var/turf/current_turf = get_turf(src)
var/datum/current_loc = loc
forceMove(null)
..()
if(!current_loc.gcDestroyed)
forceMove(current_loc)
else
forceMove(current_turf)
/obj/send_to_past(var/duration)
..()
var/static/list/resettable_vars = list(
"sharpness",
"integratedpai")
reset_vars_after_duration(resettable_vars, duration)
//Called when a mob in our locked atoms list kicks another object. Return 1 if successful, to abort the rest of the kicking action.
/obj/proc/onBuckledUserKick(var/mob/living/user, var/atom/A)
if(!anchored && !user.incapacitated() && user.has_limbs) //if you're buckled onto a non-anchored object (like office chairs) you harmlessly push yourself away with your legs
spawn() //return 1 first thing
var/movementdirection = turn(get_dir(src,A),180)
if(user.get_strength() > 1) //hulk KICK!
user.visible_message("<span class='danger'>[user] puts \his foot to \the [A] and kicks \himself away!</span>", \
"<span class='warning'>You put your foot to \the [A] and kick as hard as you can! [pick("RAAAAAAAARGH!", "HNNNNNNNNNGGGGGGH!", "GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", "AAAAAAARRRGH!")]</span>")
var/turf/T = get_edge_target_turf(src, movementdirection)
src.throw_at(T,8,20,fly_speed = 2)
else
user.visible_message("<span class='warning'>[user] kicks \himself away from \the [A].</span>", "<span class='notice'>You kick yourself away from \the [A]. Wee!</span>")
for(var/i in list(2,2,3,3))
set_glide_size(DELAY2GLIDESIZE(i))
if(!step(src, movementdirection))
change_dir(turn(movementdirection, 180)) //stop, but don't turn around when hitting a wall
break
change_dir(turn(movementdirection, 180)) //face away from where we're going
sleep(i)
return 1
/obj/make_invisible(var/source_define, var/time, var/include_clothing)
if(..() || !source_define)
return
alpha = 1
if(source_define == INVISIBLESPRAY)
has_been_invisible_sprayed = TRUE
if(ismob(loc))
var/mob/M = loc
M.regenerate_icons()
if(time > 0)
spawn(time)
alpha = initial(alpha)
has_been_invisible_sprayed = FALSE
if(ismob(loc))
var/mob/M = loc
M.regenerate_icons()
/obj/proc/gen_quality(var/modifier = 0, var/min_quality = 0, var/datum/material/mat)
var/material_mod = mat ? mat.quality_mod : material_type ? material_type.quality_mod : 1
var/surrounding_mod = 1
/* - Probably better we find a better way of checking the quality of a room, like an area-level variable for room quality, and cleanliness
var/turf/T = get_turf(src)
for(var/dir in alldirs)
for(var/obj/I in get_step(T, dir))
if(I.quality > NORMAL || I.quality < NORMAL)
surrounding_mod *= I.quality/rand(1,3)
*/
var/initial_quality = round(((rand(1,3)*surrounding_mod)*material_mod)+modifier)
quality = clamp(initial_quality, B_AWFUL>min_quality?B_AWFUL:min_quality, B_LEGENDARY)
var/processed_name = lowertext(mat? mat.processed_name : material_type.processed_name)
var/to_icon_state = "[initial(icon_state)]_[processed_name]_[quality]"
if(has_icon(icon, to_icon_state))
icon_state = to_icon_state
/obj/proc/gen_description(mob/user)
var/material_mod = quality-B_GOOD>1 ? quality-B_GOOD : 0
var/additional_description
if(material_mod)
additional_description = "On \the [src] is a carving, it depicts:\n"
var/list/characters = list()
for(var/i = 1 to material_mod)
if(prob(50)) //We're gonna use an atom
var/atom/AM = pick(existing_typesof(/mob/living/simple_animal))
characters |= initial(AM.name)
else
var/strangething = pick("captain","clown","mime","\improper CMO","cargo technician","medical doctor","[user ? user : "stranger"]","octopus","changeling","\improper Nuclear Operative", "[pick("greyshirt", "greytide", "assistant")]", "xenomorph","catbeast","[user && user.mind && user.mind.heard_before.len ? pick(user.mind.heard_before) : "strange thing"]","Central Command","\improper Ian","[ticker.Bible_deity_name]","Nar-Sie","\improper Poly the Parrot","\improper Wizard","vox")
characters |= strangething
additional_description += "[i == material_mod ? " & a " : "[i > 1 ? ", a ": " A "]"][characters[i]]"
additional_description += ". They are in \the [pick("captains office","Space","mining outpost","vox outpost","a space station","[station_name()]","bar","kitchen","library","Science","void","Bluespace","Hell","Central Command")]"
if(material_mod > 2)
additional_description += ". They are [pick("[pick("fighting","robusting","attacking","beating up", "abusing")] [pick("each other", pick(characters))]","playing cards","firing lasers at [pick("something",pick(characters))]","crying","laughing","blank faced","screaming","cooking [pick("something", pick(characters))]", "eating [pick("something", pick(characters))]")]. "
if(characters.len > 1)
for(var/i in characters)
additional_description += "\The [i] is [pick("laughing","crying","screaming","naked","very naked","angry","jovial","manical","melting","fading away","making a plaintive gesture")]. "
additional_description += "The scene gives off a feeling of [pick("unease","empathy","fear","malice","dread","happiness","strangeness","insanity","drol")]. "
additional_description += "It is accented in hues of [pick("red","orange","yellow","green","blue","indigo","violet","white","black","cinnamon")]. "
if(additional_description)
desc = "[initial(desc)] \n [additional_description]"
/obj/proc/dorfify(var/datum/material/mat, var/additional_quality, var/min_quality)
if(mat)
/*var/icon/original = icon(icon, icon_state) Icon operations keep making mustard gas
if(mat.color)
original.ColorTone(mat.color)
var/obj/item/I = src
if(istype(I))
var/icon/t_state
for(var/hand in list("left_hand", "right_hand"))
t_state = icon(I.inhand_states[hand], I.item_state)
t_state.ColorTone(mat.color)
I.inhand_states[hand] = t_state
else if(mat.color_matrix)
color = mat.color_matrix
icon = original*/
alpha = mat.alpha
material_type = mat
sheet_type = mat.sheettype
gen_quality(additional_quality, min_quality)
if(quality > B_SUPERIOR)
gen_description()
if(material_type)
if(sharpness_flags && sharpness)
force = initial(force)*(material_type.sharpness_mod*(quality/B_AVERAGE))
throwforce = initial(throwforce)*(material_type.sharpness_mod*(quality/B_AVERAGE))
sharpness = initial(sharpness)*(material_type.sharpness_mod*(quality/B_AVERAGE))
else
force = initial(force)*(material_type.brunt_damage_mod*(quality/B_AVERAGE))
throwforce = initial(throwforce)*(material_type.brunt_damage_mod*(quality/B_AVERAGE))
if(!findtext(lowertext(name), lowertext(material_type.name)))
name = "[quality == B_AVERAGE ? "": "[lowertext(qualityByString[quality])] "][lowertext(mat.name)] [name]"
/obj/proc/check_uplink_validity()
return TRUE
//Return true if thrown object misses
/obj/PreImpact(atom/movable/A, speed)
if(flow_flags & ON_BORDER) //If the object should hit this, it will just by normal collision detection.
return ..()
if(density && !throwpass)
return FALSE
return TRUE
/obj/proc/FeetStab(mob/living/AM,var/soundplay = 'sound/effects/glass_step.ogg',var/damage = 5,var/knockdown = 3)
if(istype(AM))
if(AM.locked_to) //Mob is locked to something, so it's not actually stepping on the glass
playsound(src, soundplay, 50, 1)
return
if(AM.flying)
return
else //Stepping on the glass
playsound(src, soundplay, 50, 1)
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
var/danger = FALSE
var/datum/organ/external/foot = H.pick_usable_organ(LIMB_LEFT_FOOT, LIMB_RIGHT_FOOT)
if(foot && !H.organ_has_mutation(foot, M_STONE_SKIN) && !H.check_body_part_coverage(FEET))
if(foot.is_organic())
danger = TRUE
if(!H.lying && H.feels_pain())
H.Knockdown(knockdown)
H.Stun(knockdown)
if(foot.take_damage(damage, 0))
H.UpdateDamageIcon()
H.updatehealth()
to_chat(AM, "<span class='[danger ? "danger" : "notice"]'>You step in \the [src]!</span>")
/**
* This proc is used for telling whether something can pass by this object in a given direction, for use by the pathfinding system.
*
* Trying to generate one long path across the station will call this proc on every single object on every single tile that we're seeing if we can move through, likely
* multiple times per tile since we're likely checking if we can access said tile from multiple directions, so keep these as lightweight as possible.
*
* Arguments:
* * ID- An ID card representing what access we have (and thus if we can open things like airlocks or windows to pass through them). The ID card's physical location does not matter, just the reference
* * to_dir- What direction we're trying to move in, relevant for things like directional windows that only block movement in certain directions
* * caller- The movable we're checking pass flags for, if we're making any such checks
**/
/obj/proc/CanAStarPass(obj/item/weapon/card/id/ID, to_dir, atom/movable/caller)
if(istype(caller) && (caller.pass_flags & pass_flags_self))
return TRUE
. = !density