Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] adds portable radio jammer #1906

Merged
merged 1 commit into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,7 @@
#include "code\game\objects\items\devices\paint_sprayer.dm"
#include "code\game\objects\items\devices\personal_shield.dm"
#include "code\game\objects\items\devices\powersink.dm"
#include "code\game\objects\items\devices\radio_jammer.dm"
#include "code\game\objects\items\devices\slide_projector.dm"
#include "code\game\objects\items\devices\spy_bug.dm"
#include "code\game\objects\items\devices\suit_cooling.dm"
Expand Down
7 changes: 7 additions & 0 deletions code/datums/uplink/devices and tools.dm
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@
While in hacking mode, this device will grant full access to any airlock in 20 to 40 seconds. \
This device will be able to continuously reaccess the last 6 to 8 airlocks it was used on."

/datum/uplink_item/item/tools/radio_jammer
name = "Portable Radio Jammer"
item_cost = 24
path = /obj/item/device/radio_jammer
desc = "A pocket sized portable radio jammer that can intercept outgoing radio signals in a given distance. \
However, radios attempting to send outgoing transmissions will emit a faint buzzing noise. \
The jammer can be signaled remotely using assembly signalers."

/datum/uplink_item/item/tools/space_suit
name = "Voidsuit and Tactical Mask"
Expand Down
29 changes: 25 additions & 4 deletions code/game/objects/items/devices/radio/radio.dm
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,35 @@
return null

/obj/item/device/radio/talk_into(mob/living/M, message, channel, verb = "says", datum/language/speaking = null)
if(!on) return 0 // the device has to be on
// the device has to be on
if (!on)
return FALSE
// Fix for permacell radios, but kinda eh about actually fixing them.
if(!M || !message) return 0
if (!M || !message)
return FALSE

if(speaking && (speaking.flags & (NONVERBAL|SIGNLANG))) return 0
if (speaking && (speaking.flags & (NONVERBAL|SIGNLANG)))
return FALSE

if (!broadcasting)
var/list/headset_z_group = GetConnectedZlevels(get_z(src))
//needs to account for turfs
var/turf/self_turf = get_turf(src)
if (!self_turf)
return FALSE
var/self_x = self_turf.x
var/self_y = self_turf.y
for (var/obj/item/device/radio_jammer/jammer as anything in GLOB.radio_jammers)
var/turf/jammer_turf = get_turf(jammer)
if (!jammer_turf)
continue
var/dx = self_x - jammer_turf.x
var/dy = self_y - jammer_turf.y
if (dx*dx + dy*dy <= jammer.square_radius && (jammer_turf.z in headset_z_group))
to_chat(M,SPAN_WARNING("Instead of the familiar radio crackle, \the [src] emits a faint buzzing sound."))
playsound(loc, 'sound/effects/zzzt.ogg', 20, 0, -1)
return FALSE

// Sedation chemical effect should prevent radio use (Chloral and Soporific)
var/mob/living/carbon/C = M
if (istype(C))
Expand Down Expand Up @@ -559,7 +581,6 @@


/obj/item/device/radio/hear_talk(mob/M as mob, msg, verb = "says", datum/language/speaking = null)

if (broadcasting)
if(get_dist(src, M) <= canhear_range)
talk_into(M, msg,null,verb,speaking)
Expand Down
178 changes: 178 additions & 0 deletions code/game/objects/items/devices/radio_jammer.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
GLOBAL_LIST_EMPTY(radio_jammers)
//adjusted to last a while so it can last conversations
#define JAMMER_POWER_CONSUMPTION(tick_delay) ((max(0.75, range)**2 * tick_delay) / 30)

/obj/item/device/radio_jammer
name = "small remote"
desc = "A small remote control covered in a number of lights, with several antennae extending from the top."
icon = 'icons/obj/radio_jammer.dmi'
icon_state = "jammer"
w_class = ITEM_SIZE_SMALL
var/is_active = FALSE
var/range = 5
var/square_radius = 25
var/code = 23
var/frequency = 1413
var/obj/item/cell/bcell = /obj/item/cell/high

/obj/item/device/radio_jammer/Initialize()
. = ..()
if(ispath(bcell))
bcell = new bcell(src)
GLOB.listening_objects += src
set_frequency(frequency)

/obj/item/device/radio_jammer/Destroy()
GLOB.radio_jammers -= src
GLOB.listening_objects -= src
qdel(bcell)
return ..()

/obj/item/device/radio_jammer/Process(wait)
var/cost = JAMMER_POWER_CONSUMPTION(wait)
if (!bcell?.use(cost))
STOP_PROCESSING(SSobj, src)
GLOB.radio_jammers -=src
is_active = FALSE

/obj/item/device/radio_jammer/attack_self(mob/living/user)
ui_interact(user)

/obj/item/device/radio_jammer/get_cell()
return bcell

/obj/item/device/radio_jammer/emp_act(severity)
..()
if(bcell)
bcell.emp_act(severity)

/obj/item/device/radio_jammer/proc/toggle(mob/user)
if(is_active)
STOP_PROCESSING(SSobj, src)
to_chat(user,SPAN_WARNING("You flick a switch on \the [src], deactivating it."))
is_active = FALSE
GLOB.radio_jammers -= src
update_icon()
else
START_PROCESSING(SSobj, src)
to_chat(user,SPAN_WARNING("You flick a switch on \the [src], activating it."))
is_active = TRUE
GLOB.radio_jammers += src
update_icon()

/obj/item/device/radio_jammer/on_update_icon()
ClearOverlays()
if(bcell)
var/percent = bcell.percent()
switch(percent)
if(0 to 25)
AddOverlays("quarter")
if(25 to 50)
AddOverlays("half")
if(50 to 99)
AddOverlays("full")
else
AddOverlays("four_quarters")

if(is_active)
AddOverlays("on")
else
AddOverlays("off")

/obj/item/device/radio_jammer/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
radio_controller.add_object(src, frequency, RADIO_CHAT)

/obj/item/device/radio_jammer/receive_signal(datum/signal/signal)
if(signal?.encryption == code)
toggle()

/obj/item/device/radio_jammer/OnTopic(mob/user, list/href_list, state)
if (href_list["enable_jammer"])
toggle()
return TOPIC_REFRESH
if (href_list["disable_jammer"])
toggle()
return TOPIC_REFRESH
if(href_list["increase_range"])
range = min(range + 1, 10)
square_radius = range ** 2
return TOPIC_REFRESH
if(href_list["decrease_range"])
range = max(range - 1, 0)
square_radius = range ** 2
return TOPIC_REFRESH
if(href_list["set_code"])
var/adj = text2num(href_list["code"])
if(!adj)
code = input("Set radio activation code","Radio activation") as num
if (QDELETED(src) || CanUseTopic(user, state, href_list) == STATUS_INTERACTIVE)
return TOPIC_HANDLED
else
code += adj
code = clamp(code,1,100)
return TOPIC_REFRESH
if (href_list["set_frequency"])
var/adj = text2num(href_list["frequency"])
if(!adj)
var/temp = input("Set a four digit radio frequency without decimals","Radio activation") as num
set_frequency(sanitize_frequency(temp, RADIO_LOW_FREQ, RADIO_HIGH_FREQ))
if (QDELETED(src) || CanUseTopic(user, state, href_list) == STATUS_INTERACTIVE)
return TOPIC_HANDLED
return TOPIC_REFRESH

/obj/item/device/radio_jammer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
var/list/data = list(
"active" = is_active,
"current_charge" = bcell ? round(bcell.charge, 1) : 0,
"max_charge" = bcell ? bcell.maxcharge : 0,
"range" = range,
"max_range" = 10,
"frequency" = format_frequency(frequency),
"code" = code,
"total_cost" = "[ceil(JAMMER_POWER_CONSUMPTION(10))]"
)
ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "radio_jammer.tmpl", "Portable Radio Jammer", 300, 640)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(TRUE)

/obj/item/device/radio_jammer/use_tool(obj/item/tool, mob/living/user, list/click_params)
if (isCrowbar(tool))
if(is_active)
STOP_PROCESSING(SSobj, src)
is_active = FALSE
GLOB.radio_jammers -= src
if (!bcell)
USE_FEEDBACK_FAILURE("\The [src] has no cell to remove.")
return TRUE
user.put_in_hands(bcell)
user.visible_message(
SPAN_NOTICE("\The [user] removes \a [bcell] from \a [src] with \a [tool]."),
SPAN_NOTICE("You remove \the [bcell] from \the [src] with \the [tool].")
)
bcell = null
update_icon()
return TRUE
if (istype(tool, /obj/item/cell))
if (bcell)
USE_FEEDBACK_FAILURE("\The [src] already has \a [bcell] installed.")
return TRUE
if (!user.unEquip(tool, src))
FEEDBACK_UNEQUIP_FAILURE(user, tool)
return TRUE
bcell = tool
user.visible_message(
SPAN_NOTICE("\The [user] installs \a [tool] into \a [src]."),
SPAN_NOTICE("you install \the [tool] into \the [src].")
)
update_icon()
return TRUE

return ..()


#undef JAMMER_POWER_CONSUMPTION
Binary file added icons/obj/radio_jammer.dmi
Binary file not shown.
53 changes: 53 additions & 0 deletions nano/templates/radio_jammer.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<div class="block">
<h3>Status</h3>
<div class="item">
<span class='average'>{{:data.active ? "Enabled" : "Disabled"}}</span>
</div>
<div class="item">
{{:helper.link('Enable' , null, {'enable_jammer' : 1}, data.active ? "selected" : null, null)}}
{{:helper.link('Disable' , null, {'disable_jammer' : 1}, data.active ? null : "selected", null)}}
</div>
</div>

<div class="block">
<h3>Range</h3>
<div class="item">
<span class='average'>{{:data.range}}</span> meter(s)
</div>
<div class="item">
{{:helper.link('Decrease' , 'minusthick', {'decrease_range' : 1}, data.range <= 0 ? "disabled" : null, null)}}
{{:helper.link('Increase' , 'plusthick', {'increase_range' : 1}, data.range >= 10 ? "disabled" : null, null)}}
</div>
</div>

<div class="block">
<h3>Remote Activation</h3>
<div class="item">
<span class='average'> {{:helper.link( data.frequency, null, { 'set_frequency': 1})}}</span>
</div>
<div class="item">
<span class='average'> {{:helper.link( data.code, null, { 'set_code': 1})}}</span>
</div>
</div>

<div class="block">
<div class="item">
<div class="itemLabel">
Charge
</div>
<div class="itemContent">
{{:data.current_charge}}/{{:data.max_charge}} W
</div>
</div>
<div class="item">
{{:helper.displayBar(data.current_charge/data.max_charge, 0, 1, 'average')}}
</div>
<div class="item">
<div class="itemLabel">
Energy Consumption
</div>
<div class="itemContent">
~{{:data.total_cost}} W
</div>
</div>
</div>
Loading