Files
Bubberstation/code/game/objects/structures/crates_lockers/closets.dm
Joan Lung cbf733dbc4 Does something, likely to be important, to blob (#19831)
🆑 Joan
rscadd: Once the blob alert message is sent in the blob game mode, all mobs get to see how many tiles the blob has until it wins, via the Status tab.
rscdel: Removed/merged a bunch of blob chems, you probably don't care about the specifics.
tweak: The remaining blob chems should, overall, be more powerful.
tweak: Shield blobs soak brute damage less well.
tweak: Flashbangs do higher damage to blobs up close, but their damage falls off faster.
experiment: Shield blobs now cost 15 resources to make instead of 10. Node blobs now cost 50 resources to make instead of 60.
experiment: Expanding/attacking now costs 4 resources instead of 5, and blobs can now ATTACK DIAGONALLY. Diagonal attacks are weaker than normal attacks, especially against cyborgs(which may be entirely immune, depending), and they remain unable to expand diagonally.
rscadd: Shield blobs no longer block atmos while under half health. Shield blobs are still immune to fire, even if they can't block atmos.
tweak: Blobs should block explosions less well.
rscadd: Blob cores and nodes are no longer immune to fire and no longer block atmos.
rscadd: Blobs can only auto-expand one tile at a time per expanding thing, and should be easier to beat back in general.
tweak: Blobbernauts now attack faster.
tweak: Blob Overminds attack mobs slower but can attack non-mobs much faster.
rscadd: Blob Overminds start with some amount of resources; in the gamemode, it's 80 divided by the number of overminds, in the event, it's 20 plus the number of active players, and otherwise, it's 60.
bugfix: You can no longer move blob cores into space, onto the mining shuttle, white ship, gulag shuttle, or solars.
bugfix: Blob rounds might be less laggy, if they were laggy?
tweak: Blobs don't heal as fast, excluding the core.
experiment: Blobs are marginally less destructive to their environment.
/🆑

Objective:
maybe possibly make blob something you can fight instead of wishing the blob didn't exist?
but also make the blob lethal enough that it can still deal with the crew if it knows what it's doing(and still lose if the crew is good instead of snowballing forever)
2016-08-17 15:48:28 +12:00

431 lines
14 KiB
Plaintext

/obj/structure/closet
name = "closet"
desc = "It's a basic storage unit."
icon = 'icons/obj/closet.dmi'
icon_state = "generic"
density = 1
var/icon_door = null
var/icon_door_override = FALSE //override to have open overlay use icon different to its base's
var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
var/opened = FALSE
var/welded = FALSE
var/locked = FALSE
var/broken = FALSE
var/large = TRUE
var/wall_mounted = 0 //never solid (You can always pass over it)
var/health = 100
var/breakout_time = 2
var/lastbang
var/can_weld_shut = TRUE
var/horizontal = FALSE
var/allow_objects = FALSE
var/allow_dense = FALSE
var/dense_when_open = FALSE //if it's dense when open or not
var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container
var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet.
var/storage_capacity = 30 //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/cutting_tool = /obj/item/weapon/weldingtool
var/open_sound = 'sound/machines/click.ogg'
var/close_sound = 'sound/machines/click.ogg'
var/cutting_sound = 'sound/items/Welder.ogg'
var/material_drop = /obj/item/stack/sheet/metal
/obj/structure/closet/New()
..()
update_icon()
/obj/structure/closet/initialize()
..()
if(!opened) // if closed, any item at the crate's loc is put in the contents
take_contents()
/obj/structure/closet/Destroy()
dump_contents()
return ..()
/obj/structure/closet/update_icon()
cut_overlays()
if(!opened)
if(icon_door)
add_overlay("[icon_door]_door")
else
add_overlay("[icon_state]_door")
if(welded)
add_overlay("welded")
if(secure)
if(!broken)
if(locked)
add_overlay("locked")
else
add_overlay("unlocked")
else
add_overlay("off")
else
if(icon_door_override)
add_overlay("[icon_door]_open")
else
add_overlay("[icon_state]_open")
/obj/structure/closet/examine(mob/user)
..()
if(broken)
user << "<span class='notice'>It appears to be broken.</span>"
else if(secure && !opened)
user << "<span class='notice'>Alt-click to [locked ? "unlock" : "lock"].</span>"
/obj/structure/closet/alter_health()
return get_turf(src)
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0)
if(height == 0 || wall_mounted)
return 1
return !density
/obj/structure/closet/proc/can_open(mob/living/user)
if(welded || locked)
return 0
var/turf/T = get_turf(src)
for(var/mob/living/L in T)
if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
if(user)
user << "<span class='danger'>There's something large on top of [src], preventing it from opening.</span>" //you... think? there's something standing on it ffs
return 0
return 1
/obj/structure/closet/proc/can_close(mob/living/user)
var/turf/T = get_turf(src)
for(var/obj/structure/closet/closet in T)
if(closet != src && !closet.wall_mounted)
return 0
for(var/mob/living/L in T)
if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
if(user)
user << "<span class='danger'>There's something too large in [src], preventing it from closing.</span>"
return 0
return 1
/obj/structure/closet/proc/dump_contents()
var/turf/T = get_turf(src)
for(var/atom/movable/AM in src)
AM.forceMove(T)
if(throwing) // you keep some momentum when getting out of a thrown closet
step(AM, dir)
if(throwing)
throwing = 0
/obj/structure/closet/proc/take_contents()
var/turf/T = get_turf(src)
for(var/atom/movable/AM in T)
if(insert(AM) == -1) // limit reached
break
/obj/structure/closet/proc/open(mob/living/user)
if(opened || !can_open(user))
return
playsound(loc, open_sound, 15, 1, -3)
opened = 1
if(!dense_when_open)
density = 0
climb_time *= 0.5 //it's faster to climb onto an open thing
dump_contents()
update_icon()
return 1
/obj/structure/closet/proc/insert(atom/movable/AM)
if(contents.len >= storage_capacity)
return -1
if(ismob(AM))
if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
return
var/mob/living/L = AM
if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs())
return
if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items.
if(horizontal && L.density)
return
if(L.mob_size > max_mob_size)
return
var/mobs_stored = 0
for(var/mob/living/M in contents)
if(++mobs_stored >= mob_storage_capacity)
return
L.stop_pulling()
else if(istype(AM, /obj/structure/closet))
return
else if(isobj(AM))
if(!allow_objects && !istype(AM, /obj/item) && !istype(AM, /obj/effect/dummy/chameleon))
return
if(!allow_dense && AM.density)
return
if(AM.anchored || AM.has_buckled_mobs() || (AM.flags & NODROP))
return
else
return
AM.forceMove(src)
if(AM.pulledby)
AM.pulledby.stop_pulling()
return 1
/obj/structure/closet/proc/close(mob/living/user)
if(!opened || !can_close(user))
return 0
take_contents()
playsound(loc, close_sound, 15, 1, -3)
climb_time = initial(climb_time)
opened = 0
density = 1
update_icon()
return 1
/obj/structure/closet/proc/toggle(mob/living/user)
if(opened)
return close(user)
else
return open(user)
/obj/structure/closet/ex_act(severity, target)
contents_explosion(severity, target)
if(loc && ispath(material_drop) && !(flags & NODECONSTRUCT))
new material_drop(loc)
qdel(src)
..()
/obj/structure/closet/bullet_act(obj/item/projectile/P)
..()
if(P.damage_type == BRUTE || P.damage_type == BURN)
health -= P.damage
if(health <= 0)
qdel(src)
/obj/structure/closet/attack_animal(mob/living/simple_animal/user)
if(user.environment_smash)
user.do_attack_animation(src)
visible_message("<span class='danger'>[user] destroys \the [src].</span>")
qdel(src)
/obj/structure/closet/attackby(obj/item/weapon/W, mob/user, params)
if(user in src)
return
if(opened)
if(istype(W, cutting_tool))
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0, user))
return
user << "<span class='notice'>You begin cutting \the [src] apart...</span>"
playsound(loc, cutting_sound, 40, 1)
if(do_after(user, 40/WT.toolspeed, 1, target = src))
if(!opened || !WT.isOn())
return
playsound(loc, cutting_sound, 50, 1)
visible_message("<span class='notice'>[user] slices apart \the [src].</span>",
"<span class='notice'>You cut \the [src] apart with \the [WT].</span>",
"<span class='italics'>You hear welding.</span>")
var/turf/T = get_turf(src)
new material_drop(T)
qdel(src)
return 0
else if(user.drop_item())
W.forceMove(loc)
return 1
else if(istype(W, /obj/item/weapon/weldingtool) && can_weld_shut)
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0, user))
return
user << "<span class='notice'>You begin [welded ? "unwelding":"welding"] \the [src]...</span>"
playsound(loc, 'sound/items/Welder2.ogg', 40, 1)
if(do_after(user, 40/WT.toolspeed, 1, target = src))
if(opened || !WT.isOn())
return
playsound(loc, 'sound/items/welder.ogg', 50, 1)
welded = !welded
visible_message("<span class='notice'>[user] [welded ? "welds shut" : "unweldeds"] \the [src].</span>",
"<span class='notice'>You [welded ? "weld" : "unwelded"] \the [src] with \the [WT].</span>",
"<span class='italics'>You hear welding.</span>")
update_icon()
else if(user.a_intent != "harm" && !(W.flags & NOBLUDGEON))
if(W.GetID() || !toggle(user))
togglelock(user)
return 1
else
return ..()
/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
if(!istype(O) || O.anchored || istype(O, /obj/screen))
return
if(!istype(user) || user.incapacitated() || user.lying)
return
if(!Adjacent(user) || !user.Adjacent(O))
return
if(user == O) //try to climb onto it
return ..()
if(!opened)
return
if(!isturf(O.loc))
return
var/actuallyismob = 0
if(isliving(O))
actuallyismob = 1
else if(!istype(O, /obj/item))
return
var/turf/T = get_turf(src)
var/list/targets = list(O, src)
add_fingerprint(user)
user.visible_message("<span class='warning'>[user] [actuallyismob ? "tries to ":""]stuff [O] into [src].</span>", \
"<span class='warning'>You [actuallyismob ? "try to ":""]stuff [O] into [src].</span>", \
"<span class='italics'>You hear clanging.</span>")
if(actuallyismob)
if(do_after_mob(user, targets, 40))
user.visible_message("<span class='notice'>[user] stuffs [O] into [src].</span>", \
"<span class='notice'>You stuff [O] into [src].</span>", \
"<span class='italics'>You hear a loud metal bang.</span>")
var/mob/living/L = O
if(!issilicon(L))
L.Weaken(2)
O.forceMove(T)
close()
else
O.forceMove(T)
return 1
/obj/structure/closet/relaymove(mob/user)
if(user.stat || !isturf(loc) || !isliving(user))
return
var/mob/living/L = user
if(!open())
if(L.last_special <= world.time)
container_resist(L)
if(world.time > lastbang+5)
lastbang = world.time
for(var/mob/M in get_hearers_in_view(src, null))
M.show_message("<FONT size=[max(0, 5 - get_dist(src, M))]>BANG, bang!</FONT>", 2)
/obj/structure/closet/attack_hand(mob/user)
..()
if(user.lying && get_dist(src, user) > 0)
return
if(!toggle(user))
togglelock(user)
return
/obj/structure/closet/attack_alien(mob/living/user)
return attack_hand(user)
// tk grab then use on self
/obj/structure/closet/attack_self_tk(mob/user)
return attack_hand(user)
/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(iscarbon(usr) || issilicon(usr) || isdrone(usr))
attack_hand(usr)
else
usr << "<span class='warning'>This mob type can't use this verb.</span>"
// Objects that try to exit a locker by stepping were doing so successfully,
// and due to an oversight in turf/Enter() were going through walls. That
// should be independently resolved, but this is also an interesting twist.
/obj/structure/closet/Exit(atom/movable/AM)
open()
if(AM.loc == src)
return 0
return 1
/obj/structure/closet/container_resist(mob/living/user)
if(opened)
return
if(istype(loc, /atom/movable))
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
var/atom/movable/AM = loc
AM.relay_container_resist(user, src)
return
if(!welded && !locked)
open()
return
//okay, so the closet is either welded or locked... resist!!!
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user << "<span class='notice'>You lean on the back of [src] and start pushing the door open.</span>"
visible_message("<span class='warning'>[src] begins to shake violently!</span>")
if(do_after(user,(breakout_time * 60 * 10), target = src)) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
return
//we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
welded = 0 //applies to all lockers lockers
locked = 0 //applies to critter crates and secure lockers only
broken = 1 //applies to secure lockers only
user.visible_message("<span class='danger'>[user] successfully broke out of [src]!</span>",
"<span class='notice'>You successfully break out of [src]!</span>")
open()
else
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
user << "<span class='warning'>You fail to break out of [src]!</span>"
/obj/structure/closet/AltClick(mob/user)
..()
if(!user.canUseTopic(src, be_close=TRUE))
user << "<span class='warning'>You can't do that right now!</span>"
return
if(opened || !secure)
return
else
togglelock(user)
/obj/structure/closet/proc/togglelock(mob/living/user)
if(secure && !broken)
if(allowed(user))
add_fingerprint(user)
locked = !locked
user.visible_message("<span class='notice'>[user] [locked ? null : "un"]locks [src].</span>",
"<span class='notice'>You [locked ? null : "un"]lock [src].</span>")
update_icon()
else
user << "<span class='notice'>Access Denied</span>"
else if(secure && broken)
user << "<span class='warning'>\The [src] is broken!</span>"
/obj/structure/closet/emag_act(mob/user)
if(secure && !broken)
user.visible_message("<span class='warning'>Sparks fly from [src]!</span>",
"<span class='warning'>You scramble [src]'s lock, breaking it open!</span>",
"<span class='italics'>You hear a faint electrical spark.</span>")
playsound(src.loc, 'sound/effects/sparks4.ogg', 50, 1)
broken = 1
locked = 0
update_icon()
/obj/structure/closet/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1)
/obj/structure/closet/emp_act(severity)
for(var/obj/O in src)
O.emp_act(severity)
if(secure && !broken)
if(prob(50 / severity))
locked = !locked
update_icon()
if(prob(20 / severity) && !opened)
if(!locked)
open()
else
req_access = list()
req_access += pick(get_all_accesses())
..()