Skip to content

Commit

Permalink
[MIRROR] Buffs the SC/FISHER Saboteur Handgun. (#1432) (#2396)
Browse files Browse the repository at this point in the history
* Buffs the SC/FISHER Saboteur Handgun. (#81553)

## About The Pull Request
The saboteur gun will now silence pAIs, toggle off radio broadcasting
(won't auto-relay nearby speech), disable turrets, chill out secbots a
little, and turn off APCs like power outages do.
The disrupt duration has also been buffed from 10/20 to 15/25 for ranged
and point-blank respectively.
Removed a conspicious chat message from an otherwise inconspicious gun.
Brought the code up to date.

## Why It's Good For The Game
The concept is cool, alas it's also undermined by how much of a joke
it's right now, and the game has plenty already.
The amount of interactions it has with things is underwhelming, so you
could barely consider it a stealth tool. The duration is also quite
scarce, I pointed that out in the original PR too.

Basically, I want to make the item cooler.

## Changelog

:cl:
balance: Buffed the duration of the SC/FISHER Saboteur Handgun's
disruption effects. It's also stealthier and it won't conspiciously
alert living mobs hit by it.
add: Added saboteur interactions with radios, pAIs, turrets, secbots and
APCs.
/:cl:

---------



* Buffs the SC/FISHER Saboteur Handgun.

---------

Co-authored-by: NovaBot <[email protected]>
Co-authored-by: Ghom <[email protected]>
Co-authored-by: Jacquerel <[email protected]>
  • Loading branch information
4 people authored Mar 14, 2024
1 parent f051967 commit 86b06e3
Show file tree
Hide file tree
Showing 21 changed files with 181 additions and 85 deletions.
4 changes: 4 additions & 0 deletions code/__DEFINES/dcs/signals/signals_object.dm
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@
///sent to the projectile when spawning the item (shrapnel) that may be embedded: (new_item)
#define COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED "projectile_on_spawn_embedded"

/// 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"
#define COMSIG_SABOTEUR_SUCCESS (1<<0)

// /obj/vehicle/sealed/car/vim signals

///from /datum/action/vehicle/sealed/noise/chime/Trigger(): ()
Expand Down
5 changes: 0 additions & 5 deletions code/__DEFINES/dcs/signals/signals_saboteur.dm

This file was deleted.

5 changes: 5 additions & 0 deletions code/__DEFINES/robots.dm
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ DEFINE_BITFIELD(bot_cover_flags, list(
#define JUDGE_IDCHECK (1<<1)
#define JUDGE_WEAPONCHECK (1<<2)
#define JUDGE_RECORDCHECK (1<<3)
///lowered threat level
#define JUDGE_CHILLOUT (1<<4)

/// Above this level of assessed threat, Beepsky will attack you
#define THREAT_ASSESS_DANGEROUS 4
Expand All @@ -215,13 +217,16 @@ DEFINE_BITFIELD(bot_cover_flags, list(
#define SECBOT_CHECK_RECORDS (1<<3)
///Whether we will stun & cuff or endlessly stun
#define SECBOT_HANDCUFF_TARGET (1<<4)
///if it's currently affected by a saboteur bolt (lowered perp threat level)
#define SECBOT_SABOTEUR_AFFECTED (1<<5)

DEFINE_BITFIELD(security_mode_flags, list(
"SECBOT_DECLARE_ARRESTS" = SECBOT_DECLARE_ARRESTS,
"SECBOT_CHECK_IDS" = SECBOT_CHECK_IDS,
"SECBOT_CHECK_WEAPONS" = SECBOT_CHECK_WEAPONS,
"SECBOT_CHECK_RECORDS" = SECBOT_CHECK_RECORDS,
"SECBOT_HANDCUFF_TARGET" = SECBOT_HANDCUFF_TARGET,
"SECBOT_SABOTEUR_AFFECTED" = SECBOT_SABOTEUR_AFFECTED,
))

//MedBOT defines
Expand Down
3 changes: 2 additions & 1 deletion code/game/machinery/camera/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)

/obj/machinery/camera/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
emp_act(EMP_LIGHT, reset_time = disrupt_duration)
//lasts twice as much so we don't have to constantly shoot cameras just to be S T E A L T H Y
emp_act(EMP_LIGHT, reset_time = disrupt_duration * 2)
return COMSIG_SABOTEUR_SUCCESS

/obj/machinery/camera/proc/post_emp_reset(thisemp, previous_network)
Expand Down
63 changes: 36 additions & 27 deletions code/game/machinery/porta_turret/portable_turret.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ DEFINE_BITFIELD(turret_flags, list(
var/datum/action/turret_toggle/toggle_action
/// Mob that is remotely controlling the turret
var/mob/remote_controller
/// While the cooldown is still going on, it cannot be re-enabled.
COOLDOWN_DECLARE(disabled_time)

/datum/armor/machinery_porta_turret
melee = 50
Expand Down Expand Up @@ -133,18 +135,32 @@ DEFINE_BITFIELD(turret_flags, list(
if(!has_cover)
INVOKE_ASYNC(src, PROC_REF(popUp))

RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

AddElement(/datum/element/hostile_machine)

/obj/machinery/porta_turret/proc/toggle_on(set_to)
var/current = on
if (!isnull(set_to))
on = set_to
else
on = !on
if (current != on)
check_should_process()
if (!on)
popDown()
///Toggles the turret on or off depending on the value of the turn_on arg.
/obj/machinery/porta_turret/proc/toggle_on(turn_on = TRUE)
if(on == turn_on)
return
if(on && !COOLDOWN_FINISHED(src, disabled_time))
return
on = turn_on
check_should_process()
if (!on)
popDown()

///Prevents turned from being turned on for a duration, then restarts them after that if the second ard is true.
/obj/machinery/porta_turret/proc/set_disabled(duration = 6 SECONDS, will_restart = on)
COOLDOWN_START(src, disabled_time, duration)
if(will_restart)
addtimer(CALLBACK(src, PROC_REF(toggle_on), TRUE), duration + 1) //the cooldown isn't over until the tick after its end.
toggle_on(FALSE)

/obj/machinery/porta_turret/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(set_disabled), disrupt_duration)
return COMSIG_SABOTEUR_SUCCESS

/obj/machinery/porta_turret/proc/check_should_process()
if (datum_flags & DF_ISPROCESSING)
Expand Down Expand Up @@ -256,7 +272,7 @@ DEFINE_BITFIELD(turret_flags, list(
switch(action)
if("power")
if(anchored)
toggle_on()
toggle_on(!on)
return TRUE
else
to_chat(usr, span_warning("It has to be secured first!"))
Expand Down Expand Up @@ -364,10 +380,8 @@ DEFINE_BITFIELD(turret_flags, list(
audible_message(span_hear("[src] hums oddly..."))
obj_flags |= EMAGGED
controllock = TRUE
toggle_on(FALSE) //turns off the turret temporarily
set_disabled(6 SECONDS)
update_appearance()
//6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
addtimer(CALLBACK(src, PROC_REF(toggle_on), TRUE), 6 SECONDS)
//turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return TRUE

Expand All @@ -385,11 +399,9 @@ DEFINE_BITFIELD(turret_flags, list(
if(prob(20))
turret_flags |= TURRET_FLAG_SHOOT_ALL // Shooting everyone is a pretty big deal, so it's least likely to get turned on

toggle_on(FALSE)
set_disabled(rand(6 SECONDS, 20 SECONDS))
remove_control()

addtimer(CALLBACK(src, PROC_REF(toggle_on), TRUE), rand(60,600))

/obj/machinery/porta_turret/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
. = ..()
if(. && atom_integrity > 0) //damage received
Expand Down Expand Up @@ -1186,17 +1198,14 @@ DEFINE_BITFIELD(turret_flags, list(
installation = /obj/item/gun/energy/laser/bluetag
team_color = "blue"

/obj/machinery/porta_turret/lasertag/bullet_act(obj/projectile/P)
/obj/machinery/porta_turret/lasertag/bullet_act(obj/projectile/projectile)
. = ..()
if(on)
if(team_color == "blue")
if(istype(P, /obj/projectile/beam/lasertag/redtag))
toggle_on(FALSE)
addtimer(CALLBACK(src, PROC_REF(toggle_on), TRUE), 10 SECONDS)
else if(team_color == "red")
if(istype(P, /obj/projectile/beam/lasertag/bluetag))
toggle_on(FALSE)
addtimer(CALLBACK(src, PROC_REF(toggle_on), TRUE), 10 SECONDS)
if(!on)
return
if(team_color == "blue" && istype(projectile, /obj/projectile/beam/lasertag/redtag))
set_disabled(10 SECONDS)
else if(team_color == "red" && istype(projectile, /obj/projectile/beam/lasertag/bluetag))
set_disabled(10 SECONDS)

#undef TURRET_STUN
#undef TURRET_LETHAL
Expand Down
8 changes: 8 additions & 0 deletions code/game/objects/items/devices/radio/radio.dm
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,21 @@
slapcraft_recipes = list(/datum/crafting_recipe/improv_explosive)\
)

RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

/obj/item/radio/Destroy()
remove_radio_all(src) //Just to be sure
QDEL_NULL(wires)
if(istype(keyslot))
QDEL_NULL(keyslot)
return ..()

/obj/item/radio/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(broadcasting) //no broadcasting but it can still be used to send radio messages.
set_broadcasting(FALSE)
return COMSIG_SABOTEUR_SUCCESS

/obj/item/radio/proc/set_frequency(new_frequency)
SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args)
remove_radio(src, frequency)
Expand Down
9 changes: 9 additions & 0 deletions code/game/objects/items/melee/baton.dm
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@
else
cell = new preload_cell_type(src)
RegisterSignal(src, COMSIG_ATOM_ATTACKBY, PROC_REF(convert))
RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))
update_appearance()

/obj/item/melee/baton/security/get_cell()
Expand Down Expand Up @@ -488,6 +489,14 @@
qdel(item)
qdel(src)

/obj/item/melee/baton/security/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(!active)
return
toggle_light()
active = FALSE
update_appearance()
return COMSIG_SABOTEUR_SUCCESS
/obj/item/melee/baton/security/Exited(atom/movable/mov_content)
. = ..()
if(mov_content == cell)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/cargo/markets/market_items/weapons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

/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."
desc = "A self-recharging, compact pistol that disrupts lights, cameras, APCs, turrets and more, if only temporarily. Also usable in melee."
item = /obj/item/gun/energy/recharge/fisher

price_min = CARGO_CRATE_VALUE * 2
Expand Down
13 changes: 10 additions & 3 deletions code/modules/clothing/head/hardhat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
/obj/item/clothing/head/utility/hardhat/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)

/obj/item/clothing/head/utility/hardhat/attack_self(mob/living/user)
toggle_helmet_light(user)
RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

/obj/item/clothing/head/utility/hardhat/proc/toggle_helmet_light(mob/living/user)
on = !on
Expand All @@ -62,6 +60,15 @@
/obj/item/clothing/head/utility/hardhat/proc/turn_off(mob/user)
set_light_on(FALSE)

/obj/item/clothing/head/utility/hardhat/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(on)
toggle_helmet_light()
return COMSIG_SABOTEUR_SUCCESS

/obj/item/clothing/head/utility/hardhat/attack_self(mob/living/user)
toggle_helmet_light(user)

/obj/item/clothing/head/utility/hardhat/orange
icon_state = "hardhat0_orange"
inhand_icon_state = null
Expand Down
19 changes: 16 additions & 3 deletions code/modules/clothing/spacesuits/plasmamen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
. = ..()
visor_toggling()
update_appearance()
RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

/obj/item/clothing/head/helmet/space/plasmaman/examine()
. = ..()
Expand Down Expand Up @@ -108,6 +109,11 @@
playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing
update_appearance()

/obj/item/clothing/head/helmet/space/plasmaman/update_icon_state()
. = ..()
icon_state = "[initial(icon_state)][helmet_on ? "-light":""]"
inhand_icon_state = icon_state

/obj/item/clothing/head/helmet/space/plasmaman/update_overlays()
. = ..()
. += visor_icon
Expand Down Expand Up @@ -139,6 +145,7 @@
hitting_clothing.forceMove(src)
update_appearance()

///By the by, helmets have the update_icon_updates_onmob element, so we don't have to call mob.update_worn_head()
/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(mutable_appearance/standing, isinhands)
. = ..()
if(!isinhands && smile)
Expand All @@ -161,9 +168,7 @@

/obj/item/clothing/head/helmet/space/plasmaman/attack_self(mob/user)
helmet_on = !helmet_on
icon_state = "[initial(icon_state)][helmet_on ? "-light":""]"
inhand_icon_state = icon_state
user.update_worn_head() //So the mob overlay updates
update_appearance()

if(helmet_on)
if(!up)
Expand All @@ -176,6 +181,14 @@

update_item_action_buttons()

/obj/item/clothing/head/helmet/space/plasmaman/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(!helmet_on)
return
helmet_on = FALSE
update_appearance()
return COMSIG_SABOTEUR_SUCCESS

/obj/item/clothing/head/helmet/space/plasmaman/attack_hand_secondary(mob/user)
..()
. = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@
if(judgement_criteria & JUDGE_EMAGGED || HAS_TRAIT(src, TRAIT_ALWAYS_WANTED))
return 10 //Everyone is a criminal!

var/threatcount = 0
var/threatcount = judgement_criteria & JUDGE_CHILLOUT ? -THREAT_ASSESS_DANGEROUS : 0

//Lasertag bullshit
if(lasercolor)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/silicon/robot/robot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@
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."))
balloon_alert(src, "headlamp off!")
return COMSIG_SABOTEUR_SUCCESS

/**
Expand Down
13 changes: 13 additions & 0 deletions code/modules/mob/living/simple_animal/bot/secbot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
)
AddElement(/datum/element/connect_loc, loc_connections)
AddComponent(/datum/component/security_vision, judgement_criteria = NONE, update_judgement_criteria = CALLBACK(src, PROC_REF(judgement_criteria)))
RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

/mob/living/simple_animal/bot/secbot/Destroy()
QDEL_NULL(weapon)
Expand All @@ -164,6 +165,16 @@
SSmove_manager.stop_looping(src)
last_found = world.time

/mob/living/simple_animal/bot/secbot/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(!(security_mode_flags & SECBOT_SABOTEUR_AFFECTED))
security_mode_flags |= SECBOT_SABOTEUR_AFFECTED
addtimer(CALLBACK(src, PROC_REF(remove_saboteur_effect)), disrupt_duration)
return COMSIG_SABOTEUR_SUCCESS

/mob/living/simple_animal/bot/secbot/proc/remove_saboteur_effect()
security_mode_flags &= ~SECBOT_SABOTEUR_AFFECTED

/mob/living/simple_animal/bot/secbot/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)//shocks only make him angry
if(base_speed < initial(base_speed) + 3)
base_speed += 3
Expand Down Expand Up @@ -232,6 +243,8 @@
final |= JUDGE_RECORDCHECK
if(security_mode_flags & SECBOT_CHECK_WEAPONS)
final |= JUDGE_WEAPONCHECK
if(security_mode_flags & SECBOT_SABOTEUR_AFFECTED)
final |= JUDGE_CHILLOUT
return final

/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
Expand Down
12 changes: 12 additions & 0 deletions code/modules/mod/modules/modules_general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@
/// Maximum range we can set.
var/max_range = 5

/obj/item/mod/module/flashlight/on_suit_activation()
RegisterSignal(mod.wearer, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))

/obj/item/mod/module/flashlight/on_suit_deactivation(deleting = FALSE)
UnregisterSignal(mod.wearer, COMSIG_HIT_BY_SABOTEUR)

/obj/item/mod/module/flashlight/on_activation()
. = ..()
if(!.)
Expand All @@ -392,6 +398,12 @@
set_light_flags(light_flags & ~LIGHT_ATTACHED)
set_light_on(active)

/obj/item/mod/module/flashlight/proc/on_saboteur(datum/source, disrupt_duration)
SIGNAL_HANDLER
if(active)
on_deactivation()
return COMSIG_SABOTEUR_SUCCESS

/obj/item/mod/module/flashlight/on_process(seconds_per_tick)
active_power_cost = base_power * light_range
return ..()
Expand Down
Loading

0 comments on commit 86b06e3

Please sign in to comment.