Files
Aurora.3/code/modules/detectivework/tools/rag.dm
T
VMSolidus 201592f6bd Mob Destroy Refactoring (#22573)
Refactoring the entire destroy proc path from Mob Human all the way down
to Atom while trying to find the causes for the damn mob human hard
deletes. This PR comprehensively reorganizes every single stray
snowflake var used by /atom/ all the way to /mob/living/carbon/human,
and makes sure that every var that COULD store a reference, is now
cleared during the entirety of the Mob Destroy() parent hierarchy.

This may very well be the end of the lag war. 

In total, I've hunted down and cleared 39 hanging references between
/atom and /mob/living/carbon/human

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
2026-06-03 15:15:56 +00:00

312 lines
11 KiB
Plaintext

/obj/item/clothing/gloves
var/transfer_blood = 0
var/datum/weakref/bloody_hands_mob
/obj/item/clothing/shoes/
var/track_footprint = 0
/obj/item/reagent_containers/glass/rag
name = "rag"
desc = "For cleaning up messes, you suppose."
w_class = WEIGHT_CLASS_TINY
icon = 'icons/obj/janitor.dmi'
icon_state = "rag"
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 10
can_be_placed_into = null
atom_flags = ATOM_FLAG_OPEN_CONTAINER
item_flags = ITEM_FLAG_NO_BLUDGEON
unacidable = FALSE
fragile = FALSE
drop_sound = SFX_CLOTH_DROP
pickup_sound = SFX_CLOTH_PICKUP
var/on_fire = 0
var/burn_time = 20 //if the rag burns for too long it turns to ashes
var/cleantime = 30
var/last_clean
var/clean_msg = FALSE
/obj/item/reagent_containers/glass/rag/Initialize()
. = ..()
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/Destroy()
STOP_PROCESSING(SSprocessing, src) //so we don't continue turning to ash while gc'd
return ..()
/obj/item/reagent_containers/glass/rag/attack_self(mob/user)
if(on_fire)
user.visible_message(SPAN_WARNING("\The [user] stamps out \the [src]."), SPAN_WARNING("You stamp out \the [src]."))
user.unEquip(src)
extinguish()
else
remove_contents(user)
/obj/item/reagent_containers/glass/rag/attackby(obj/item/attacking_item, mob/user)
if(!on_fire && attacking_item.isFlameSource())
ignite()
if(on_fire)
visible_message(SPAN_WARNING("\The [user] lights \the [src] with \the [attacking_item]."))
else
to_chat(user, SPAN_WARNING("You manage to singe \the [src], but fail to light it."))
return TRUE
. = ..()
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/proc/update_name(var/base_name = initial(name))
SEND_SIGNAL(src, COMSIG_BASENAME_SETNAME, args)
if(on_fire)
name = "burning [base_name]"
else if(reagents.total_volume)
name = "damp [base_name]"
else
name = "dry [base_name]"
/obj/item/reagent_containers/glass/rag/update_icon()
if(on_fire)
icon_state = "[initial(icon_state)]_lit"
else if(reagents.total_volume)
icon_state = "[initial(icon_state)]_wet"
else
icon_state = "[initial(icon_state)]"
var/obj/item/reagent_containers/food/drinks/bottle/B = loc
if(istype(B))
B.update_icon()
/obj/item/reagent_containers/glass/rag/on_reagent_change()
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/proc/remove_contents(mob/user, atom/trans_dest = null)
if(!trans_dest && !user.loc)
return
if(reagents.total_volume)
var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]"
user.visible_message(SPAN_DANGER("\The [user] begins to wring out \the [src] over \the [target_text]."), SPAN_NOTICE("You begin to wring out \the [src] over \the [target_text]."))
if(do_after(user, reagents.total_volume*5)) //50 for a fully soaked rag
if(trans_dest)
reagents.trans_to(trans_dest, reagents.total_volume)
else
reagents.splash(user.loc, reagents.total_volume)
user.visible_message(SPAN_DANGER("\The [user] wrings out \the [src] over \the [target_text]."), SPAN_NOTICE("You finish wringing out \the [src]."))
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/proc/wipe_down(atom/A, mob/user)
if(!reagents.total_volume)
to_chat(user, SPAN_WARNING("\The [name] is dry!"))
else
if (!(last_clean && world.time < last_clean + 120) )
user.visible_message("<b>[user]</b> starts to wipe [A] with [src].")
clean_msg = TRUE
last_clean = world.time
else
clean_msg = FALSE
playsound(loc, 'sound/effects/mop.ogg', 25, 1)
update_name()
update_icon()
if(do_after(user,cleantime))
if(clean_msg)
user.visible_message("<b>[user]</b> finishes wiping [A].")
A.on_rag_wipe(src)
/obj/item/reagent_containers/glass/rag/attack(mob/living/target_mob, mob/living/user, target_zone)
if(isliving(target_mob))
var/mob/living/M = target_mob
if(on_fire)
user.visible_message(SPAN_DANGER("\The [user] hits \the [target_mob] with \the [src]!"))
user.do_attack_animation(src)
M.IgniteMob()
else if(ishuman(M))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting)
if(LAZYLEN(affecting.wounds))
for (var/datum/wound/W in affecting.wounds)
if(W.bandaged || W.clamped)
continue
to_chat(user, SPAN_NOTICE("You begin to bandage \a [W.desc] on [M]'s [affecting.name] with a rag."))
if(!do_mob(user, M, W.damage/10)) // takes twice as long as a normal bandage
to_chat(user, SPAN_NOTICE("You must stand still to bandage wounds."))
return
for(var/_R in reagents.reagent_volumes)
var/singleton/reagent/R = GET_SINGLETON(_R)
var/strength = R.germ_adjust * reagents.reagent_volumes[_R]/4
if(ispath(_R, /singleton/reagent/alcohol/ethanol))
var/singleton/reagent/alcohol/ethanol/A = R
strength = strength * (A.strength/100)
W.germ_level -= min(strength, W.germ_level)//Clean the wound a bit.
if (W.germ_level <= 0)
W.disinfected = TRUE//The wound becomes disinfected if fully cleaned
break
reagents.trans_to_mob(H, reagents.total_volume*0.75, CHEM_TOUCH) // most of it gets on the skin
reagents.trans_to_mob(H, reagents.total_volume*0.25, CHEM_BLOOD) // some gets in the wound
user.visible_message(SPAN_NOTICE("\The [user] bandages \a [W.desc] on [M]'s [affecting.name] with [src], tying it in place."), \
SPAN_NOTICE("You bandage \a [W.desc] on [M]'s [affecting.name] with [src], tying it in place."))
W.bandage()
qdel(src) // the rag is used up, it'll be all bloody and useless after
return // we can only do one at a time
else if(reagents.total_volume)
if(user.zone_sel.selecting == BP_MOUTH && !(M.wear_mask && M.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT))
user.do_attack_animation(src)
user.visible_message(
SPAN_DANGER("\The [user] smothers [target_mob] with [src]!"),
SPAN_WARNING("You smother [target_mob] with [src]!"),
"You hear some struggling and muffled cries of surprise."
)
//it's inhaled, so... maybe CHEM_BLOOD doesn't make a whole lot of sense but it's the best we can do for now
//^HA HA HA
reagents.trans_to_mob(target_mob, amount_per_transfer_from_this, CHEM_BREATHE)
update_name()
update_icon()
else
wipe_down(target_mob, user)
return
return ..()
/obj/item/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity)
if(!proximity)
return
if(istype(A, /obj/structure/sink))
return
else if(istype(A, /obj/structure/reagent_dispensers) || istype(A, /obj/structure/mopbucket) || istype(A, /obj/item/reagent_containers/glass))
if(!REAGENTS_FREE_SPACE(reagents))
to_chat(user, SPAN_WARNING("\The [src] is already soaked."))
return
if(A.reagents && A.reagents.trans_to_obj(src, reagents.maximum_volume))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
user.visible_message(SPAN_NOTICE("\The [user] soaks \the [src] using \the [A]."), SPAN_NOTICE("You soak \the [src] using \the [A]."))
update_name()
update_icon()
return
else if(!on_fire && istype(A) && (src in user))
if(A.is_open_container() && !(A in user))
remove_contents(user, A)
else if(!ismob(A)) //mobs are handled in attack() - this prevents us from wiping down people while smothering them.
wipe_down(A, user)
return
/obj/item/reagent_containers/glass/rag/fire_act(exposed_temperature, exposed_volume)
. = ..()
if(exposed_temperature >= 50 + T0C)
ignite()
if(exposed_temperature >= 900 + T0C)
new /obj/effect/decal/cleanable/ash(get_turf(src))
qdel(src)
//rag must have a minimum of 2 units fuel and at least 80% of the reagents must be fuel.
//maybe generalize flammable reagents someday
/obj/item/reagent_containers/glass/rag/proc/can_ignite()
var/fuel = 0
for(var/fuel_type in reagents.reagent_volumes)
if(ispath(fuel_type, /singleton/reagent/fuel) || ispath(fuel_type, /singleton/reagent/alcohol))
fuel += reagents.reagent_volumes[fuel_type]
return (fuel >= 2 && fuel >= reagents.total_volume*0.8)
/obj/item/reagent_containers/glass/rag/proc/ignite()
if(on_fire)
return
if(!can_ignite())
return
//also copied from matches
if(REAGENT_VOLUME(reagents, /singleton/reagent/toxin/phoron)) // the phoron explodes when exposed to fire
visible_message(SPAN_DANGER("\The [src] conflagrates violently!"))
var/datum/effect/effect/system/reagents_explosion/e = new()
e.set_up(round(REAGENT_VOLUME(reagents, /singleton/reagent/toxin/phoron) / 2.5, 1), get_turf(src), 0, 0)
e.start()
qdel(src)
return
START_PROCESSING(SSprocessing, src)
set_light(2, null, "#E38F46")
on_fire = 1
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/proc/extinguish()
STOP_PROCESSING(SSprocessing, src)
set_light(0)
on_fire = 0
//rags sitting around with 1 second of burn time left is dumb.
//ensures players always have a few seconds of burn time left when they light their rag
if(burn_time <= 5)
visible_message(SPAN_WARNING("\The [src] falls apart!"))
if(istype(loc, /obj/item/reagent_containers/food/drinks/bottle))
var/obj/item/reagent_containers/food/drinks/bottle/B = loc
B.delete_rag()
else
new /obj/effect/decal/cleanable/ash(get_turf(src))
qdel(src)
return
update_name()
update_icon()
/obj/item/reagent_containers/glass/rag/process(seconds_per_tick)
if(!can_ignite())
visible_message(SPAN_WARNING("\The [src] burns out."))
extinguish()
//copied from matches
if(isliving(loc))
var/mob/living/M = loc
M.IgniteMob()
var/turf/location = get_turf(src)
if(location)
location.hotspot_expose(700, 5)
if(burn_time <= 0)
STOP_PROCESSING(SSprocessing, src)
if(istype(loc, /obj/item/reagent_containers/food/drinks/bottle))
var/obj/item/reagent_containers/food/drinks/bottle/B = loc
B.delete_rag()
else
new /obj/effect/decal/cleanable/ash(location)
qdel(src)
return
for(var/fuel_type in reagents.reagent_volumes)
if(ispath(fuel_type, /singleton/reagent/fuel) || ispath(fuel_type, /singleton/reagent/alcohol))
reagents.remove_reagent(fuel_type, ((reagents.maximum_volume/25) * seconds_per_tick))
break
update_name()
update_icon()
burn_time -= seconds_per_tick
/obj/item/reagent_containers/glass/rag/advanced
name = "microfiber cloth"
desc = "A synthetic fiber cloth; the split fibers and the size of the individual filaments make it more effective for cleaning purposes."
w_class = WEIGHT_CLASS_TINY
icon = 'icons/obj/janitor.dmi'
icon_state = "advrag"
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5)
volume = 10
cleantime = 15
/obj/item/reagent_containers/glass/rag/advanced/idris
name = "Idris advanced service cloth"
desc = "An advanced rag developed and sold by Idris Incorporated at a steep price. Its dry-clean design and advanced insulating synthetic weave make this the pinnacle of service cloths for any self-respecting chef or bartender!"
icon_state = "idrisrag"
volume = 15
/obj/item/reagent_containers/glass/rag/handkerchief
name = "handkerchief"
desc = "For cleaning a lady's hand, your bruised ego or a crime scene."
volume = 5
icon_state = "handkerchief"