diff --git a/aurorastation.dme b/aurorastation.dme index 3758a3dc6bf..bb215de7dfd 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -305,6 +305,7 @@ #include "code\datums\helper_datums\teleport.dm" #include "code\datums\looping_sounds\_looping_sound.dm" #include "code\datums\looping_sounds\machinery_sounds.dm" +#include "code\datums\looping_sounds\thermal_drill.dm" #include "code\datums\observation\_debug.dm" #include "code\datums\observation\destroyed.dm" #include "code\datums\observation\equipped.dm" @@ -909,6 +910,7 @@ #include "code\game\objects\items\weapons\tape.dm" #include "code\game\objects\items\weapons\teleportation.dm" #include "code\game\objects\items\weapons\tether.dm" +#include "code\game\objects\items\weapons\thermal_drill.dm" #include "code\game\objects\items\weapons\tools.dm" #include "code\game\objects\items\weapons\towel.dm" #include "code\game\objects\items\weapons\traps.dm" diff --git a/code/datums/looping_sounds/thermal_drill.dm b/code/datums/looping_sounds/thermal_drill.dm new file mode 100644 index 00000000000..d4a20647f2b --- /dev/null +++ b/code/datums/looping_sounds/thermal_drill.dm @@ -0,0 +1,4 @@ +/datum/looping_sound/thermal_drill + mid_sounds = list('sound/items/thermal_drill.ogg' = 1) + mid_length = 19 + volume = 30 \ No newline at end of file diff --git a/code/datums/uplink/devices and tools.dm b/code/datums/uplink/devices and tools.dm index fdab18f0157..0e85f0da17b 100644 --- a/code/datums/uplink/devices and tools.dm +++ b/code/datums/uplink/devices and tools.dm @@ -123,6 +123,11 @@ item_cost = 35 path = /obj/item/antag_spawner/borg_tele +/datum/uplink_item/item/tools/thermal_drill + name = "Thermal Safe Drill" + item_cost = 8 + path = /obj/item/thermal_drill + /datum/uplink_item/item/tools/heatpatch name = "HUDPatch, Thermal" item_cost = 6 diff --git a/code/game/objects/items/weapons/thermal_drill.dm b/code/game/objects/items/weapons/thermal_drill.dm new file mode 100644 index 00000000000..e4113a90430 --- /dev/null +++ b/code/game/objects/items/weapons/thermal_drill.dm @@ -0,0 +1,23 @@ +/obj/item/thermal_drill + name = "thermal safe drill" + desc = "A tungsten carbide thermal drill with magnetic clamps for the purpose of drilling hardened objects. Guaranteed 100% jam proof." + icon = 'icons/obj/safe_drill.dmi' + icon_state = "hardened_drill" + w_class = ITEMSIZE_HUGE + force = 12 + var/time_multiplier = 1 + var/datum/looping_sound/thermal_drill/soundloop + +/obj/item/thermal_drill/Initialize() + . = ..() + soundloop = new(list(src), FALSE) + +/obj/item/thermal_drill/Destroy() + QDEL_NULL(soundloop) + return ..() + +/obj/item/thermal_drill/diamond_drill + name = "diamond tipped thermal safe drill" + desc = "A diamond tipped thermal drill with magnetic clamps for the purpose of quickly drilling hardened objects. Guaranteed 100% jam proof." + icon_state = "diamond_drill" + time_multiplier = 2 \ No newline at end of file diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index 7a832edc2dc..7bb0deabe2e 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -8,10 +8,11 @@ FLOOR SAFES /obj/structure/safe name = "safe" desc = "A huge chunk of metal with a dial embedded in it. Fine print on the dial reads \"Scarborough Arms - 2 tumbler safe, guaranteed thermite resistant, explosion resistant, and assistant resistant.\"" - icon = 'icons/obj/structures.dmi' + icon = 'icons/obj/safe.dmi' icon_state = "safe" anchored = 1 density = 1 + var/broken = FALSE //is the tumbler broken into var/open = 0 //is the safe open? var/tumbler_1_pos //the tumbler position- from 0 to 71 var/tumbler_1_open //the tumbler position to open at- 0 to 71 @@ -21,17 +22,21 @@ FLOOR SAFES var/space = 0 //the combined w_class of everything in the safe var/maxspace = 24 //the maximum combined w_class of stuff in the safe + // Variables (Drill) + var/obj/item/thermal_drill/drill // The currently placed thermal drill, if any. + var/time_to_drill = 300 SECONDS // Drill duration of the current thermal drill. + var/last_drill_time = 0 // Last world.time the drill time was checked. Used to reduce time_to_drill accurately + var/image/drill_overlay // The drill overlay image to display during the drilling process. + var/drill_x_offset = -13 // The X pixel offset for the drill + var/drill_y_offset = -3 // The Y pixel offset for the drill -/obj/structure/safe/New() +/obj/structure/safe/Initialize() + . = ..() tumbler_1_pos = rand(0, 71) tumbler_1_open = rand(0, 71) tumbler_2_pos = rand(0, 71) tumbler_2_open = min(71 , max( 1 , abs(tumbler_1_open + rand(-34, 34)))) - - -/obj/structure/safe/Initialize() - . = ..() for(var/obj/item/I in loc) if(space >= maxspace) return @@ -39,13 +44,27 @@ FLOOR SAFES space += I.w_class I.forceMove(src) +/obj/structure/safe/examine(mob/user) + . = ..() + if(broken) + to_chat(user, SPAN_WARNING("\The [src]'s locking system has been drilled open!")) + else if(time_to_drill < 300 SECONDS) + var/time_left = max(round(time_to_drill / 10), 0) + to_chat(user, SPAN_WARNING("There are only [time_left] second\s of drilling left until \the [src] is broken!")) + +/obj/structure/safe/Destroy() + if(drill) + drill.soundloop.stop() + drill.forceMove(loc) + drill = null + return ..() /obj/structure/safe/proc/check_unlocked(mob/user as mob, canhear) if(user && canhear) if(tumbler_1_pos == tumbler_1_open) - to_chat(user, "You hear a [pick("tonk", "krunk", "plunk")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("tonk", "krunk", "plunk")] from [src].")) if(tumbler_2_pos == tumbler_2_open) - to_chat(user, "You hear a [pick("tink", "krink", "plink")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("tink", "krink", "plink")] from [src].")) if(tumbler_1_pos == tumbler_1_open && tumbler_2_pos == tumbler_2_open) if(user) visible_message("[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!") return 1 @@ -68,22 +87,72 @@ FLOOR SAFES /obj/structure/safe/update_icon() if(open) - icon_state = "[initial(icon_state)]-open" + if(broken) + icon_state = "[initial(icon_state)]-open-broken" + else + icon_state = "[initial(icon_state)]-open" else - icon_state = initial(icon_state) + if(broken) + icon_state = "[initial(icon_state)]-broken" + else + icon_state = initial(icon_state) + cut_overlay(drill_overlay) + if(istype(drill, /obj/item/thermal_drill)) + var/drill_icon = istype(drill, /obj/item/thermal_drill/diamond_drill) ? "d" : "h" + var/state = "[initial(icon_state)]_[drill_icon]-drill-[isprocessing ? "on" : "off"]" + drill_overlay = image(icon = 'icons/effects/drill.dmi', icon_state = state, pixel_x = drill_x_offset, pixel_y = drill_y_offset) + add_overlay(drill_overlay) /obj/structure/safe/attack_hand(mob/user as mob) - user.set_machine(src) - var/dat = "
" - dat += "[open ? "Close" : "Open"] [src] | - [dial * 5] +" - if(open) - dat += "" - for(var/i = contents.len, i>=1, i--) - var/obj/item/P = contents[i] - dat += "" - dat += "
[P.name]
" - user << browse("[name][dat]", "window=safe;size=350x300") + if(drill) + switch(alert("What would you like to do?", "Thermal Drill", "Turn [isprocessing ? "Off" : "On"]", "Remove Drill", "Cancel")) + if("Turn On") + if(!drill || isprocessing) + return + if(broken) + to_chat(user, SPAN_WARNING("\The [src] is already broken open!")) + return + if(do_after(user, 2 SECONDS)) + if(!drill || isprocessing) + return + if(broken) + return + last_drill_time = world.time + drill.soundloop.start() + START_PROCESSING(SSprocessing, src) + update_icon() + if("Turn Off") + if(!drill || !isprocessing) + return + if(do_after(user, 2 SECONDS)) + if(!drill || !isprocessing) + return + drill.soundloop.stop() + STOP_PROCESSING(SSprocessing, src) + update_icon() + if("Remove Drill") + if(isprocessing) + to_chat(user, SPAN_WARNING("You cannot remove the drill while it's running!")) + else if(do_after(user, 2 SECONDS)) + if(isprocessing) + return + user.put_in_hands(drill) + drill = null + update_icon() + if("Cancel") + return + else + user.set_machine(src) + var/dat = "
" + dat += "[open ? "Close" : "Open"] [src][drill || broken ? "" : " | - [dial * 5] +"]" + if(open) + dat += "" + for(var/i = contents.len, i>=1, i--) + var/obj/item/P = contents[i] + dat += "" + dat += "
[P.name]
" + user << browse("[name][dat]", "window=safe;size=350x300") /obj/structure/safe/Topic(href, href_list) @@ -95,14 +164,17 @@ FLOOR SAFES canhear = 1 if(href_list["open"]) - if(check_unlocked()) - to_chat(user, "You [open ? "close" : "open"] [src].") + if(drill) + to_chat(user, SPAN_WARNING("You can't open \the [src] if there's a drill attached.")) + return + if(broken || check_unlocked()) + to_chat(user, SPAN_NOTICE("You [open ? "close" : "open"] [src].")) open = !open update_icon() updateUsrDialog() return else - to_chat(user, "You can't [open ? "close" : "open"] [src], the lock is engaged!") + to_chat(user, SPAN_NOTICE("You can't [open ? "close" : "open"] [src], the lock is engaged!")) return if(href_list["decrement"]) @@ -110,11 +182,11 @@ FLOOR SAFES if(dial == tumbler_1_pos + 1 || dial == tumbler_1_pos - 71) tumbler_1_pos = decrement(tumbler_1_pos) if(canhear) - to_chat(user, "You hear a [pick("clack", "scrape", "clank")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("clack", "scrape", "clank")] from [src].")) if(tumbler_1_pos == tumbler_2_pos + 37 || tumbler_1_pos == tumbler_2_pos - 35) tumbler_2_pos = decrement(tumbler_2_pos) if(canhear) - to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("click", "chink", "clink")] from [src].")) check_unlocked(user, canhear) updateUsrDialog() return @@ -124,11 +196,11 @@ FLOOR SAFES if(dial == tumbler_1_pos - 1 || dial == tumbler_1_pos + 71) tumbler_1_pos = increment(tumbler_1_pos) if(canhear) - to_chat(user, "You hear a [pick("clack", "scrape", "clank")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("clack", "scrape", "clank")] from [src].")) if(tumbler_1_pos == tumbler_2_pos - 37 || tumbler_1_pos == tumbler_2_pos + 35) tumbler_2_pos = increment(tumbler_2_pos) if(canhear) - to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") + to_chat(user, SPAN_NOTICE("You hear a [pick("click", "chink", "clink")] from [src].")) check_unlocked(user, canhear) updateUsrDialog() return @@ -148,17 +220,41 @@ FLOOR SAFES if(I.w_class + space <= maxspace) space += I.w_class user.drop_from_inventory(I,src) - to_chat(user, "You put [I] in [src].") + to_chat(user, SPAN_NOTICE("You put [I] in [src].")) updateUsrDialog() return else - to_chat(user, "[I] won't fit in [src].") + to_chat(user, SPAN_NOTICE("[I] won't fit in [src].")) return else if(istype(I, /obj/item/clothing/accessory/stethoscope)) - to_chat(user, "Hold [I] in one of your hands while you manipulate the dial.") - return + attack_hand(user) + else if(istype(I, /obj/item/thermal_drill)) + if(drill) + to_chat(user, SPAN_WARNING("There is already a drill attached!")) + else if(do_after(user, 2 SECONDS)) + user.drop_from_inventory(I, src) + drill = I + update_icon() + else + to_chat(user, SPAN_WARNING("You can't put [I] into the safe while it is closed!")) +/obj/structure/safe/process() + if(!drill) + return + time_to_drill -= (world.time - last_drill_time) * drill.time_multiplier + last_drill_time = world.time + if(prob(15)) + spark(loc, 3, alldirs) + if(time_to_drill <= 0) + drill_open() + +/obj/structure/safe/proc/drill_open() + broken = TRUE + if(drill) + drill.soundloop.stop() + STOP_PROCESSING(SSprocessing, src) + update_icon() obj/structure/safe/ex_act(severity) return @@ -170,6 +266,8 @@ obj/structure/safe/ex_act(severity) density = 0 level = 1 //underfloor layer = 2.5 + drill_x_offset = -1 + drill_y_offset = 20 /obj/structure/safe/floor/Initialize() . = ..() @@ -193,4 +291,4 @@ obj/structure/safe/ex_act(severity) new /obj/random/highvalue(src) new /obj/random/highvalue(src) new /obj/random/highvalue(src) - new /obj/random/highvalue(src) + new /obj/random/highvalue(src) \ No newline at end of file diff --git a/html/changelogs/geeves-get_that_drill.yml b/html/changelogs/geeves-get_that_drill.yml new file mode 100644 index 00000000000..249894662fd --- /dev/null +++ b/html/changelogs/geeves-get_that_drill.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - bugfix: "Station safes now spawn with items in them again." + - rscadd: "You can now buy a thermal drill capable of drilling into the station safe for 8 telecrystals. It will take five minutes to do so." \ No newline at end of file diff --git a/icons/effects/drill.dmi b/icons/effects/drill.dmi new file mode 100644 index 00000000000..c6935b39eed Binary files /dev/null and b/icons/effects/drill.dmi differ diff --git a/icons/obj/safe.dmi b/icons/obj/safe.dmi new file mode 100644 index 00000000000..375b986a8e0 Binary files /dev/null and b/icons/obj/safe.dmi differ diff --git a/icons/obj/safe_drill.dmi b/icons/obj/safe_drill.dmi new file mode 100644 index 00000000000..da06ea89807 Binary files /dev/null and b/icons/obj/safe_drill.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index ec1e67cbace..fa4f3bcdcdc 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/sound/items/thermal_drill.ogg b/sound/items/thermal_drill.ogg new file mode 100644 index 00000000000..035380dd5c9 Binary files /dev/null and b/sound/items/thermal_drill.ogg differ