diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi index 02d848eb4e9d..77721bb9bbb3 100644 Binary files a/icons/obj/machines/research.dmi and b/icons/obj/machines/research.dmi differ diff --git a/monkestation/code/game/machinery/bomb_actualizer.dm b/monkestation/code/game/machinery/bomb_actualizer.dm new file mode 100644 index 000000000000..cbf791e0cea1 --- /dev/null +++ b/monkestation/code/game/machinery/bomb_actualizer.dm @@ -0,0 +1,251 @@ +/obj/machinery/bomb_actualizer + name = "Bomb Actualizer" + desc = "An advanced machine capable of releasing the normally bluespace-inhibited destructive potential of a bomb assembly... or so the sticker says" + circuit = /obj/item/circuitboard/machine/bomb_actualizer + icon = 'icons/obj/machines/research.dmi' + base_icon_state = "bomb_actualizer" + icon_state = "bomb_actualizer" + density = TRUE + max_integrity = 600 + use_power = NO_POWER_USE + resistance_flags = FIRE_PROOF | ACID_PROOF + processing_flags = START_PROCESSING_MANUALLY + subsystem_type = /datum/controller/subsystem/processing/fastprocess + + /** + * Stages for countdown warnings and alerts. + * 0 = no major alerts, + * 1 = the timer has reached 60 seconds, + * 2 = the timer has reached 10 seconds (it will reset to zero immediately after) + */ + var/stage = 0 + //location to call out on priority message + var/alerthere = "" + /// The TTV inserted in the machine. + var/obj/item/transfer_valve/inserted_bomb + //combined gasmix to determine the simulation to reality + var/datum/gas_mixture/combined_gasmix + //Timer till detonation in seconds + var/default_time = 420 SECONDS + //used to track current world time + var/timer = null + /// The countdown that'll show up to ghosts regarding the bomb's timer. + var/obj/effect/countdown/bomb_actualizer/countdown + //Can examine the Countdown + var/examinable_countdown = TRUE + //So the ttv transfers gas properly + var/obj/item/tank/tank_to_target + //For managing if the tank exploded so it doesnt explode twice + var/active = FALSE + var/exploded = FALSE + //When to beep (every second) + var/next_beep = null + //sounds for scaryness + var/beepsound = 'sound/items/timer.ogg' + var/scarywarning = 'sound/misc/bloblarm.ogg' + var/verybadsound = 'sound/machines/engine_alert1.ogg' + var/youdied = 'sound/misc/guitarreverb.ogg' + /// The countdown that'll show up to ghosts regarding the bomb's timer. + ///Our internal radio + var/obj/item/radio/radio + ///The key our internal radio uses + var/radio_key = /obj/item/encryptionkey/headset_sci + ///The common channel + var/common_channel = null + //Cooldown for pressing button + var/COOLDOWN_BOMB_BUTTON + +/obj/machinery/bomb_actualizer/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ATOM_INTERNAL_EXPLOSION, PROC_REF(modify_explosion)) + radio = new(src) + radio.keyslot = new radio_key + radio.set_listening(FALSE) + radio.recalculateChannels() + countdown = new(src) + update_appearance() + +//For when the machine is destroyed +/obj/machinery/bomb_actualizer/Destroy() + inserted_bomb = null + radio = null + combined_gasmix = null + QDEL_NULL(countdown) + end_processing() + return ..() + +/obj/machinery/bomb_actualizer/attackby(obj/item/tool, mob/living/user, params) + if(active && istype(tool, /obj/item/transfer_valve)) + to_chat(user, span_warning("You can't insert [tool] into [src] while [p_theyre()] currently active.")) + return + if(istype(tool, /obj/item/transfer_valve)) + if(inserted_bomb) + to_chat(user, span_warning("There is already a bomb in [src].")) + return + var/obj/item/transfer_valve/valve = tool + if(!valve.ready()) + to_chat(user, span_warning("[valve] is incomplete.")) + return + if(!user.transferItemToLoc(tool, src)) + to_chat(user, span_warning("[tool] is stuck to your hand.")) + return + inserted_bomb = tool + tank_to_target = inserted_bomb.tank_two + to_chat(user, span_notice("You insert [tool] into [src]")) + return + update_appearance() + return ..() + +/obj/machinery/bomb_actualizer/wrench_act(mob/living/user, obj/item/tool) + . = ..() + if(!active) + default_unfasten_wrench(user, tool) + return TOOL_ACT_TOOLTYPE_SUCCESS + return FALSE + +/obj/machinery/bomb_actualizer/screwdriver_act(mob/living/user, obj/item/tool) + if(!active) + if(!default_deconstruction_screwdriver(user, "[base_icon_state]-off", "[base_icon_state]", tool)) + return FALSE + update_appearance() + return TRUE + +/obj/machinery/bomb_actualizer/crowbar_act(mob/living/user, obj/item/tool) + if(!default_deconstruction_crowbar(tool) && !active) + return FALSE + return TRUE + +/** + * Starts the Detonation Sequence + */ +/obj/machinery/bomb_actualizer/proc/start_detonation() + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_BOMB_BUTTON)) + + if(active) + say("ERROR: The countdown has aready begun!!!") + TIMER_COOLDOWN_START(src, COOLDOWN_BOMB_BUTTON, 3 SECONDS) + return + + else if(!istype(inserted_bomb)) + say("ERROR: No Bomb Inserted") + TIMER_COOLDOWN_START(src, COOLDOWN_BOMB_BUTTON, 3 SECONDS) + return + + + else if(!on_reebe(src)) + say("Beginning detonation sequence. Countdown starting.") + alerthere = get_area(src) + countdown.start() + active = TRUE + next_beep = world.time + 1 SECONDS + timer = world.time + (default_time) + begin_processing() + priority_announce("DANGER - Tampering of bluespace ordinance dampeners detected, Resulting explosion may be catastrophic to station integrity. \ + Remove the tampering device within 7 Minutes or evacuate the localized areas. \ + Location: [alerthere].", "Doppler Array Detection - DANGER", 'sound/misc/notice3.ogg') + TIMER_COOLDOWN_START(src, COOLDOWN_BOMB_BUTTON, 3 SECONDS) + return + say("UNKNOWN ERROR: Nice try nerd. ") + TIMER_COOLDOWN_START(src, COOLDOWN_BOMB_BUTTON, 3 SECONDS) + return + +//Process for handling the bombs timer +/obj/machinery/bomb_actualizer/process() + var/volume = 40 + if(!active) + end_processing() + timer = null + next_beep = null + countdown.stop() + stage = 0 + return + if(!isnull(next_beep) && (next_beep <= world.time)) + + playsound(loc, beepsound, volume, FALSE) + next_beep = world.time +10 + if(seconds_remaining() <= 60) + if(stage == 0) + radio.talk_into(src, "WARNING: DETONATION IN ONE MINUTE.", common_channel) + playsound(loc, scarywarning, volume, FALSE) + stage++ + if(seconds_remaining() <= 10) + if(stage == 1) + radio.talk_into(src, "FAILSAFE DISENGAGED, DETONATION IMMINENT", common_channel) + playsound(loc, verybadsound, 80, FALSE) + stage++ + + if(active && (timer <= world.time)) + playsound(loc, youdied, 100, FALSE, 45) + active = FALSE + stage = 0 + update_appearance() + inserted_bomb.toggle_valve(tank_to_target) + + +/obj/machinery/bomb_actualizer/proc/seconds_remaining() + if(active) + . = max(0, round(timer - world.time) / 10) + + else + . = 420 + + + + /** + * catches the parameters of the TTV's explosion as it happens internally, + * cancels the explosion and then re-triggers it to happen with modified perameters (such as maxcap = false) + * while REDUCING the theoretical size by actualizer multiplier + * (actualizer_multiplier 0.25 would mean the 200 size theoretical bomb is only 12 + (200*0.25) in size ) + */ +/obj/machinery/bomb_actualizer/proc/modify_explosion(atom/source, list/arguments) + SIGNAL_HANDLER + if(!exploded) + var/heavy = arguments[EXARG_KEY_DEV_RANGE] + var/medium = arguments[EXARG_KEY_HEAVY_RANGE] + var/light = arguments[EXARG_KEY_LIGHT_RANGE] + var/flame = 0 + var/flash = 0 + var/turf/location = get_turf(src) + var/actualizer_multiplier = 0.5 + var/capped_heavy + var/capped_medium + var/capped_light + + if(heavy > 12) + capped_heavy = (GLOB.MAX_EX_DEVESTATION_RANGE + (heavy * actualizer_multiplier)) + + if(medium > 12) + capped_medium = (GLOB.MAX_EX_HEAVY_RANGE + (medium * actualizer_multiplier)) + + if(light > 12) + capped_light = (GLOB.MAX_EX_LIGHT_RANGE + (light * actualizer_multiplier)) + + SSexplosions.explode(location, capped_heavy, capped_medium, capped_light, flame, flash, TRUE, TRUE, FALSE, FALSE) + exploded = TRUE + return COMSIG_CANCEL_EXPLOSION + return COMSIG_ATOM_EXPLODE + +/obj/machinery/bomb_actualizer/examine(mob/user) + . = ..() + . += "Big bomb." + if(examinable_countdown) + . += span_notice("A digital display on it reads \"[seconds_remaining()]\".") + if(active) + balloon_alert(user, "[seconds_remaining()]") + else + . += span_notice({"The digital display on it is inactive."}) + +/obj/machinery/bomb_actualizer/ui_interact(mob/user, datum/tgui/ui) + .=..() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BombActualizer", name) + ui.open() + +/obj/machinery/bomb_actualizer/ui_act(action, params) + . = ..() + if (.) + return + if(action == "start_timer" && !active) + start_detonation() + diff --git a/monkestation/code/game/objects/effects/countdown.dm b/monkestation/code/game/objects/effects/countdown.dm index 4bff884f31ac..f0b805002e7b 100644 --- a/monkestation/code/game/objects/effects/countdown.dm +++ b/monkestation/code/game/objects/effects/countdown.dm @@ -11,3 +11,14 @@ var/completion = round(C.get_completion()) return completion + + +/obj/effect/countdown/bomb_actualizer + name = "bomb actualizer countdown" + color = "#ff9100" +/obj/effect/countdown/bomb_actualizer/get_value() + var/obj/machinery/bomb_actualizer/Bomb_Countdown = attached_to + if(!istype(Bomb_Countdown)) + return + else if(Bomb_Countdown.active) + return Bomb_Countdown.seconds_remaining() diff --git a/monkestation/code/game/objects/items/circuitboards/machine_circuitboards.dm b/monkestation/code/game/objects/items/circuitboards/machine_circuitboards.dm index f92f715cb3f9..ffc5fe574103 100644 --- a/monkestation/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/monkestation/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -84,6 +84,15 @@ . = ..() . += "Cloud ID is currently set to [cloud_id]." +/obj/item/circuitboard/machine/bomb_actualizer + name = "Bomb Actualizer (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/bomb_actualizer + req_components = list( + /datum/stock_part/manipulator = 1, + /datum/stock_part/scanning_module = 1, + /datum/stock_part/matter_bin = 5) + /obj/item/circuitboard/machine/composters name = "NT-Brand Auto Composter (Machine Board)" greyscale_colors = CIRCUIT_COLOR_ENGINEERING diff --git a/monkestation/code/modules/research/designs/machine_designs.dm b/monkestation/code/modules/research/designs/machine_designs.dm index 9dd731010b29..d5c912d3bb51 100644 --- a/monkestation/code/modules/research/designs/machine_designs.dm +++ b/monkestation/code/modules/research/designs/machine_designs.dm @@ -81,6 +81,16 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE +/datum/design/board/bomb_actualizer + name = "Machine Design (Bomb Actualizer Board)" + desc = "The circuit board for a bomb actualizing machine" + id = "bomb_actualizer" + build_path = /obj/item/circuitboard/machine/bomb_actualizer + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_RESEARCH + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + /datum/design/board/composters name = "Machine Design (NT-Brand Auto Composter Board)" desc = "The circuit board for a NT-Brand Auto Composter." diff --git a/monkestation/code/modules/research/techweb/all_nodes.dm b/monkestation/code/modules/research/techweb/all_nodes.dm index 741c43fcf747..65498530e0db 100644 --- a/monkestation/code/modules/research/techweb/all_nodes.dm +++ b/monkestation/code/modules/research/techweb/all_nodes.dm @@ -223,3 +223,15 @@ "ipc_leg_right" ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + + + +/datum/techweb_node/bomb_actualizer + id = "bomb_actualizer" + display_name = "Bomb Actualization Technology" + description = "Using bluespace technology we can increase the actual yield of ordinance to their theoretical maximum on station... to disasterous effect." + prereq_ids = list("micro_bluespace", "bluespace_storage", "practical_bluespace") + design_ids = list( + "bomb_actualizer", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 20000) diff --git a/sound/misc/guitarreverb.ogg b/sound/misc/guitarreverb.ogg new file mode 100644 index 000000000000..b0492dfbfb1b Binary files /dev/null and b/sound/misc/guitarreverb.ogg differ diff --git a/tgstation.dme b/tgstation.dme index b8fdb34eecb7..4ea67be4cf5c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5882,6 +5882,7 @@ #include "monkestation\code\game\area\areas\station.dm" #include "monkestation\code\game\machinery\_machinery.dm" #include "monkestation\code\game\machinery\announcement_system.dm" +#include "monkestation\code\game\machinery\bomb_actualizer.dm" #include "monkestation\code\game\machinery\cloning.dm" #include "monkestation\code\game\machinery\deployable.dm" #include "monkestation\code\game\machinery\exp_cloner.dm" diff --git a/tgui/packages/tgui/interfaces/BombActualizer.tsx b/tgui/packages/tgui/interfaces/BombActualizer.tsx new file mode 100644 index 000000000000..ade41d8c7208 --- /dev/null +++ b/tgui/packages/tgui/interfaces/BombActualizer.tsx @@ -0,0 +1,33 @@ +import { useBackend } from '../backend'; +import { Button, Section } from '../components'; +import { Window } from '../layouts'; + +export const BombActualizer = (props) => { + const { act } = useBackend(); + return ( + + + + + + ); +}; + +export const BombActualizerContent = (props) => { + const { act } = useBackend(); + const color = 'rgba(13, 13, 213, 0.7)'; + const backColor = 'rgba(0, 0, 69, 0.5)'; + return ( +
+
+ ); +};