mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-02-07 23:09:28 +00:00
About The Pull Request Fixes #69043 assemblies not providing a UI when part of a one-tank bomb. (This doesn't count voice analyzers, which don't have UI) Fixes #68139 assemblies triggering themselves (and often turning themselves off). Fixes timers ceasing to loop if the timer is set to less than the 3-second anti-spam threshold. #69335, #68733 signalers occasionally runtiming due to qdel'd weak reference datums. Already addressed by another PR Proximity sensors and mousetraps work on more wire datums, but proximity sensors are still buggy. Igniter-sensor pairs can detonate fuel tanks properly, including plumbed fuel tanks. Fuel tank explosions scale with how much fuel is in them; this is slightly nerfed from existing values. The fuel tank detonation code has been made generic, but other reagent dispensers have rigging turned off. If turned on with a varedit, you can rig and detonate water and other reagent tanks. Reagent tanks can theoretically both explode and spread reagents if it should happen to contain both welding fuel and other stuff. I have not actually tested this part of it, but I have detonated both water tanks and fuel tanks and each works correctly. In making mousetraps work on wire datums, I had the opportunity to make it so that you could place a mousetrap in a door's wire and it would activate when someone passed through the door (useful to bolt a door open when someone authorized goes through, for example). This is a fun mechanic but does not make sense for a simple mousetrap to be so powerful, so it is disabled. Ideally, you could put the laser tripwire in a door's wires to do the same thing, but that would be a massive rework. Mousetraps still work in on-found mode for all wire datums, and will work on items with wiring datums (like C4 and chem bombs) when stepped on. The signaler runtimes were a result of weak_ref datums being deleted, and the communications system not handling that. It's probably not ideal to run null checks in the post_signal loop, but I am not going to worry about it. Many of the assemblies were not properly registering when the assembly holder was attached to an item. This was most important for proximity sensors, but that also has other problems that I haven't been able to track down. The problem with UI not appearing was a result of the transition to TGUI however long ago that was; the proc that assures TGUI that you have the right item needed to be aware of one-tank bombs and similar, or else when you pass along an interact request it says "but you can't see it" and ignores you. Why It's Good For The Game Bugfixen. The thing with the reagent dispensers only got this complicated when I realized that the plumbed fuel tank variant wasn't a subtype and therefore couldn't be rigged. And then... I basically just scaled it because the flat scale no matter the contents of the tank offended me. You could wrench open tanks, drain them entirely of fuel, rig them, and they would still go off like a pile of dynamite. I used to have code in my branch that turned chem bombs into variants depending on the trigger, with mousetraps being mines for example. That's honestly the main reason I went out of my way to make mousetraps work better as assemblies. I could wish it were better supported, but mousetraps on grenade wiring will have to do for now. Changelog cl balance: Welding fuel tank explosions have been scaled slightly down and require the fuel tanks to actually be full of welding fuel fix: You can detonate welding fuel tanks with an igniter-sensor assembly fix: You can reach your one-tank bomb's assembly controls by activating the item in your hand. fix: Certain assemblies should no longer turn themselves off. fix: Clumsy fools handling a mousetrap-based multi-part assembly may set it off by accident /cl
214 lines
7.5 KiB
Plaintext
214 lines
7.5 KiB
Plaintext
/*
|
|
* HOW IT WORKS
|
|
*
|
|
*The SSradio is a global object maintaining all radio transmissions, think about it as about "ether".
|
|
*Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
|
|
*procs:
|
|
*
|
|
* add_object(obj/device as obj, new_frequency as num, filter as text|null = null)
|
|
* Adds listening object.
|
|
* parameters:
|
|
* device - device receiving signals, must have proc receive_signal (see description below).
|
|
* one device may listen several frequencies, but not same frequency twice.
|
|
* new_frequency - see possibly frequencies below;
|
|
* filter - thing for optimization. Optional, but recommended.
|
|
* All filters should be consolidated in this file, see defines later.
|
|
* Device without listening filter will receive all signals (on specified frequency).
|
|
* Device with filter will receive any signals sent without filter.
|
|
* Device with filter will not receive any signals sent with different filter.
|
|
* returns:
|
|
* Reference to frequency object.
|
|
*
|
|
* remove_object (obj/device, old_frequency)
|
|
* Obliviously, after calling this proc, device will not receive any signals on old_frequency.
|
|
* Other frequencies will left unaffected.
|
|
*
|
|
*return_frequency(var/frequency as num)
|
|
* returns:
|
|
* Reference to frequency object. Use it if you need to send and do not need to listen.
|
|
*
|
|
*radio_frequency is a global object maintaining list of devices that listening specific frequency.
|
|
*procs:
|
|
*
|
|
* post_signal(obj/source as obj|null, datum/signal/signal, filter as text|null = null, range as num|null = null)
|
|
* Sends signal to all devices that wants such signal.
|
|
* parameters:
|
|
* source - object, emitted signal. Usually, devices will not receive their own signals.
|
|
* signal - see description below.
|
|
* filter - described above.
|
|
* range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels.
|
|
*
|
|
* obj/proc/receive_signal(datum/signal/signal, receive_method as num, receive_param)
|
|
* Handler from received signals. By default does nothing. Define your own for your object.
|
|
* Avoid of sending signals directly from this proc, use spawn(0). Do not use sleep() here please.
|
|
* parameters:
|
|
* signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return!
|
|
* receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO.
|
|
* TRANSMISSION_WIRE is currently unused.
|
|
* receive_param - for TRANSMISSION_RADIO here comes frequency.
|
|
*
|
|
* datum/signal
|
|
* vars:
|
|
* source
|
|
* an object that emitted signal. Used for debug and bearing.
|
|
* data
|
|
* list with transmitting data. Usual use pattern:
|
|
* data["msg"] = "hello world"
|
|
* encryption
|
|
* Some number symbolizing "encryption key".
|
|
* Note that game actually do not use any cryptography here.
|
|
* If receiving object don't know right key, it must ignore encrypted signal in its receive_signal.
|
|
*
|
|
*/
|
|
/* the radio controller is a confusing piece of shit and didnt work
|
|
so i made radios not use the radio controller.
|
|
*/
|
|
GLOBAL_LIST_EMPTY(all_radios)
|
|
|
|
/proc/add_radio(obj/item/radio, freq)
|
|
if(!freq || !radio)
|
|
return
|
|
if(!GLOB.all_radios["[freq]"])
|
|
GLOB.all_radios["[freq]"] = list(radio)
|
|
return freq
|
|
|
|
GLOB.all_radios["[freq]"] |= radio
|
|
return freq
|
|
|
|
/proc/remove_radio(obj/item/radio, freq)
|
|
if(!freq || !radio)
|
|
return
|
|
if(!GLOB.all_radios["[freq]"])
|
|
return
|
|
|
|
GLOB.all_radios["[freq]"] -= radio
|
|
|
|
/proc/remove_radio_all(obj/item/radio)
|
|
for(var/freq in GLOB.all_radios)
|
|
GLOB.all_radios["[freq]"] -= radio
|
|
|
|
// For information on what objects or departments use what frequencies,
|
|
// see __DEFINES/radio.dm. Mappers may also select additional frequencies for
|
|
// use in maps, such as in intercoms.
|
|
|
|
GLOBAL_LIST_INIT(radiochannels, list(
|
|
RADIO_CHANNEL_COMMON = FREQ_COMMON,
|
|
RADIO_CHANNEL_SCIENCE = FREQ_SCIENCE,
|
|
RADIO_CHANNEL_COMMAND = FREQ_COMMAND,
|
|
RADIO_CHANNEL_MEDICAL = FREQ_MEDICAL,
|
|
RADIO_CHANNEL_ENGINEERING = FREQ_ENGINEERING,
|
|
RADIO_CHANNEL_SECURITY = FREQ_SECURITY,
|
|
RADIO_CHANNEL_CENTCOM = FREQ_CENTCOM,
|
|
RADIO_CHANNEL_SYNDICATE = FREQ_SYNDICATE,
|
|
RADIO_CHANNEL_SUPPLY = FREQ_SUPPLY,
|
|
RADIO_CHANNEL_SERVICE = FREQ_SERVICE,
|
|
RADIO_CHANNEL_AI_PRIVATE = FREQ_AI_PRIVATE,
|
|
RADIO_CHANNEL_CTF_RED = FREQ_CTF_RED,
|
|
RADIO_CHANNEL_CTF_BLUE = FREQ_CTF_BLUE,
|
|
RADIO_CHANNEL_CTF_GREEN = FREQ_CTF_GREEN,
|
|
RADIO_CHANNEL_CTF_YELLOW = FREQ_CTF_YELLOW
|
|
))
|
|
|
|
GLOBAL_LIST_INIT(reverseradiochannels, list(
|
|
"[FREQ_COMMON]" = RADIO_CHANNEL_COMMON,
|
|
"[FREQ_SCIENCE]" = RADIO_CHANNEL_SCIENCE,
|
|
"[FREQ_COMMAND]" = RADIO_CHANNEL_COMMAND,
|
|
"[FREQ_MEDICAL]" = RADIO_CHANNEL_MEDICAL,
|
|
"[FREQ_ENGINEERING]" = RADIO_CHANNEL_ENGINEERING,
|
|
"[FREQ_SECURITY]" = RADIO_CHANNEL_SECURITY,
|
|
"[FREQ_CENTCOM]" = RADIO_CHANNEL_CENTCOM,
|
|
"[FREQ_SYNDICATE]" = RADIO_CHANNEL_SYNDICATE,
|
|
"[FREQ_SUPPLY]" = RADIO_CHANNEL_SUPPLY,
|
|
"[FREQ_SERVICE]" = RADIO_CHANNEL_SERVICE,
|
|
"[FREQ_AI_PRIVATE]" = RADIO_CHANNEL_AI_PRIVATE,
|
|
"[FREQ_CTF_RED]" = RADIO_CHANNEL_CTF_RED,
|
|
"[FREQ_CTF_BLUE]" = RADIO_CHANNEL_CTF_BLUE,
|
|
"[FREQ_CTF_GREEN]" = RADIO_CHANNEL_CTF_GREEN,
|
|
"[FREQ_CTF_YELLOW]" = RADIO_CHANNEL_CTF_YELLOW
|
|
))
|
|
|
|
/datum/radio_frequency
|
|
var/frequency
|
|
/// List of filters -> list of devices
|
|
var/list/list/datum/weakref/devices = list()
|
|
|
|
/datum/radio_frequency/New(freq)
|
|
frequency = freq
|
|
|
|
//If range > 0, only post to devices on the same z_level and within range
|
|
//Use range = -1, to restrain to the same z_level without limiting range
|
|
/datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, filter = null as text|null, range = null as num|null)
|
|
// Ensure the signal's data is fully filled
|
|
signal.source = source
|
|
signal.frequency = frequency
|
|
|
|
//Apply filter to the signal. If none supply, broadcast to every devices
|
|
//_default channel is always checked
|
|
var/list/filter_list
|
|
|
|
if(filter)
|
|
filter_list = list(filter,"_default")
|
|
else
|
|
filter_list = devices
|
|
|
|
//If checking range, find the source turf
|
|
var/turf/start_point
|
|
if(range)
|
|
start_point = get_turf(source)
|
|
if(!start_point)
|
|
return
|
|
|
|
//Send the data
|
|
for(var/current_filter in filter_list)
|
|
for(var/datum/weakref/device_ref as anything in devices[current_filter])
|
|
var/obj/device = device_ref.resolve()
|
|
if(!device)
|
|
devices[current_filter] -= device_ref
|
|
continue
|
|
if(device == source)
|
|
continue
|
|
if(range)
|
|
var/turf/end_point = get_turf(device)
|
|
if(!end_point)
|
|
continue
|
|
if(start_point.z != end_point.z || (range > 0 && get_dist(start_point, end_point) > range))
|
|
continue
|
|
device.receive_signal(signal)
|
|
CHECK_TICK
|
|
|
|
/datum/radio_frequency/proc/add_listener(obj/device, filter as text|null)
|
|
if (!filter)
|
|
filter = "_default"
|
|
|
|
var/datum/weakref/new_listener = WEAKREF(device)
|
|
if(isnull(new_listener))
|
|
return stack_trace("null, non-datum, or qdeleted device")
|
|
var/list/devices_line = devices[filter]
|
|
if(!devices_line)
|
|
devices[filter] = devices_line = list()
|
|
devices_line += new_listener
|
|
|
|
/datum/radio_frequency/proc/remove_listener(obj/device)
|
|
for(var/devices_filter in devices)
|
|
var/list/devices_line = devices[devices_filter]
|
|
if(!devices_line)
|
|
devices -= devices_filter
|
|
devices_line -= WEAKREF(device)
|
|
if(!devices_line.len)
|
|
devices -= devices_filter
|
|
|
|
/obj/proc/receive_signal(datum/signal/signal)
|
|
return
|
|
|
|
/datum/signal
|
|
var/obj/source
|
|
var/frequency = 0
|
|
var/transmission_method
|
|
var/list/data
|
|
var/logging_data
|
|
|
|
/datum/signal/New(data, transmission_method = TRANSMISSION_RADIO, logging_data = null)
|
|
src.data = data || list()
|
|
src.transmission_method = transmission_method
|
|
src.logging_data = logging_data
|