diff --git a/code/game/objects/items/lock.dm b/code/game/objects/items/lock.dm index 280e74fc808..118f2f98364 100644 --- a/code/game/objects/items/lock.dm +++ b/code/game/objects/items/lock.dm @@ -1,4 +1,6 @@ +/// This list isn't used for anything lmfao GLOBAL_LIST_EMPTY(global_locks) + /obj/item/lock_construct name = "\improper lock" icon = 'icons/obj/lock.dmi' @@ -25,6 +27,7 @@ GLOBAL_LIST_EMPTY(global_locks) to_chat(user, span_notice("You fashion \the [I] to unlock \the [src]")) K.lock_data = lock_data K.desc = "A simple key for locks. It has [K.lock_data] engraved on it." + playsound(get_turf(src), "sound/f13items/flashlight_off.ogg", 25, FALSE, -4) else to_chat(user, span_warning("\The [I] already unlocks something...")) return @@ -36,7 +39,7 @@ GLOBAL_LIST_EMPTY(global_locks) return ..() -/obj/item/lock_construct/proc/check_key(obj/item/key/K, mob/user = null) +/obj/item/lock_construct/proc/check_key(obj/item/key/K, mob/user = null,atom/movable/D) if(K.lock_data == src.lock_data) //if the key matches us if(locked) user.visible_message(span_warning("[user] unlocks \the [src].")) @@ -44,9 +47,13 @@ GLOBAL_LIST_EMPTY(global_locks) else user.visible_message(span_warning("[user] locks \the [src].")) locked = TRUE + playsound(get_turf(src), "sound/f13items/flashlight_off.ogg", 50, FALSE) + if(D) + D.do_squish(0.9,0.9,0.25 SECONDS) else to_chat(user, span_warning("This is the wrong key!")) +/// Always returns true. Very cool. /obj/item/lock_construct/proc/check_locked() return locked @@ -62,7 +69,7 @@ GLOBAL_LIST_EMPTY(global_locks) var/result = do_after(user, time_to_open, target = A) prying = FALSE if(result) - user.visible_message(span_notice("[src] breaks off [A] and falls to pieces.")) + user.visible_message(span_notice("[src] breaks off [A] and falls to the ground.")) return TRUE return FALSE @@ -91,3 +98,61 @@ GLOBAL_LIST_EMPTY(global_locks) S.lock_data = src.lock_data else return ..() + +//// Deadbolt / Barrel Bolt / Bolt Lock / Etc +//// Basically just a keyless lock that can only be opened from one direction. Useful for mappers. + +/obj/item/lock_bolt + name = "bolt lock" + desc = "This simple lock doesn't need a key, but it can only be manipulated from one side of a door." + icon = 'icons/obj/lock.dmi' + icon_state = "deadbolt_mapping" + w_class = WEIGHT_CLASS_SMALL + dir = SOUTH + /// This variable will set itself, do not touch it in the map editor >:( + var/mapped = FALSE + var/prying = FALSE + var/locked = FALSE + +//Exclusively used for mapping rooms that should start locked. +/obj/item/lock_bolt/prelocked + locked = TRUE + +/obj/item/lock_bolt/Initialize(mapload) + . = ..() + icon_state = "deadbolt" + GLOB.global_locks += src + if(mapload && isturf(loc))//Mapped on a turf. Ignores deadbolts inside of containers and what not. + mapped = TRUE + var/obj/structure/simple_door/SD = locate(/obj/structure/simple_door) in loc + if(SD && SD.can_have_lock) + name = "[SD.name] [name]" //Give this lock a unique name so it can be tracked easier + SD.attach_deadbolt(src, FALSE, null, mapped) + +/obj/item/lock_bolt/Destroy() + ..() + GLOB.global_locks -= src + +/obj/item/lock_bolt/proc/pry_off(mob/living/user, atom/A) + if(!prying) + user.visible_message(span_notice("[user] starts prying [src] off [A]."), \ + span_notice("You start prying [src] off [A].")) + var/time_to_open = 50 + if(locked) + time_to_open = 500 + playsound(src, 'sound/machines/airlock_alien_prying.ogg',100,1) //is it aliens or just the CE being a dick? + prying = TRUE + var/result = do_after(user, time_to_open, target = A) + prying = FALSE + if(result) + user.visible_message(span_notice("[src] breaks off [A] and falls to the ground.")) + return TRUE + return FALSE + +/obj/item/lock_bolt/proc/ToggleLock(mob/user) + if(locked) + user.visible_message(span_warning("[user] unlocks \the [src].")) + locked = FALSE + else + user.visible_message(span_warning("[user] locks \the [src].")) + locked = TRUE diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 593813227d6..349a695401f 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -38,10 +38,11 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("field arrowhead", /obj/item/stack/arrowhead/field, 1, 1, time = 1 SECONDS), \ null, \ new/datum/stack_recipe("lock", /obj/item/lock_construct, 1), \ - new/datum/stack_recipe("coffee pot", /obj/item/crafting/coffee_pot, 1), \ - new/datum/stack_recipe("lunchbox", /obj/item/crafting/lunchbox, 1), \ new/datum/stack_recipe("key", /obj/item/key, 1), \ new/datum/stack_recipe("key chain", /obj/item/storage/keys_set, 1), \ + new/datum/stack_recipe("bolt lock", /obj/item/lock_bolt, 1), \ + new/datum/stack_recipe("coffee pot", /obj/item/crafting/coffee_pot, 1), \ + new/datum/stack_recipe("lunchbox", /obj/item/crafting/lunchbox, 1), \ null, \ new/datum/stack_recipe("seed extractor", /obj/structure/legion_extractor, 6, one_per_turf = TRUE, on_floor = TRUE), \ null, \ diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index fa6c5542297..ca23555129b 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -216,7 +216,7 @@ close_sound = "sound/f13machines/doorchainlink_close.ogg" opacity = FALSE base_opacity = FALSE - can_hold_padlock = TRUE + can_have_lock = TRUE opening_time = 3 closing_time = 2 hard_open = 0 diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 06c2918ce9b..aaa70674c32 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -157,7 +157,7 @@ close_sound = "sound/machines/door_close.ogg" opacity = FALSE base_opacity = FALSE - can_hold_padlock = TRUE + can_have_lock = TRUE //Yellow rail diff --git a/code/modules/fallout/obj/door_keys.dm b/code/modules/fallout/obj/door_keys.dm index d4c3e343ad3..f4ae182dc4b 100644 --- a/code/modules/fallout/obj/door_keys.dm +++ b/code/modules/fallout/obj/door_keys.dm @@ -97,7 +97,7 @@ if(id) attach_id(id) var/obj/structure/simple_door/D = locate(/obj/structure/simple_door) in loc - if(istype(D) && D.can_hold_padlock) + if(istype(D) && D.can_have_lock) D.attach_padlock(src, TRUE) /obj/item/lock/attackby(obj/item/W, mob/user, params) diff --git a/code/modules/fallout/obj/structures/simple_door.dm b/code/modules/fallout/obj/structures/simple_door.dm index 39c8c72dfd7..29b6f4d86b9 100644 --- a/code/modules/fallout/obj/structures/simple_door.dm +++ b/code/modules/fallout/obj/structures/simple_door.dm @@ -18,8 +18,11 @@ anchored = TRUE layer = CLOSED_DOOR_LAYER explosion_block = 0.5 - var/can_hold_padlock = FALSE + var/can_have_lock = FALSE var/obj/item/lock_construct/padlock + var/obj/item/lock_bolt/deadbolt + /// Set one that fits the type of door. Default is for a french-style door that opens from the middle. + var/deadbolt_overlay = "deadbolt" var/door_type = "house" var/base_opacity = TRUE var/manual_opened = 0 @@ -48,12 +51,30 @@ if(padlock) padlock.forceMove(get_turf(src)) padlock = null + if(deadbolt) + deadbolt.forceMove(get_turf(src)) + deadbolt = null //fortuna edit investigate_log("Door '[src]' destroyed at [AREACOORD(src)]. Last fingerprints: [src.fingerprintslast]", INVESTIGATE_DESTROYED) //message_admins("Door '[ADMIN_JMP(src)]' destroyed at [AREACOORD(src)]. Last fingerprints(If any): [src.fingerprintslast]") log_game("Door '[src]' destroyed at [AREACOORD(src)]. Last fingerprints: [src.fingerprintslast]") return ..() +/obj/structure/simple_door/examine(mob/user) + . = ..() + if(deadbolt) + . += span_notice("Alt-Click [src] from \the [dir2text(deadbolt.dir)] to use the bolt lock.") + +/obj/structure/simple_door/AltClick(mob/user) + . = ..() + if(deadbolt && isliving(user) && Adjacent(user) && !user.incapacitated()) + if(get_dir(src,user) != deadbolt.dir) + to_chat(user, span_warning("[deadbolt] can only be reached from \the [dir2text(deadbolt.dir)]!")) + else + deadbolt.ToggleLock(user) + do_squish(0.9,0.9,0.25 SECONDS) + playsound(get_turf(src), "sound/f13items/flashlight_off.ogg", 50, FALSE, 0) + /obj/structure/simple_door/proc/SetBounds() if(width>1) if(dir in list(EAST, WEST)) @@ -72,8 +93,14 @@ . = ..() apply_opacity_to_my_turfs(new_opacity) +/obj/structure/simple_door/proc/HasLock() + if(padlock || deadbolt) + return TRUE + return FALSE + +//Padlocks /obj/structure/simple_door/proc/attach_padlock(obj/item/lock_construct/P, force = FALSE, mob/user) - if(!force && (!can_hold_padlock || !P )) + if(!force && (!can_have_lock || !P )) return FALSE if(padlock) to_chat(user, "[src] already has \a [padlock] attached") @@ -93,6 +120,35 @@ padlock = null cut_overlay("[initial(icon_state)]_padlock") +//Deadbolts +/obj/structure/simple_door/proc/attach_deadbolt(obj/item/lock_bolt/L, force = FALSE, mob/user, mapload) + if(!force && (!can_have_lock || !L )) + return FALSE + if(deadbolt) + to_chat(user, "[src] already has \a [deadbolt] attached") + return FALSE + if(padlock?.locked) + to_chat(user, span_warning("Unlock \the [padlock] before installing a bolt lock."))//Prevents grief, mostly. + return FALSE + if(mapload) + L.forceMove(src) + deadbolt = L + if(density) + add_overlay(deadbolt_overlay) + else if(user.transferItemToLoc(L, src)) + L.dir = get_dir(src,user) + user.visible_message(span_notice("[user] adds [L] to [src]."),span_notice("You add [L] to [src]. It can only be manipulated from \the [dir2text(L.dir)]")) + deadbolt = L + if(density) + add_overlay(deadbolt_overlay) +/// Moves the deadbolt to the turf of the door, sets the door's deadbolt to null, and cuts the deadbolt overlay/ +/obj/structure/simple_door/proc/remove_deadbolt(force = FALSE) + if(!force && (!deadbolt)) + return FALSE + deadbolt.forceMove(get_turf(src)) + deadbolt = null + cut_overlay(deadbolt_overlay) + //Very useful proc we have here, excellent work on that one /obj/structure/simple_door/bullet_act(obj/item/projectile/Proj) ..() @@ -110,6 +166,8 @@ playsound(src.loc, open_sound, 30, 0, 0) if(padlock) cut_overlay("[initial(icon_state)]_padlock") + if(deadbolt) + cut_overlay(deadbolt_overlay) if(animate) moving = 1 flick("[door_type]opening", src) @@ -131,6 +189,8 @@ set_opacity(base_opacity) if(padlock) add_overlay("[initial(icon_state)]_padlock") + if(deadbolt) + add_overlay(deadbolt_overlay) density = 1 moving = 0 layer = CLOSED_DOOR_LAYER @@ -142,19 +202,24 @@ remove_padlock() padlock = null src.desc = "[initial(desc)]" + cut_overlay("[initial(icon_state)]_padlock") + else if(deadbolt) + if(deadbolt.pry_off(user,src)) + if(deadbolt.mapped) + message_admins("Mapped in deadbolt [ADMIN_JMP(deadbolt)] removed at [AREACOORD(src)] by [user.real_name][ADMIN_PP(user)].") + remove_deadbolt() + deadbolt = null + cut_overlay(deadbolt_overlay) return /obj/structure/simple_door/proc/SwitchState(animate) if(density) - if(padlock) - if(!padlock.locked) - Open(animate) - else - playsound(src.loc, pick('sound/f13items/door_knock1.wav', 'sound/f13items/door_knock2.wav', 'sound/f13items/door_knock3.wav', 'sound/f13items/door_knock4.wav'), 80, 0, 0) - - else + var/padlocked = padlock?.locked + var/boltlocked = deadbolt?.locked + if(!padlocked && !boltlocked) Open(animate) - + else //One of the lock types on this door is locked + playsound(src.loc, pick('sound/f13items/door_knock1.wav', 'sound/f13items/door_knock2.wav', 'sound/f13items/door_knock3.wav', 'sound/f13items/door_knock4.wav'), 80, 0, 0) else var/turf/T = get_turf(src) for(var/mob/living/L in T) @@ -171,8 +236,8 @@ P.attackby(I, user, params) return TRUE if(istype(I, /obj/item/screwdriver)) - if(padlock) - to_chat(user, span_warning("Remove padlock before door dissasembling.")) + if(HasLock()) + to_chat(user, span_warning("Remove all locks before door dissasembling.")) return 1 else if(can_disasemble && do_after(user, 60, target = src)) @@ -182,43 +247,21 @@ playsound(loc, 'sound/items/Screwdriver.ogg', 25, -3) qdel(src) return 1 -/* if(istype(I, /obj/item/storage/keys_set)) - var/obj/item/storage/keys_set/S = I - if(padlock) - var/obj/item/key/K = S.get_key_with_id(padlock.id) - if(istype(K)) - I = K - if(istype(user.get_inactive_held_item(), /obj/item/lock)) - var/obj/item/lock/L = user.get_inactive_held_item() - var/obj/item/key/K = S.get_key_with_id(L.id) - if(istype(K)) - I = K - */ - //I'll deal with that shit later -harcourt - if(istype(I, /obj/item/lock_construct) && can_hold_padlock) + if(istype(I, /obj/item/lock_construct) && can_have_lock) if(attach_padlock(I,FALSE,user)) return TRUE//Don't open the door when we add a padlock - /* - if(padlock) - to_chat(user, "[src] already has \a [padlock] attached") - return - else - if(user.transferItemToLoc(I, src)) - user.visible_message(span_notice("[user] adds [I] to [src]."), \ - span_notice("You add [I] to [src].")) - if (istype(I, /obj/item/lock_construct)) - desc = "[src.desc] Has a lock."//Fuck it im not doing this bullshit tonight. This will do. :) -with love, harcourt - padlock = I - */ + else return FALSE//Don't knock on the door if we fail to put the lock on. + if(istype(I, /obj/item/lock_bolt) && can_have_lock) + if(attach_deadbolt(I,FALSE,user,FALSE)) + return TRUE//Don't open the door when we add a padlock + else return FALSE//Don't knock on the door if we fail to put the lock on. if(istype(I, /obj/item/key)) if(!padlock) to_chat(user, "[src] has no lock attached") return else - return padlock.check_key(I,user) + return padlock.check_key(I,user,src) if(user.a_intent == INTENT_HARM) -// if(padlock) -// add_logs(user, src, "attacked", src) return ..() attack_hand(user) @@ -287,7 +330,7 @@ icon_state = "house" door_type = "house" can_disasemble = TRUE - can_hold_padlock = TRUE + can_have_lock = TRUE // cleaned and repainted white /obj/structure/simple_door/house/clean @@ -299,14 +342,14 @@ icon_state = "wood" door_type = "wood" can_disasemble = TRUE - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/interior icon_state = "interior" door_type = "interior" can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE //Example wide doors with terrible sprites but you get the idea /obj/structure/simple_door/twowide_example @@ -316,7 +359,7 @@ icon_state = "interior" door_type = "interior" can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE width = 2 /obj/structure/simple_door/threewide_example @@ -326,14 +369,14 @@ icon_state = "interior" door_type = "interior" can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE width = 3 /obj/structure/simple_door/room icon_state = "room" door_type = "room" can_disasemble = TRUE - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/room/dirty icon_state = "room_d" @@ -345,7 +388,7 @@ desc = "Battered and hastily repaired." icon_state = "room_repaired" door_type = "room_repaired" - can_hold_padlock = TRUE + can_have_lock = TRUE // --------------------------------------------- @@ -357,7 +400,7 @@ door_type = "tentflap_leather" base_opacity = TRUE can_disasemble = FALSE - can_hold_padlock = FALSE + can_have_lock = FALSE open_sound = 'sound/effects/footstep/hardbarefoot4.ogg' close_sound = 'sound/effects/footstep/hardbarefoot5.ogg' @@ -367,7 +410,7 @@ door_type = "tentflap_cloth" base_opacity = TRUE can_disasemble = FALSE - can_hold_padlock = FALSE + can_have_lock = FALSE open_sound = 'sound/effects/footstep/hardbarefoot4.ogg' close_sound = 'sound/effects//footstep/hardbarefoot5.ogg' @@ -380,7 +423,7 @@ material_type = /obj/item/stack/sheet/cloth open_sound = "sound/effects/curtain.ogg" close_sound = "sound/effects/curtain.ogg" - can_hold_padlock = TRUE + can_have_lock = TRUE // -------------------------------------------------------------- @@ -402,7 +445,7 @@ icon_state = "iron" door_type = "iron" explosion_block = 5 - can_hold_padlock = TRUE + can_have_lock = TRUE opening_time = 12 closing_time = 8 @@ -415,7 +458,7 @@ close_sound = "sound/f13machines/doorchainlink_close.ogg" opacity = FALSE base_opacity = FALSE - can_hold_padlock = TRUE + can_have_lock = TRUE proj_pass_rate = 95 pass_flags = LETPASSTHROW @@ -423,7 +466,7 @@ desc = "The glass is dirty, you can't see a thing behind it." icon_state = "dirtyglass" door_type = "dirtyglass" - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/brokenglass name = "shattered glass door" @@ -432,7 +475,7 @@ door_type = "brokenglass" opacity = FALSE base_opacity = FALSE - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/glass desc = "The glass is quite clean, someone took care of this door." @@ -440,14 +483,14 @@ door_type = "glass" opacity = FALSE base_opacity = FALSE - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/metal/dirtystore desc = "A metal door with dirty glass, you can't see a thing behind it." icon_state = "dirtystore" door_type = "dirtystore" - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/metal/store icon_state = "store" @@ -455,7 +498,7 @@ opacity = FALSE base_opacity = FALSE can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/wood/alt/window icon = 'icons/fallout/structures/doors.dmi' @@ -464,7 +507,7 @@ opacity = TRUE base_opacity = FALSE can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE /obj/structure/simple_door/wood/alt icon = 'icons/fallout/structures/doors.dmi' @@ -473,7 +516,7 @@ opacity = FALSE base_opacity = FALSE can_disasemble = 1 - can_hold_padlock = TRUE + can_have_lock = TRUE // -------------------------------------- // BUNKER DOORS diff --git a/icons/fallout/structures/doors.dmi b/icons/fallout/structures/doors.dmi index f13287b2a89..fe9882bf38d 100644 Binary files a/icons/fallout/structures/doors.dmi and b/icons/fallout/structures/doors.dmi differ diff --git a/icons/obj/lock.dmi b/icons/obj/lock.dmi index 13b09348401..45ce2cb2e90 100644 Binary files a/icons/obj/lock.dmi and b/icons/obj/lock.dmi differ