mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-10 01:12:18 +00:00
Currently, a mouse gnawing open a box to get its contents generates about a screen's worth of chatspam. And the same applies to eating a box of raisins or similar large meal. I feel this isn't appropriate for the size of the creature nor the severity of the act. In any case ive come up with a better method. Main attraction of this PR, is that the box nibbling no longer uses visible messages, it only outputs to chat once, when it finally ruptures. In the meantime, any nibbling which doesn't break the box will instead shake it around and make a nibbling sound. Shaking code stolen from locker resist Mice nibbling things is a quiet clicking noise, easy to ignore. so its unintrusive Update: I've now extended this to all animal nibbling, not only boxes, but also on food too. To cut down on chatspam from small animals eating things. The result of this change is that a creature eating a box or a meal is simultaneously easier than before to notice, if you care about it. And easier to ignore, if you don't care. Also included, two bugfixes: Re-adds the reverted console canpass behaviour that was lost a couple patches ago adds a little robustness fix to animals, to deal with an issue where they were getting their stat set back to 0 without properly waking up. still not sure why it happens but now the icons will properly update when they do
407 lines
12 KiB
Plaintext
407 lines
12 KiB
Plaintext
/obj/structure/closet
|
|
name = "closet"
|
|
desc = "It's a basic storage unit."
|
|
icon = 'icons/obj/closet.dmi'
|
|
icon_state = "closed"
|
|
density = 1
|
|
w_class = 5
|
|
var/icon_closed = "closed"
|
|
var/icon_opened = "open"
|
|
var/opened = 0
|
|
var/welded = 0
|
|
var/wall_mounted = 0 //never solid (You can always pass over it)
|
|
var/health = 100
|
|
var/breakout = 0 //if someone is currently breaking out. mutex
|
|
var/storage_capacity = 40 //Tying this to mob sizes was dumb
|
|
//This is so that someone can't pack hundreds of items in a locker/crate
|
|
//then open it in a populated area to crash clients.
|
|
var/open_sound = 'sound/machines/click.ogg'
|
|
var/close_sound = 'sound/machines/click.ogg'
|
|
|
|
var/store_misc = 1
|
|
var/store_items = 1
|
|
var/store_mobs = 1
|
|
|
|
var/const/default_mob_size = 15
|
|
|
|
/obj/structure/closet/LateInitialize()
|
|
if (opened) // if closed, any item at the crate's loc is put in the contents
|
|
return
|
|
var/obj/I
|
|
for(I in src.loc)
|
|
if (!istype(I, /obj/item) && !istype(I, /obj/random))
|
|
continue
|
|
if (I.density || I.anchored || I == src)
|
|
continue
|
|
I.forceMove(src)
|
|
// adjust locker size to hold all items with 5 units of free store room
|
|
var/content_size = 0
|
|
for(I in src.contents)
|
|
content_size += Ceiling(I.w_class/2)
|
|
if(content_size > storage_capacity-5)
|
|
storage_capacity = content_size + 5
|
|
|
|
/obj/structure/closet/Initialize(mapload)
|
|
..()
|
|
fill()
|
|
return mapload ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_NORMAL
|
|
|
|
// Fill lockers with this.
|
|
/obj/structure/closet/proc/fill()
|
|
|
|
/obj/structure/closet/examine(mob/user)
|
|
if(..(user, 1) && !opened)
|
|
var/content_size = 0
|
|
for(var/obj/item/I in src.contents)
|
|
if(!I.anchored)
|
|
content_size += Ceiling(I.w_class/2)
|
|
if(!content_size)
|
|
user << "It is empty."
|
|
else if(storage_capacity > content_size*4)
|
|
user << "It is barely filled."
|
|
else if(storage_capacity > content_size*2)
|
|
user << "It is less than half full."
|
|
else if(storage_capacity > content_size)
|
|
user << "There is still some free space."
|
|
else
|
|
user << "It is full."
|
|
|
|
/obj/structure/closet/proc/stored_weight()
|
|
var/content_size = 0
|
|
for(var/obj/item/I in src.contents)
|
|
if(!I.anchored)
|
|
content_size += Ceiling(I.w_class/2)
|
|
return content_size
|
|
|
|
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
|
if(air_group || (height==0 || wall_mounted)) return 1
|
|
return (!density)
|
|
|
|
/obj/structure/closet/proc/can_open()
|
|
if(src.welded)
|
|
return 0
|
|
return 1
|
|
|
|
/obj/structure/closet/proc/can_close()
|
|
for(var/obj/structure/closet/closet in get_turf(src))
|
|
if(closet != src)
|
|
return 0
|
|
return 1
|
|
|
|
/obj/structure/closet/proc/dump_contents()
|
|
//Cham Projector Exception
|
|
for(var/obj/effect/dummy/chameleon/AD in src)
|
|
AD.forceMove(src.loc)
|
|
|
|
for(var/obj/I in src)
|
|
I.forceMove(src.loc)
|
|
|
|
for(var/mob/M in src)
|
|
M.forceMove(src.loc)
|
|
if(M.client)
|
|
M.client.eye = M.client.mob
|
|
M.client.perspective = MOB_PERSPECTIVE
|
|
|
|
/obj/structure/closet/proc/open()
|
|
if(src.opened)
|
|
return 0
|
|
|
|
if(!src.can_open())
|
|
return 0
|
|
|
|
src.dump_contents()
|
|
|
|
src.icon_state = src.icon_opened
|
|
src.opened = 1
|
|
playsound(src.loc, open_sound, 15, 1, -3)
|
|
density = 0
|
|
return 1
|
|
|
|
/obj/structure/closet/proc/close()
|
|
if(!src.opened)
|
|
return 0
|
|
if(!src.can_close())
|
|
return 0
|
|
|
|
var/stored_units = 0
|
|
|
|
if(store_misc)
|
|
stored_units += store_misc(stored_units)
|
|
if(store_items)
|
|
stored_units += store_items(stored_units)
|
|
if(store_mobs)
|
|
stored_units += store_mobs(stored_units)
|
|
|
|
src.icon_state = src.icon_closed
|
|
src.opened = 0
|
|
|
|
playsound(src.loc, close_sound, 15, 1, -3)
|
|
density = 1
|
|
return 1
|
|
|
|
//Cham Projector Exception
|
|
/obj/structure/closet/proc/store_misc(var/stored_units)
|
|
var/added_units = 0
|
|
for(var/obj/effect/dummy/chameleon/AD in src.loc)
|
|
if((stored_units + added_units) > storage_capacity)
|
|
break
|
|
AD.forceMove(src)
|
|
added_units++
|
|
return added_units
|
|
|
|
/obj/structure/closet/proc/store_items(var/stored_units)
|
|
var/added_units = 0
|
|
for(var/obj/item/I in src.loc)
|
|
var/item_size = Ceiling(I.w_class / 2)
|
|
if(stored_units + added_units + item_size > storage_capacity)
|
|
continue
|
|
if(!I.anchored)
|
|
I.forceMove(src)
|
|
added_units += item_size
|
|
return added_units
|
|
|
|
/obj/structure/closet/proc/store_mobs(var/stored_units)
|
|
var/added_units = 0
|
|
for(var/mob/living/M in src.loc)
|
|
if(M.buckled || M.pinned.len)
|
|
continue
|
|
if(stored_units + added_units + M.mob_size > storage_capacity)
|
|
break
|
|
if(M.client)
|
|
M.client.perspective = EYE_PERSPECTIVE
|
|
M.client.eye = src
|
|
M.forceMove(src)
|
|
added_units += M.mob_size
|
|
return added_units
|
|
|
|
/obj/structure/closet/proc/toggle(mob/user as mob)
|
|
if(!(src.opened ? src.close() : src.open()))
|
|
user << "<span class='notice'>It won't budge!</span>"
|
|
return
|
|
update_icon()
|
|
return 1
|
|
|
|
// this should probably use dump_contents()
|
|
/obj/structure/closet/ex_act(severity)
|
|
switch(severity)
|
|
if(1)
|
|
health -= rand(120, 240)
|
|
if(2)
|
|
health -= rand(60, 120)
|
|
if(3)
|
|
health -= rand(30, 60)
|
|
|
|
if (health <= 0)
|
|
for (var/atom/movable/A as mob|obj in src)
|
|
A.forceMove(src.loc)
|
|
A.ex_act(severity + 1)
|
|
qdel(src)
|
|
|
|
/obj/structure/closet/proc/damage(var/damage)
|
|
health -= damage
|
|
if(health <= 0)
|
|
for(var/atom/movable/A in src)
|
|
A.forceMove(src.loc)
|
|
qdel(src)
|
|
|
|
/obj/structure/closet/bullet_act(var/obj/item/projectile/Proj)
|
|
var/proj_damage = Proj.get_structure_damage()
|
|
if(!proj_damage)
|
|
return
|
|
|
|
..()
|
|
damage(proj_damage)
|
|
|
|
/obj/structure/closet/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
if(src.opened)
|
|
if(istype(W, /obj/item/weapon/grab))
|
|
var/obj/item/weapon/grab/G = W
|
|
src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
|
|
return 0
|
|
if(istype(W,/obj/item/tk_grab))
|
|
return 0
|
|
if(istype(W, /obj/item/weapon/weldingtool))
|
|
var/obj/item/weapon/weldingtool/WT = W
|
|
if(!WT.remove_fuel(0,user))
|
|
if(WT.isOn())
|
|
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
|
|
return
|
|
else
|
|
new /obj/item/stack/material/steel(src.loc)
|
|
for(var/mob/M in viewers(src))
|
|
M.show_message("<span class='notice'>\The [src] has been cut apart by [user] with \the [WT].</span>", 3, "You hear welding.", 2)
|
|
qdel(src)
|
|
return
|
|
if(istype(W, /obj/item/weapon/storage/laundry_basket) && W.contents.len)
|
|
var/obj/item/weapon/storage/laundry_basket/LB = W
|
|
var/turf/T = get_turf(src)
|
|
for(var/obj/item/I in LB.contents)
|
|
LB.remove_from_storage(I, T)
|
|
user.visible_message("<span class='notice'>[user] empties \the [LB] into \the [src].</span>", \
|
|
"<span class='notice'>You empty \the [LB] into \the [src].</span>", \
|
|
"<span class='notice'>You hear rustling of clothes.</span>")
|
|
return
|
|
if(!dropsafety(W))
|
|
return
|
|
usr.drop_item()
|
|
if(W)
|
|
W.forceMove(src.loc)
|
|
else if(istype(W, /obj/item/weapon/packageWrap))
|
|
return
|
|
else if(istype(W, /obj/item/weapon/weldingtool))
|
|
var/obj/item/weapon/weldingtool/WT = W
|
|
if(!WT.remove_fuel(0,user))
|
|
if(!WT.isOn())
|
|
return
|
|
else
|
|
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
|
|
return
|
|
src.welded = !src.welded
|
|
src.update_icon()
|
|
for(var/mob/M in viewers(src))
|
|
M.show_message("<span class='warning'>[src] has been [welded?"welded shut":"unwelded"] by [user.name].</span>", 3, "You hear welding.", 2)
|
|
else
|
|
src.attack_hand(user)
|
|
return
|
|
|
|
/obj/structure/closet/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob)
|
|
if(istype(O, /obj/screen)) //fix for HUD elements making their way into the world -Pete
|
|
return
|
|
if(O.loc == user)
|
|
return
|
|
if(user.restrained() || user.stat || user.weakened || user.stunned || user.paralysis)
|
|
return
|
|
if((!( istype(O, /atom/movable) ) || O.anchored || !Adjacent(user) || !Adjacent(O) || !user.Adjacent(O) || user.contents.Find(src)))
|
|
return
|
|
if(!isturf(user.loc)) // are you in a container/closet/pod/etc?
|
|
return
|
|
if(!src.opened)
|
|
return
|
|
if(istype(O, /obj/structure/closet))
|
|
return
|
|
step_towards(O, src.loc)
|
|
if(user != O)
|
|
user.show_viewers("<span class='danger'>[user] stuffs [O] into [src]!</span>")
|
|
src.add_fingerprint(user)
|
|
return
|
|
|
|
/obj/structure/closet/attack_ai(mob/user)
|
|
if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Robots can open/close it, but not the AI.
|
|
attack_hand(user)
|
|
|
|
/obj/structure/closet/relaymove(mob/user as mob)
|
|
if(user.stat || !isturf(src.loc))
|
|
return
|
|
|
|
if(!src.open())
|
|
user << "<span class='notice'>It won't budge!</span>"
|
|
|
|
/obj/structure/closet/attack_hand(mob/user as mob)
|
|
src.add_fingerprint(user)
|
|
return src.toggle(user)
|
|
|
|
// tk grab then use on self
|
|
/obj/structure/closet/attack_self_tk(mob/user as mob)
|
|
src.add_fingerprint(user)
|
|
if(!src.toggle())
|
|
usr << "<span class='notice'>It won't budge!</span>"
|
|
|
|
/obj/structure/closet/verb/verb_toggleopen()
|
|
set src in oview(1)
|
|
set category = "Object"
|
|
set name = "Toggle Open"
|
|
|
|
if(!usr.canmove || usr.stat || usr.restrained())
|
|
return
|
|
|
|
if(ishuman(usr))
|
|
src.add_fingerprint(usr)
|
|
src.toggle(usr)
|
|
else
|
|
usr << "<span class='warning'>This mob type can't use this verb.</span>"
|
|
|
|
/obj/structure/closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
|
|
cut_overlays()
|
|
if(!opened)
|
|
icon_state = icon_closed
|
|
if(welded)
|
|
add_overlay("welded")
|
|
else
|
|
icon_state = icon_opened
|
|
|
|
/obj/structure/closet/hear_talk(mob/M as mob, text, verb, datum/language/speaking)
|
|
for (var/atom/A in src)
|
|
if(istype(A,/obj/))
|
|
var/obj/O = A
|
|
O.hear_talk(M, text, verb, speaking)
|
|
|
|
/obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys", var/wallbreaker)
|
|
if(!damage || !wallbreaker)
|
|
return
|
|
user.do_attack_animation(src)
|
|
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")
|
|
dump_contents()
|
|
QDEL_IN(src, 1)
|
|
return 1
|
|
|
|
/obj/structure/closet/proc/req_breakout()
|
|
|
|
if(opened)
|
|
return 0 //Door's open... wait, why are you in it's contents then?
|
|
if(welded)
|
|
return 1 //closed but not welded...
|
|
if(breakout)
|
|
return -1 //Already breaking out.
|
|
return 0
|
|
|
|
/obj/structure/closet/proc/mob_breakout(var/mob/living/escapee)
|
|
|
|
//Improved by nanako
|
|
//Now it actually works, also locker breakout time stacks with locking and welding
|
|
//This means secure lockers are more useful for imprisoning people
|
|
var/breakout_time = 1.5 * req_breakout()//1.5 minutes if locked or welded, 3 minutes if both
|
|
if(breakout_time <= 0)
|
|
return
|
|
|
|
|
|
|
|
//okay, so the closet is either welded or locked... resist!!!
|
|
escapee.next_move = world.time + 100
|
|
escapee.last_special = world.time + 100
|
|
escapee << "<span class='warning'>You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)</span>"
|
|
visible_message("<span class='danger'>The [src] begins to shake violently!</span>")
|
|
|
|
breakout = 1
|
|
for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2
|
|
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
|
|
animate_shake()
|
|
|
|
if(!do_after(escapee, 50)) //5 seconds
|
|
breakout = 0
|
|
return
|
|
if(!escapee || escapee.stat || escapee.loc != src)
|
|
breakout = 0
|
|
return //closet/user destroyed OR user dead/unconcious OR user no longer in closet OR closet opened
|
|
//Perform the same set of checks as above for weld and lock status to determine if there is even still a point in 'resisting'...
|
|
if(!req_breakout())
|
|
breakout = 0
|
|
return
|
|
|
|
//Well then break it!
|
|
breakout = 0
|
|
escapee << "<span class='warning'>You successfully break out!</span>"
|
|
visible_message("<span class='danger'>\the [escapee] successfully broke out of \the [src]!</span>")
|
|
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
|
|
break_open()
|
|
animate_shake()
|
|
|
|
/obj/structure/closet/proc/break_open()
|
|
welded = 0
|
|
update_icon()
|
|
//Do this to prevent contents from being opened into nullspace (read: bluespace)
|
|
if(istype(loc, /obj/structure/bigDelivery))
|
|
var/obj/structure/bigDelivery/BD = loc
|
|
BD.unwrap()
|
|
open()
|
|
|