diff --git a/code/__DEFINES/dcs/signals/signals_saboteur.dm b/code/__DEFINES/dcs/signals/signals_saboteur.dm new file mode 100644 index 00000000000..5ef536683fe --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_saboteur.dm @@ -0,0 +1,4 @@ +// Light disruptor. Not to be confused with the light eater, which permanently disables lights. + +/// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target +#define COMSIG_HIT_BY_SABOTEUR "hit_by_saboteur" diff --git a/code/datums/components/seclight_attachable.dm b/code/datums/components/seclight_attachable.dm index 56761cfd1bf..b3f36fe041a 100644 --- a/code/datums/components/seclight_attachable.dm +++ b/code/datums/components/seclight_attachable.dm @@ -98,6 +98,7 @@ RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_parent_deleted)) + RegisterSignal(parent, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /datum/component/seclite_attachable/UnregisterFromParent() UnregisterSignal(parent, list( @@ -156,12 +157,10 @@ if(!light) return FALSE - light.on = !light.on - light.update_brightness() - if(user) - user.balloon_alert(user, "[light.name] toggled [light.on ? "on":"off"]") - - playsound(light, 'sound/weapons/empty.ogg', 100, TRUE) + var/successful_toggle = light.toggle_light(user) + if(!successful_toggle) + return TRUE + user.balloon_alert(user, "[light.name] toggled [light.on ? "on":"off"]") update_light() return TRUE @@ -296,3 +295,9 @@ // Yes, this might mess with other icon state alterations, // but that's the downside of using icon states over overlays. source.icon_state = base_state + +/// Signal proc for [COMSIG_HIT_BY_SABOTEUR] that turns the light off for a few seconds. +/datum/component/seclite_attachable/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + . = light.on_saboteur(source, disrupt_duration) + update_light() diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index a47115a9f60..575464a98af 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -30,7 +30,6 @@ var/busy = FALSE var/emped = FALSE //Number of consecutive EMP's on this camera var/in_use_lights = 0 - // Upgrades bitflag var/upgrades = 0 @@ -105,6 +104,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) alarm_manager = new(src) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) + /obj/machinery/camera/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) for(var/i in network) network -= i @@ -155,7 +156,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) if(!status && powered()) . += span_info("It can reactivated with wirecutters.") -/obj/machinery/camera/emp_act(severity) +/obj/machinery/camera/emp_act(severity, reset_time = 90 SECONDS) . = ..() if(!status) return @@ -168,7 +169,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) set_light(0) emped = emped+1 //Increase the number of consecutive EMP's update_appearance() - addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), 90 SECONDS) + addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) for(var/i in GLOB.player_list) var/mob/M = i if (M.client?.eye == src) @@ -176,6 +177,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) M.reset_perspective(null) to_chat(M, span_warning("The screen bursts into static!")) +/obj/machinery/camera/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + emp_act(EMP_LIGHT, reset_time = disrupt_duration) + return TRUE + /obj/machinery/camera/proc/post_emp_reset(thisemp, previous_network) if(QDELETED(src)) return @@ -188,7 +194,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) if(can_use()) GLOB.cameranet.addCamera(src) emped = 0 //Resets the consecutive EMP count - addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 100) + addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS) /obj/machinery/camera/ex_act(severity, target) if(invuln) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 14fc91ea7d0..ee7a66044fd 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -23,6 +23,8 @@ light_range = 4 light_power = 1 light_on = FALSE + /// If we've been forcibly disabled for a temporary amount of time. + COOLDOWN_DECLARE(disabled_time) /// Can we toggle this light on and off (used for contexual screentips only) var/toggle_context = TRUE /// The sound the light makes when it's turned on @@ -32,16 +34,15 @@ /// Is the light turned on or off currently var/on = FALSE -// SKYRAT EDIT REMOVAL BEGIN - MOVED TO MODUALR FLASHLIGHT.DM -/* /obj/item/flashlight/Initialize(mapload) . = ..() if(icon_state == "[initial(icon_state)]-on") on = TRUE update_brightness() register_context() -*/ -// SKYRAT EDIT REMOVAL END + + if(toggle_context) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /obj/item/flashlight/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) // single use lights can be toggled on once @@ -68,19 +69,21 @@ if(light_system == STATIC_LIGHT) update_light() -// SKYRAT EDIT REMOVAL BEGIN - MOVED TO MODUALR FLASHLIGHT.DM -/* -/obj/item/flashlight/proc/toggle_light() +/obj/item/flashlight/proc/toggle_light(mob/user) + var/disrupted = FALSE + //playsound(src, on ? sound_on : sound_off, 40, TRUE) SKYRAT EDIT REMOVAL - SOUND HANDLED IN MODULAR FLASHLIGHT.DM on = !on - playsound(src, on ? sound_on : sound_off, 40, TRUE) + if(!COOLDOWN_FINISHED(src, disabled_time)) + if(user) + balloon_alert(user, "disrupted!") + on = FALSE + disrupted = TRUE update_brightness() update_item_action_buttons() - return TRUE + return !disrupted /obj/item/flashlight/attack_self(mob/user) - toggle_light() -*/ -// SKYRAT EDIT REMOVAL END + toggle_light(user) /obj/item/flashlight/attack_hand_secondary(mob/user, list/modifiers) attack_self(user) @@ -262,6 +265,14 @@ if(istype(user) && dir != user.dir) setDir(user.dir) +/// when hit by a light disruptor - turns the light off, forces the light to be disabled for a few seconds +/obj/item/flashlight/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + if(on) + toggle_light() + COOLDOWN_START(src, disabled_time, disrupt_duration) + return TRUE + /obj/item/flashlight/pen name = "penlight" desc = "A pen-sized light, used by medical staff. It can also be used to create a hologram to alert people of incoming medical assistance." @@ -420,16 +431,15 @@ damtype = BURN . = ..() -/obj/item/flashlight/flare/turn_off() //SKYRAT EDIT CHANGE - //on = FALSE SKYRAT EDIT REMOVAL +/obj/item/flashlight/flare/proc/turn_off() + on = FALSE name = initial(name) attack_verb_continuous = initial(attack_verb_continuous) attack_verb_simple = initial(attack_verb_simple) hitsound = initial(hitsound) force = initial(force) damtype = initial(damtype) - //update_brightness() - SKYRAT EDIT MOVED TO PARENT - . = ..() //SKYRAT EDIT - MODULAR PARENT PROC + update_brightness() /obj/item/flashlight/flare/extinguish() . = ..() @@ -749,11 +759,9 @@ turn_off() STOP_PROCESSING(SSobj, src) -/* SKYRAT EDIT REMOVAL /obj/item/flashlight/glowstick/proc/turn_off() on = FALSE update_appearance(UPDATE_ICON) -*/ /obj/item/flashlight/glowstick/update_appearance(updates=ALL) . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 1e05bae6298..de19ce19058 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -15,7 +15,7 @@ contents_pressure_protection = 0 /// How insulated the thing is, for the purposes of calculating body temperature. Must be between 0 and 1! contents_thermal_insulation = 0 - pass_flags_self = LETPASSCLICKS + pass_flags_self = PASSSTRUCTURE | LETPASSCLICKS /// The overlay for the closet's door var/obj/effect/overlay/closet_door/door_obj diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index f40e4fa1447..6115b1e1557 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -63,3 +63,13 @@ price_max = CARGO_CRATE_VALUE * 2 stock_max = 2 availability_prob = 50 + +/datum/market_item/weapon/fisher + name = "SC/FISHER Saboteur Handgun" + desc = "A self-recharging, compact pistol that disrupts flashlights and security cameras, if only temporarily. Also usable in melee." + item = /obj/item/gun/energy/recharge/fisher + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + stock_max = 1 + availability_prob = 50 diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index a1edd69ba3e..8ae842807a8 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -38,6 +38,7 @@ ) //technically it's huge and bulky, but this provides an incentive to use it AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /obj/item/kinetic_crusher/Destroy() QDEL_LIST(trophies) @@ -165,6 +166,10 @@ playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) update_appearance() +/obj/item/kinetic_crusher/proc/on_saboteur(datum/source, disrupt_duration) + set_light_on(FALSE) + playsound(src, 'sound/weapons/empty.ogg', 100, TRUE) + return TRUE /obj/item/kinetic_crusher/update_icon_state() inhand_icon_state = "crusher[HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 9546a659e41..f087eb6b92c 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -68,6 +68,7 @@ RegisterSignal(ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act)) RegisterSignal(ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) RegisterSignal(ethereal, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(ethereal, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) ethereal_light = ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species) spec_updatehealth(ethereal) new_ethereal.set_safe_hunger_level() @@ -84,6 +85,7 @@ UnregisterSignal(former_ethereal, COMSIG_ATOM_EMAG_ACT) UnregisterSignal(former_ethereal, COMSIG_ATOM_EMP_ACT) UnregisterSignal(former_ethereal, COMSIG_LIGHT_EATER_ACT) + UnregisterSignal(former_ethereal, COMSIG_HIT_BY_SABOTEUR) QDEL_NULL(ethereal_light) return ..() @@ -147,6 +149,15 @@ if(EMP_HEAVY) addtimer(CALLBACK(src, PROC_REF(stop_emp), H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds +/datum/species/ethereal/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + var/mob/living/carbon/human/our_target = source + EMPeffect = TRUE + spec_updatehealth(our_target) + to_chat(our_target, span_warning("Something inside of you crackles in a bad way.")) + our_target.take_bodypart_damage(burn = 3, wound_bonus = CANT_WOUND) + addtimer(CALLBACK(src, PROC_REF(stop_emp), our_target), disrupt_duration, TIMER_UNIQUE|TIMER_OVERRIDE) + /datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user) SIGNAL_HANDLER if(emageffect) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 9732222f0cf..17e59660eb4 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -19,6 +19,7 @@ AddElement(/datum/element/ridable, /datum/component/riding/creature/cyborg) RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(charge)) RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) robot_modules_background = new() robot_modules_background.icon_state = "block" @@ -470,6 +471,13 @@ smash_headlamp() return COMPONENT_BLOCK_LIGHT_EATER +/// special handling for getting shot with a light disruptor/saboteur e.g. the fisher +/mob/living/silicon/robot/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + if(lamp_enabled) + toggle_headlamp(TRUE) + to_chat(src, span_warning("Your headlamp was forcibly turned off. Restarting it should fix it, though.")) + return TRUE /** * Handles headlamp smashing diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index 3ab8ece250f..0898e31735b 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -144,6 +144,7 @@ /obj/machinery/power/floodlight/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_OBJ_PAINTED, TYPE_PROC_REF(/obj/machinery/power/floodlight, on_color_change)) //update light color when color changes + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) register_context() /obj/machinery/power/floodlight/proc/on_color_change(obj/machinery/power/flood_light, mob/user, obj/item/toy/crayon/spraycan/spraycan, is_dark_color) @@ -289,6 +290,11 @@ /obj/machinery/power/floodlight/attack_ai(mob/user) return attack_hand(user) +/obj/machinery/power/floodlight/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + atom_break(ENERGY) // technically, + return TRUE + /obj/machinery/power/floodlight/atom_break(damage_flag) . = ..() if(!.) @@ -297,7 +303,8 @@ var/obj/structure/floodlight_frame/floodlight_frame = new(loc) floodlight_frame.state = FLOODLIGHT_NEEDS_LIGHTS - new /obj/item/light/tube(loc) + var/obj/item/light/tube/our_light = new(loc) + our_light.shatter() qdel(src) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 2486a6500c1..ea6a28a8fe4 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -114,6 +114,7 @@ // Light projects out backwards from the dir of the light set_light(l_dir = REVERSE_DIR(dir)) RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) AddElement(/datum/element/atmos_sensitive, mapload) return INITIALIZE_HINT_LATELOAD @@ -706,6 +707,11 @@ tube?.burn() return +/obj/machinery/light/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + break_light_tube() + return TRUE + /obj/machinery/light/proc/grey_tide(datum/source, list/grey_tide_areas) SIGNAL_HANDLER diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index bedfab7b235..24fba4b9ba4 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -74,3 +74,9 @@ select_name = "marksman nanoshot" e_cost = 0 fire_sound = 'sound/weapons/gun/revolver/shot_alt.ogg' + +/obj/item/ammo_casing/energy/fisher + projectile_type = /obj/projectile/energy/fisher + select_name = "light-buster" + e_cost = 250 + fire_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' // fwip fwip fwip fwip diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index ddacb419bbe..e76af741a18 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -26,6 +26,7 @@ var/vary_fire_sound = TRUE var/fire_sound_volume = 50 var/dry_fire_sound = 'sound/weapons/gun/general/dry_fire.ogg' + var/dry_fire_sound_volume = 30 var/suppressed = null //whether or not a message is displayed when fired var/can_suppress = FALSE var/suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' @@ -169,7 +170,7 @@ /obj/item/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj) balloon_alert_to_viewers("*click*") - playsound(src, dry_fire_sound, 30, TRUE) + playsound(src, dry_fire_sound, dry_fire_sound_volume, TRUE) /obj/item/gun/proc/fire_sounds() if(suppressed) diff --git a/code/modules/projectiles/guns/energy/recharge.dm b/code/modules/projectiles/guns/energy/recharge.dm index 6644accd8a5..eed27478755 100644 --- a/code/modules/projectiles/guns/energy/recharge.dm +++ b/code/modules/projectiles/guns/energy/recharge.dm @@ -135,3 +135,36 @@ custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*2) suppressed = null ammo_type = list(/obj/item/ammo_casing/energy/bolt/large) + +/// A silly gun that does literally zero damage, but disrupts electrical sources of light, like flashlights. +/obj/item/gun/energy/recharge/fisher + name = "\improper SC/FISHER disruptor" + desc = "A self-recharging, permanently suppressed, and very haphazardly modified accelerator handgun that does literally nothing to anything except light fixtures and cameras. \ + Can fire twice before requiring a recharge, with bolts passing through machinery, but demands precision." + icon_state = "fisher" + base_icon_state = "fisher" + dry_fire_sound_volume = 10 + w_class = WEIGHT_CLASS_SMALL + holds_charge = TRUE + suppressed = TRUE + recharge_time = 1.2 SECONDS + ammo_type = list(/obj/item/ammo_casing/energy/fisher) + +/obj/item/gun/energy/recharge/fisher/examine_more(mob/user) + . = ..() + . += span_notice("The SC/FISHER is an illegally-modified kinetic accelerator cut down and refit into a disassembled miniature energy gun chassis, with its pressure chamber \ + attenuated to launch kinetic bolts that disrupt flashlights and cameras, if only temporarily. This effect also works on cyborg headlamps, and works longer in melee.

\ + While some would argue that this is a really terrible design choice, others argue that it is very funny to be able to shoot at light sources. Caveat emptor.") + +/obj/item/gun/energy/recharge/fisher/afterattack(atom/target, mob/living/user, flag, params) + // you should just shoot them, but in case you can't/wont + . = ..() + if(user.Adjacent(target)) + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.on_hit(target) + +/obj/item/gun/energy/recharge/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + // ...you reeeeeally just shoot them, but in case you can't/won't + . = ..() + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.on_hit(hit_atom) diff --git a/code/modules/projectiles/projectile/special/lightbreaker.dm b/code/modules/projectiles/projectile/special/lightbreaker.dm new file mode 100644 index 00000000000..cf273a1d3b2 --- /dev/null +++ b/code/modules/projectiles/projectile/special/lightbreaker.dm @@ -0,0 +1,34 @@ +/obj/projectile/energy/fisher + name = "attenuated kinetic force" + alpha = 0 + damage = 0 + damage_type = BRUTE + armor_flag = BOMB + range = 14 + projectile_phasing = PASSTABLE | PASSMOB | PASSMACHINE | PASSSTRUCTURE + hitscan = TRUE + var/disrupt_duration = 10 SECONDS + +/obj/projectile/energy/fisher/on_hit(atom/target, blocked, pierce_hit) + . = ..() + SEND_SIGNAL(target, COMSIG_HIT_BY_SABOTEUR, disrupt_duration) + if(!isliving(target)) + return + var/list/things_to_disrupt = list() + var/lights_flickered = 0 + if(ishuman(target)) + var/mob/living/carbon/human/human_target = target + things_to_disrupt = human_target.get_all_gear() + else + var/mob/living/living_target = target // i guess this covers borgs too? + things_to_disrupt = living_target.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE) + for(var/obj/item/thingy as anything in things_to_disrupt) + if(SEND_SIGNAL(thingy, COMSIG_HIT_BY_SABOTEUR, disrupt_duration)) + lights_flickered++ + if(lights_flickered) + to_chat(target, span_warning("Your light [lights_flickered > 1 ? "sources flick" : "source flicks"] off.")) + +/obj/projectile/energy/fisher/melee + range = 1 + suppressed = SUPPRESSED_VERY + disrupt_duration = 20 SECONDS diff --git a/icons/obj/weapons/guns/energy.dmi b/icons/obj/weapons/guns/energy.dmi index 07ac342a36d..97b75335b91 100644 Binary files a/icons/obj/weapons/guns/energy.dmi and b/icons/obj/weapons/guns/energy.dmi differ diff --git a/modular_skyrat/modules/cell_component/code/flashlight.dm b/modular_skyrat/modules/cell_component/code/flashlight.dm index 01de50266e3..6e585781a83 100644 --- a/modular_skyrat/modules/cell_component/code/flashlight.dm +++ b/modular_skyrat/modules/cell_component/code/flashlight.dm @@ -18,13 +18,10 @@ /obj/item/flashlight/Initialize(mapload) . = ..() - if(icon_state == "[initial(icon_state)]-on") - turn_on(FALSE) - update_brightness() - register_context() + update_item_action_buttons() if(uses_battery) - AddComponent(/datum/component/cell, cell_override, CALLBACK(src, PROC_REF(turn_off)), _has_cell_overlays = FALSE) + AddComponent(/datum/component/cell, cell_override, CALLBACK(src, PROC_REF(quietly_turn_off)), _has_cell_overlays = FALSE) /obj/item/flashlight/examine(mob/user) . = ..() @@ -55,46 +52,37 @@ set_light_power(initial(light_power)) to_chat(user, span_notice("You set [src] to low.")) -/obj/item/flashlight/proc/toggle_light() +/obj/item/flashlight/toggle_light(noisy = TRUE) + . = ..() if(on) - turn_off() - else + after_turn_on() if(uses_battery && !(item_use_power(power_use_amount, TRUE) & COMPONENT_POWER_SUCCESS)) return - turn_on(makes_noise_when_lit) - playsound(src, on ? sound_on : sound_off, 40, TRUE) - return TRUE - -/obj/item/flashlight/attack_self(mob/user) - . = ..() - toggle_light() + if(noisy) + playsound(src, on ? sound_on : sound_off, 40, TRUE) /** * Handles turning on the flashlight. * Parameters: * * noisy - Boolean on whether the flashlight should make an additional noise from being turned on or not. Defaults to TRUE. */ -/obj/item/flashlight/proc/turn_on(noisy = TRUE) - on = TRUE - if (uses_battery) +/obj/item/flashlight/proc/after_turn_on(noisy = TRUE) + if(uses_battery) START_PROCESSING(SSobj, src) - update_brightness() if(noisy) playsound(src, 'modular_skyrat/master_files/sound/effects/flashlight.ogg', 40, TRUE) //Credits to ERIS for the sound - update_item_action_buttons() -/// Handles turning off the flashlight. -/obj/item/flashlight/proc/turn_off() - on = FALSE - update_brightness() - update_item_action_buttons() +/// Quietly turns the flashlight off if it was on (called by the battery running out of charge). +/obj/item/flashlight/proc/quietly_turn_off() + if(on) + toggle_light(noisy = FALSE) /obj/item/flashlight/process(seconds_per_tick) if(!on) STOP_PROCESSING(SSobj, src) return if(uses_battery && !(item_use_power(power_use_amount) & COMPONENT_POWER_SUCCESS)) - turn_off() + quietly_turn_off() /obj/item/flashlight/update_icon_state() . = ..() diff --git a/tgstation.dme b/tgstation.dme index 194d81879f0..d1c22afce1e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -319,6 +319,7 @@ #include "code\__DEFINES\dcs\signals\signals_radiation.dm" #include "code\__DEFINES\dcs\signals\signals_reagent.dm" #include "code\__DEFINES\dcs\signals\signals_restaurant.dm" +#include "code\__DEFINES\dcs\signals\signals_saboteur.dm" #include "code\__DEFINES\dcs\signals\signals_scangate.dm" #include "code\__DEFINES\dcs\signals\signals_screentips.dm" #include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm" @@ -4991,6 +4992,7 @@ #include "code\modules\projectiles\projectile\special\floral.dm" #include "code\modules\projectiles\projectile\special\gravity.dm" #include "code\modules\projectiles\projectile\special\ion.dm" +#include "code\modules\projectiles\projectile\special\lightbreaker.dm" #include "code\modules\projectiles\projectile\special\meteor.dm" #include "code\modules\projectiles\projectile\special\mindflayer.dm" #include "code\modules\projectiles\projectile\special\neurotoxin.dm"