Files
Aurora.3/code/game/objects/structures/crates_lockers/closets.dm
T
Mykhailo BykhovtsevandErki 88267a1a6a Small map, and sprite fixes. Welder fixes (#3887)
Fixed fire alarm in virology #3875

Fixed random pixel on glasses #3872

Fixed welder issue #3888. Plus explored further issue with welder, fixing it. Small logic optimization.

Fixed firelocker icon not being updated with welded overlay, even so they have been welded

Welding interaction with closets was reworked, almost all secure closets except for detective's, barternder's now work with welding same way as closets/crates.

Coffins, and wooden closets of any kind can no longer be welded shut.

Clean up of some code using src as reference, and :
2017-11-30 06:50:55 +02:00

455 lines
13 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/welded_overlay_state = "welded"
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/effects/locker_open.ogg'
var/close_sound = 'sound/effects/locker_close.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 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 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 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 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(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(loc)
for(var/obj/I in src)
I.forceMove(loc)
for(var/mob/M in src)
M.forceMove(loc)
if(M.client)
M.client.eye = M.client.mob
M.client.perspective = MOB_PERSPECTIVE
/obj/structure/closet/proc/open()
if(opened)
return 0
if(!can_open())
return 0
dump_contents()
icon_state = icon_opened
opened = 1
playsound(loc, open_sound, 15, 1, -3)
density = 0
return 1
/obj/structure/closet/proc/close()
if(!opened)
return 0
if(!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)
icon_state = icon_closed
opened = 0
playsound(loc, close_sound, 25, 0, -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 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 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 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(!(opened ? close() : 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(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(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(opened)
if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
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(iswelder(W))
var/obj/item/weapon/weldingtool/WT = W
if(WT.isOn())
user.visible_message(
"<span class='warning'>[user] begins cutting [src] apart.</span>",
"<span class='notice'>You begin cutting [src] apart.</span>",
"You hear a welding torch on metal."
)
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
if (!do_after(user, 2 SECONDS, act_target = src, extra_checks = CALLBACK(src, .proc/is_open)))
return
if(!WT.remove_fuel(0,user))
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
return
else
new /obj/item/stack/material/steel(loc)
user.visible_message(
"<span class='notice'>[src] has been cut apart by [user] with [WT].</span>",
"<span class='notice'>You cut apart [src] with [WT].</span>"
)
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(loc)
else if(istype(W, /obj/item/weapon/packageWrap))
return
else if(iswelder(W))
var/obj/item/weapon/weldingtool/WT = W
if(WT.isOn())
user.visible_message(
"<span class='warning'>[user] begins welding [src] [welded ? "open" : "shut"].</span>",
"<span class='notice'>You begin welding [src] [welded ? "open" : "shut"].</span>",
"You hear a welding torch on metal."
)
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
if (!do_after(user, 2 SECONDS, act_target = src, extra_checks = CALLBACK(src, .proc/is_closed)))
return
if(!WT.remove_fuel(0,user))
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
return
welded = !welded
update_icon()
user.visible_message(
"<span class='warning'>[src] has been [welded ? "welded shut" : "unwelded"] by [user].</span>",
"<span class='notice'>You weld [src] [!welded ? "open" : "shut"].</span>"
)
else
attack_hand(user)
else
attack_hand(user)
return
// helper procs for callbacks
/obj/structure/closet/proc/is_closed()
. = !opened
/obj/structure/closet/proc/is_open()
. = opened
/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(!opened)
return
if(istype(O, /obj/structure/closet))
return
step_towards(O, loc)
if(user != O)
user.show_viewers("<span class='danger'>[user] stuffs [O] into [src]!</span>")
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(loc))
return
if(!open())
user << "<span class='notice'>It won't budge!</span>"
/obj/structure/closet/attack_hand(mob/user as mob)
add_fingerprint(user)
return toggle(user)
// tk grab then use on self
/obj/structure/closet/attack_self_tk(mob/user as mob)
add_fingerprint(user)
if(!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))
add_fingerprint(usr)
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_overlay_state)
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>")
var/time = 6 * breakout_time * 2
var/datum/progressbar/bar
if (escapee.client && escapee.client.prefs.parallax_togs & PROGRESS_BARS)
bar = new(escapee, time, src)
breakout = 1
for(var/i in 1 to time) //minutes * 6 * 5seconds * 2
playsound(loc, 'sound/effects/grillehit.ogg', 100, 1)
animate_shake()
if (bar)
bar.update(i)
if(!do_after(escapee, 50, display_progress = FALSE)) //5 seconds
breakout = 0
qdel(bar)
return
if(!escapee || escapee.stat || escapee.loc != src)
breakout = 0
qdel(bar)
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
qdel(bar)
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(loc, 'sound/effects/grillehit.ogg', 100, 1)
break_open()
animate_shake()
qdel(bar)
/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()
/obj/structure/closet/onDropInto(var/atom/movable/AM)
return