Merged Upstream

This is a big one.
This commit is contained in:
Vetinari
2014-03-04 22:19:09 +11:00
92 changed files with 2944 additions and 1648 deletions
+252
View File
@@ -0,0 +1,252 @@
/////////////////////////////////////////////
// Chem smoke
/////////////////////////////////////////////
/obj/effect/effect/smoke/chem
icon = 'icons/effects/chemsmoke.dmi'
opacity = 0
time_to_live = 300
pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass
/obj/effect/effect/smoke/chem/New()
..()
var/datum/reagents/R = new/datum/reagents(500)
reagents = R
R.my_atom = src
return
/datum/effect/effect/system/smoke_spread/chem
smoke_type = /obj/effect/effect/smoke/chem
var/obj/chemholder
var/range
var/list/targetTurfs
var/list/wallList
var/density
/datum/effect/effect/system/smoke_spread/chem/New()
..()
chemholder = new/obj()
var/datum/reagents/R = new/datum/reagents(500)
chemholder.reagents = R
R.my_atom = chemholder
//------------------------------------------
//Sets up the chem smoke effect
//
// Calculates the max range smoke can travel, then gets all turfs in that view range.
// Culls the selected turfs to a (roughly) circle shape, then calls smokeFlow() to make
// sure the smoke can actually path to the turfs. This culls any turfs it can't reach.
//------------------------------------------
/datum/effect/effect/system/smoke_spread/chem/set_up(var/datum/reagents/carry = null, n = 10, c = 0, loca, direct)
range = n * 0.3
cardinals = c
carry.copy_to(chemholder, carry.total_volume)
if(istype(loca, /turf/))
location = loca
else
location = get_turf(loca)
if(!location)
return
targetTurfs = new()
//build affected area list
for(var/turf/T in view(range, location))
//cull turfs to circle
if(cheap_pythag(T.x - location.x, T.y - location.y) <= range)
targetTurfs += T
//make secondary list for reagents that affect walls
if(chemholder.reagents.has_reagent("thermite") || chemholder.reagents.has_reagent("plantbgone"))
wallList = new()
//pathing check
smokeFlow(location, targetTurfs, wallList)
//set the density of the cloud - for diluting reagents
density = max(1, targetTurfs.len / 4) //clamp the cloud density minimum to 1 so it cant multiply the reagents
//Admin messaging
var/contained = ""
for(var/reagent in carry.reagent_list)
contained += " [reagent] "
if(contained)
contained = "\[[contained]\]"
var/area/A = get_area(location)
var/where = "[A.name] | [location.x], [location.y]"
var/whereLink = "<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[location.x];Y=[location.y];Z=[location.z]'>[where]</a>"
if(carry.my_atom.fingerprintslast)
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
var/more = ""
if(M)
more = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</a>)"
message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
//------------------------------------------
//Runs the chem smoke effect
//
// Spawns damage over time loop for each reagent held in the cloud.
// Applies reagents to walls that affect walls (only thermite and plant-b-gone at the moment).
// Also calculates target locations to spawn the visual smoke effect on, so the whole area
// is covered fairly evenly.
//------------------------------------------
/datum/effect/effect/system/smoke_spread/chem/start()
if(!location) //kill grenade if it somehow ends up in nullspace
return
//reagent application - only run if there are extra reagents in the smoke
if(chemholder.reagents.reagent_list.len)
for(var/datum/reagent/R in chemholder.reagents.reagent_list)
var/proba = 100
var/runs = 5
//dilute the reagents according to cloud density
R.volume /= density
chemholder.reagents.update_total()
//apply wall affecting reagents to walls
if(R.id in list("thermite", "plantbgone"))
for(var/turf/T in wallList)
R.reaction_turf(T, R.volume)
//reagents that should be applied to turfs in a random pattern
if(R.id == "carbon")
proba = 75
else if(R.id in list("blood", "radium", "uranium"))
proba = 25
spawn(0)
for(var/i = 0, i < runs, i++)
for(var/turf/T in targetTurfs)
if(prob(proba))
R.reaction_turf(T, R.volume)
for(var/atom/A in T.contents)
if(istype(A, /obj/effect/effect/smoke/chem)) //skip the item if it is chem smoke
continue
else if(istype(A, /mob))
var/dist = cheap_pythag(T.x - location.x, T.y - location.y)
if(!dist)
dist = 1
R.reaction_mob(A, volume = R.volume / dist)
else if(istype(A, /obj))
R.reaction_obj(A, R.volume)
sleep(30)
//build smoke icon
var/color = mix_color_from_reagents(chemholder.reagents.reagent_list)
var/icon/I
if(color)
I = icon('icons/effects/chemsmoke.dmi')
I += color
else
I = icon('icons/effects/96x96.dmi', "smoke")
//distance between each smoke cloud
var/const/arcLength = 2.3559
//calculate positions for smoke coverage - then spawn smoke
for(var/i = 0, i < range, i++)
var/radius = i * 1.5
if(!radius)
spawn(0)
spawnSmoke(location, I, 1)
continue
var/offset = 0
var/points = round((radius * 2 * PI) / arcLength)
var/angle = round(ToDegrees(arcLength / radius), 1)
if(!IsInteger(radius))
offset = 45 //degrees
for(var/j = 0, j < points, j++)
var/a = (angle * j) + offset
var/x = round(radius * cos(a) + location.x, 1)
var/y = round(radius * sin(a) + location.y, 1)
var/turf/T = locate(x,y,location.z)
if(!T)
continue
if(T in targetTurfs)
spawn(0)
spawnSmoke(T, I, range)
//------------------------------------------
// Randomizes and spawns the smoke effect.
// Also handles deleting the smoke once the effect is finished.
//------------------------------------------
/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1)
var/obj/effect/effect/smoke/chem/smoke = new(location)
if(chemholder.reagents.reagent_list.len)
chemholder.reagents.copy_to(smoke, chemholder.reagents.total_volume / dist, safety = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents
smoke.icon = I
smoke.layer = 6
smoke.dir = pick(cardinal)
smoke.pixel_x = -32 + rand(-8,8)
smoke.pixel_y = -32 + rand(-8,8)
walk_to(smoke, T)
smoke.opacity = 1 //switching opacity on after the smoke has spawned, and then
sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner
smoke.opacity = 0 // lighting and view range updates
fadeOut(smoke)
smoke.delete()
//------------------------------------------
// Fades out the smoke smoothly using it's alpha variable.
//------------------------------------------
/datum/effect/effect/system/smoke_spread/chem/proc/fadeOut(var/atom/A, var/frames = 16)
var/step = A.alpha / frames
for(var/i = 0, i < frames, i++)
A.alpha -= step
sleep(world.tick_lag)
return
//------------------------------------------
// Smoke pathfinder. Uses a flood fill method based on zones to
// quickly check what turfs the smoke (airflow) can actually reach.
//------------------------------------------
/datum/effect/effect/system/smoke_spread/chem/proc/smokeFlow()
var/list/pending = new()
var/list/complete = new()
pending += location
while(pending.len)
for(var/turf/simulated/current in pending)
for(var/D in cardinal)
var/turf/simulated/target = get_step(current, D)
if(wallList)
if(istype(target, /turf/simulated/wall))
if(!(target in wallList))
wallList += target
continue
if(!target.zone)
continue
if(target in pending)
continue
if(target in complete)
continue
if(!(target in targetTurfs))
continue
pending += target
pending -= current
complete += current
targetTurfs = complete
return
+2 -116
View File
@@ -201,7 +201,8 @@ steam.start() -- spawns the effect
sleep(5)
step(sparks,direction)
spawn(20)
sparks.delete()
if(sparks)
sparks.delete()
src.total_sparks--
@@ -379,121 +380,6 @@ steam.start() -- spawns the effect
/datum/effect/effect/system/smoke_spread/mustard
smoke_type = /obj/effect/effect/smoke/mustard
/////////////////////////////////////////////
// Chem smoke
/////////////////////////////////////////////
/obj/effect/effect/smoke/chem
icon = 'icons/effects/chemsmoke.dmi'
/obj/effect/effect/smoke/chem/New()
..()
var/datum/reagents/R = new/datum/reagents(500)
reagents = R
R.my_atom = src
return
/obj/effect/effect/smoke/chem/proc/applyReagents()
if(reagents.reagent_list.len)
for(var/atom/A in view(1, src))
if(!istype(A, src.type))
if(reagents.has_reagent("radium")||reagents.has_reagent("uranium")||reagents.has_reagent("carbon")||reagents.has_reagent("thermite"))//Prevents unholy radium spam by reducing the number of 'greenglows' down to something reasonable -Sieve
if(prob(5))
reagents.reaction(A)
else
reagents.reaction(A)
/obj/effect/effect/smoke/chem/affect(mob/living/carbon/M as mob )
reagents.reaction(M)
/datum/effect/effect/system/smoke_spread/chem
smoke_type = /obj/effect/effect/smoke/chem
var/obj/chemholder
New()
..()
chemholder = new/obj()
var/datum/reagents/R = new/datum/reagents(500)
chemholder.reagents = R
R.my_atom = chemholder
set_up(var/datum/reagents/carry = null, n = 5, c = 0, loca, direct)
if(n > 20)
n = 20
number = n
cardinals = c
carry.copy_to(chemholder, carry.total_volume)
if(istype(loca, /turf/))
location = loca
else
location = get_turf(loca)
if(direct)
direction = direct
var/contained = ""
for(var/reagent in carry.reagent_list)
contained += " [reagent] "
if(contained)
contained = "\[[contained]\]"
var/area/A = get_area(location)
var/where = "[A.name] | [location.x], [location.y]"
var/whereLink = "<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[location.x];Y=[location.y];Z=[location.z]'>[where]</a>"
if(carry.my_atom.fingerprintslast)
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
var/more = ""
if(M)
more = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</a>)"
message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
start()
var/i = 0
var/color = mix_color_from_reagents(chemholder.reagents.reagent_list)
for(i=0, i<src.number, i++)
if(src.total_smoke > 20)
return
spawn(0)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/smoke/chem/smoke = new /obj/effect/effect/smoke/chem(src.location)
src.total_smoke++
var/direction = src.direction
if(!direction)
if(src.cardinals)
direction = pick(cardinal)
else
direction = pick(alldirs)
if(chemholder.reagents.total_volume != 1) // can't split 1 very well
chemholder.reagents.copy_to(smoke, chemholder.reagents.total_volume / number, safety = 1) // copy reagents to each smoke, divide evenly
if(color)
smoke.icon += color // give the smoke color, if it has any to begin with
else
// if no color, just use the old smoke icon
smoke.icon = 'icons/effects/96x96.dmi'
smoke.icon_state = "smoke"
for(i=0, i<pick(0,1,1,1,2,2,2,3), i++)
sleep(10)
step(smoke,direction)
//apply the reagents to the environment after the smoke has stopped moving - to reduce reagent spam
for(i=0, i<2 + pick(0,1,), i++)
smoke.applyReagents()
sleep(20)
sleep(60)
smoke.delete()
src.total_smoke--
/////////////////////////////////////////////
-3
View File
@@ -133,9 +133,6 @@ move an amendment</a> to the drawing.</p>
move_turfs_to_area(turfs, A)
A.always_unpowered = 0
for(var/turf/T in A.contents)
T.lighting_changed = 1
lighting_controller.changed_turfs += T
spawn(5)
//ma = A.master ? "[A.master]" : "(null)"
+2 -1
View File
@@ -482,7 +482,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
return 0
if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that.
U.unset_machine()
ui.close()
if(ui)
ui.close()
return 0
add_fingerprint(U)
@@ -21,6 +21,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon = 'icons/obj/cigarettes.dmi'
icon_state = "match_unlit"
var/lit = 0
var/burnt = 0
var/smoketime = 5
w_class = 1.0
origin_tech = "materials=1"
@@ -30,24 +31,27 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
icon_state = "match_burnt"
lit = -1
processing_objects.Remove(src)
burn_out()
return
if(location)
location.hotspot_expose(700, 5)
return
/obj/item/weapon/match/dropped(mob/user as mob)
if(lit == 1)
lit = -1
damtype = "brute"
icon_state = "match_burnt"
item_state = "cigoff"
name = "burnt match"
desc = "A match. This one has seen better days."
if(lit)
burn_out()
return ..()
/obj/item/weapon/match/proc/burn_out()
lit = 0
burnt = 1
damtype = "brute"
icon_state = "match_burnt"
item_state = "cigoff"
name = "burnt match"
desc = "A match. This one has seen better days."
processing_objects.Remove(src)
//////////////////
//FINE SMOKABLES//
//////////////////
@@ -419,4 +423,4 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(lit)
user.SetLuminosity(user.luminosity-2)
SetLuminosity(2)
return
return
@@ -185,7 +185,7 @@
H.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been wrapped with [src.name] by [user.name] ([user.ckey])</font>")
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to wrap [H.name] ([H.ckey])</font>")
log_attack("[user.name] ([user.ckey]) used the [src.name] to wrap [H.name] ([H.ckey])")
msg_admin_attack("[key_name(user)] used [src] to wrap [key_name(H)]")
else
user << "\blue You need more paper."
@@ -161,6 +161,10 @@
if( A == src ) continue
src.reagents.reaction(A, 1, 10)
if(istype(loc, /mob/living/carbon)) //drop dat grenade if it goes off in your hand
var/mob/living/carbon/C = loc
C.drop_from_inventory(src)
C.throw_mode_off()
invisibility = INVISIBILITY_MAXIMUM //Why am i doing this?
spawn(50) //To make sure all reagents can work
+27 -2
View File
@@ -54,7 +54,7 @@
C.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been handcuffed (attempt) by [user.name] ([user.ckey])</font>")
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Attempted to handcuff [C.name] ([C.ckey])</font>")
log_attack("[user.name] ([user.ckey]) Attempted to handcuff [C.name] ([C.ckey])")
msg_admin_attack("[key_name(user)] attempted to handcuff [key_name(C)]")
var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( )
O.source = user
@@ -92,6 +92,31 @@
return
return
var/last_chew = 0
/mob/living/carbon/human/RestrainedClickOn(var/atom/A)
if (A != src) return ..()
if (last_chew + 26 > world.time) return
var/mob/living/carbon/human/H = A
if (!H.handcuffed) return
if (H.a_intent != "hurt") return
if (H.zone_sel.selecting != "mouth") return
if (H.wear_mask) return
if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket)) return
var/datum/organ/external/O = H.organs_by_name[H.hand?"l_hand":"r_hand"]
if (!O) return
var/s = "\red [H.name] chews on \his [O.display_name]!"
H.visible_message(s, "\red You chew on your [O.display_name]!")
H.attack_log += text("\[[time_stamp()]\] <font color='red'>[s] ([H.ckey])</font>")
log_attack("[s] ([H.ckey])")
if(O.take_damage(3,0,1,"teeth marks"))
H:UpdateDamageIcon()
last_chew = world.time
/obj/item/weapon/handcuffs/cable
name = "cable restraints"
desc = "Looks like some cables tied together. Could be used to tie something up."
@@ -123,4 +148,4 @@
color = "#FFFFFF"
/obj/item/weapon/handcuffs/cyborg
dispenser = 1
dispenser = 1
@@ -173,7 +173,6 @@
desc = "Can hold security gear like handcuffs and flashes, with more pouches for more storage."
icon_state = "swatbelt"
item_state = "swatbelt"
var/obj/item/weapon/gun/holstered = null
storage_slots = 9
max_w_class = 3
max_combined_w_class = 21
@@ -195,40 +194,5 @@
"/obj/item/device/flashlight",
"/obj/item/device/pda",
"/obj/item/device/radio/headset",
"/obj/item/weapon/melee",
"/obj/item/taperoll/police",
"/obj/item/weapon/gun/energy/taser"
)
/obj/item/weapon/storage/belt/security/tactical/verb/holster()
set name = "Holster"
set category = "Object"
set src in usr
if(!istype(usr, /mob/living)) return
if(usr.stat) return
if(!holstered)
if(!istype(usr.get_active_hand(), /obj/item/weapon/gun))
usr << "\blue You need your gun equiped to holster it."
return
var/obj/item/weapon/gun/W = usr.get_active_hand()
if (!W.isHandgun())
usr << "\red This gun won't fit in \the belt!"
return
holstered = usr.get_active_hand()
usr.drop_item()
holstered.loc = src
usr.visible_message("\blue \The [usr] holsters \the [holstered].", "You holster \the [holstered].")
else
if(istype(usr.get_active_hand(),/obj) && istype(usr.get_inactive_hand(),/obj))
usr << "\red You need an empty hand to draw the gun!"
else
if(usr.a_intent == "hurt")
usr.visible_message("\red \The [usr] draws \the [holstered], ready to shoot!", \
"\red You draw \the [holstered], ready to shoot!")
else
usr.visible_message("\blue \The [usr] draws \the [holstered], pointing it at the ground.", \
"\blue You draw \the [holstered], pointing it at the ground.")
usr.put_in_hands(holstered)
holstered = null
"/obj/item/weapon/melee"
)
@@ -418,6 +418,7 @@
w_class = 1
flags = TABLEPASS
slot_flags = SLOT_BELT
can_hold = list("/obj/item/weapon/match")
New()
..()
@@ -425,8 +426,9 @@
new /obj/item/weapon/match(src)
attackby(obj/item/weapon/match/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/match) && W.lit == 0)
if(istype(W) && !W.lit && !W.burnt)
W.lit = 1
W.damtype = "burn"
W.icon_state = "match_lit"
processing_objects.Add(W)
W.update_icon()
@@ -173,7 +173,6 @@
/obj/item/weapon/storage/fancy/cigarettes/update_icon()
icon_state = "[initial(icon_state)][contents.len]"
desc = "There are [contents.len] cig\s left!"
return
/obj/item/weapon/storage/fancy/cigarettes/remove_from_storage(obj/item/W as obj, atom/new_location)
@@ -253,5 +252,4 @@
/obj/item/weapon/storage/lockbox/vials/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
update_icon()
update_icon()
+2 -2
View File
@@ -88,7 +88,7 @@
user.attack_log += "\[[time_stamp()]\]<font color='red'> Stunned [H.name] ([H.ckey]) with [src.name]</font>"
H.attack_log += "\[[time_stamp()]\]<font color='orange'> Stunned by [user.name] ([user.ckey]) with [src.name]</font>"
log_attack("[user.name] ([user.ckey]) stunned [H.name] ([H.ckey]) with [src.name]")
msg_admin_attack("[key_name(user)] stunned [key_name(H)] with [src.name]")
playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
if(charges < 1)
@@ -115,7 +115,7 @@
H.visible_message("<span class='danger'>[src], thrown by [foundmob.name], strikes [H] and stuns them!</span>")
H.attack_log += "\[[time_stamp()]\]<font color='orange'> Stunned by thrown [src.name] last touched by ([src.fingerprintslast])</font>"
log_attack("Flying [src.name], last touched by ([src.fingerprintslast]) stunned [H.name] ([H.ckey])" )
msg_admin_attack("Flying [src.name], last touched by ([src.fingerprintslast]) stunned [key_name(H)]" )
/obj/item/weapon/melee/baton/emp_act(severity)
switch(severity)
@@ -620,6 +620,35 @@ LOOK FOR SURGERY.DM*/
return
*/
/*
* Researchable Scalpels
*/
/obj/item/weapon/scalpel/laser1
name = "laser scalpel"
desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks basic and could be improved."
icon_state = "scalpel_laser1_on"
damtype = "fire"
/obj/item/weapon/scalpel/laser2
name = "laser scalpel"
desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks somewhat advanced."
icon_state = "scalpel_laser2_on"
damtype = "fire"
force = 12.0
/obj/item/weapon/scalpel/laser3
name = "laser scalpel"
desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks to be the pinnacle of precision energy cutlery!"
icon_state = "scalpel_laser3_on"
damtype = "fire"
force = 15.0
/obj/item/weapon/scalpel/manager
name = "incision management system"
desc = "A true extension of the surgeon's body, this marvel instantly and completely prepares an incision allowing for the immediate commencement of therapeutic steps."
icon_state = "scalpel_manager_on"
force = 7.5
/*
* Circular Saw
*/
@@ -819,4 +848,4 @@ LOOK FOR SURGERY.DM*/
throw_speed = 3
throw_range = 5
w_class = 2.0
attack_verb = list("attacked", "hit", "bludgeoned")
attack_verb = list("attacked", "hit", "bludgeoned")
@@ -104,7 +104,7 @@
M.Weaken(5)
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked with [src.name] by [user.name] ([user.ckey])</font>")
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to attack [M.name] ([M.ckey])</font>")
log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])")
msg_admin_attack("[key_name(user)] attacked [key_name(user)] with [src.name] (INTENT: [uppertext(user.a_intent)])")
src.add_fingerprint(user)
for(var/mob/O in viewers(M))
@@ -153,7 +153,7 @@
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
add_fingerprint(user)
if(blood_overlay && (blood_DNA.len >= 1)) //updates blood overlay, if any
if(blood_overlay && blood_DNA && (blood_DNA.len >= 1)) //updates blood overlay, if any
overlays.Cut()//this might delete other item overlays as well but eeeeeeeh
var/icon/I = new /icon(src.icon, src.icon_state)
@@ -265,4 +265,4 @@
H.update_inv_r_hand()
add_fingerprint(user)
return
return
+3 -1
View File
@@ -268,10 +268,12 @@
if(H.belt)
if(H.belt.clean_blood())
H.update_inv_belt(0)
H.clean_blood(washshoes)
else
if(M.wear_mask) //if the mob is not human, it cleans the mask without asking for bitflags
if(M.wear_mask.clean_blood())
M.update_inv_wear_mask(0)
M.clean_blood()
else
O.clean_blood()
@@ -413,4 +415,4 @@
/obj/structure/sink/puddle/attackby(obj/item/O as obj, mob/user as mob)
icon_state = "puddle-splash"
..()
icon_state = "puddle"
icon_state = "puddle"