Merge pull request #9300 from Spookerton/spkrtn/del/remove-tcomms-scripting

remove tcomms scripting
This commit is contained in:
Atermonera
2024-01-30 16:23:24 -08:00
committed by GitHub
75 changed files with 1887 additions and 5600 deletions

View File

@@ -2,7 +2,7 @@
Contains helper procs for airflow, handled in /connection_group.
*/
/mob/var/tmp/last_airflow_stun = 0
/mob/var/last_airflow_stun = 0
/mob/proc/airflow_stun()
if(stat == 2)
return 0
@@ -64,10 +64,10 @@ Contains helper procs for airflow, handled in /connection_group.
else
if(n < vsc.airflow_dense_pressure) return 0
/atom/movable/var/tmp/turf/airflow_dest
/atom/movable/var/tmp/airflow_speed = 0
/atom/movable/var/tmp/airflow_time = 0
/atom/movable/var/tmp/last_airflow = 0
/atom/movable/var/turf/airflow_dest
/atom/movable/var/airflow_speed = 0
/atom/movable/var/airflow_time = 0
/atom/movable/var/last_airflow = 0
/atom/movable/proc/AirflowCanMove(n)
return 1

View File

@@ -34,7 +34,7 @@ Macros:
// macro-ized to cut down on proc calls
#define check(c) (c && c.valid())
/turf/var/tmp/connection_manager/connections
/turf/var/connection_manager/connections
/connection_manager/var/connection/N
/connection_manager/var/connection/S

View File

@@ -9,7 +9,7 @@ var/global/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark")
/connection_edge/var/dbg_out = 0
/turf/var/tmp/dbg_img
/turf/var/dbg_img
/turf/proc/dbg(image/img, d = 0)
if(d > 0) img.dir = d
cut_overlay(dbg_img)
@@ -17,4 +17,4 @@ var/global/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark")
dbg_img = img
/proc/soft_assert(thing,fail)
if(!thing) message_admins(fail)
if(!thing) message_admins(fail)

View File

@@ -6,10 +6,10 @@ SUBSYSTEM_DEF(ai)
wait = 2 SECONDS
/// The list of AI datums to be processed.
var/static/tmp/list/queue = list()
var/static/list/queue = list()
/// The list of AI datums currently being processed.
var/static/tmp/list/current = list()
var/static/list/current = list()
/datum/controller/subsystem/ai/stat_entry(msg_prefix)

View File

@@ -6,10 +6,10 @@ SUBSYSTEM_DEF(aifast)
wait = 0.25 SECONDS
/// The list of AI datums to be processed.
var/static/tmp/list/queue = list()
var/static/list/queue = list()
/// The list of AI datums currently being processed.
var/static/tmp/list/current = list()
var/static/list/current = list()
/datum/controller/subsystem/aifast/stat_entry(msg_prefix)

View File

@@ -101,11 +101,11 @@ SUBSYSTEM_DEF(airflow)
#undef CLEAR_OBJECT
/atom/movable
var/tmp/airflow_xo
var/tmp/airflow_yo
var/tmp/airflow_od
var/tmp/airflow_process_delay
var/tmp/airflow_skip_speedcheck
var/airflow_xo
var/airflow_yo
var/airflow_od
var/airflow_process_delay
var/airflow_skip_speedcheck
/atom/movable/proc/prepare_airflow(n)
if (!airflow_dest || airflow_speed < 0 || last_airflow > world.time - vsc.airflow_delay)

View File

@@ -5,13 +5,13 @@ SUBSYSTEM_DEF(alarm)
init_order = INIT_ORDER_ALARM
/// The list of alarm handlers this subsystem processes
var/static/tmp/list/datum/alarm_handler/handlers
var/static/list/datum/alarm_handler/handlers
/// The list of alarm handlers currently being processed
var/static/tmp/list/current = list()
var/static/list/current = list()
/// The list of active alarms
var/static/tmp/list/active = list()
var/static/list/active = list()
/datum/controller/subsystem/alarm/Initialize(timeofday)

View File

@@ -2,7 +2,7 @@ SUBSYSTEM_DEF(events)
name = "Events (Legacy)"
wait = 2 SECONDS
var/tmp/list/currentrun = null
var/list/currentrun = null
var/list/datum/event/active_events = list()
var/list/datum/event/finished_events = list()

View File

@@ -2,7 +2,7 @@ SUBSYSTEM_DEF(inactivity)
name = "Inactivity"
wait = 60 SECONDS
flags = SS_NO_INIT | SS_BACKGROUND
var/tmp/list/client_list
var/list/client_list
var/number_kicked = 0
/datum/controller/subsystem/inactivity/fire(resumed, no_mc_tick)

View File

@@ -6,16 +6,16 @@ SUBSYSTEM_DEF(overlays)
init_order = INIT_ORDER_OVERLAY
/// The queue of atoms that need overlay updates.
var/static/tmp/list/queue = list()
var/static/list/queue = list()
/// A list([icon] = list([state] = [appearance], ...), ...) cache of appearances.
var/static/tmp/list/state_cache = list()
var/static/list/state_cache = list()
/// A list([icon] = [appearance], ...) cache of appearances.
var/static/tmp/list/icon_cache = list()
var/static/list/icon_cache = list()
/// The number of appearances currently cached.
var/static/tmp/cache_size = 0
var/static/cache_size = 0
/datum/controller/subsystem/overlays/Recover()

View File

@@ -7,9 +7,9 @@ SUBSYSTEM_DEF(radiation)
var/list/sources_assoc = list() // Sources indexed by turf for de-duplication.
var/list/resistance_cache = list() // Cache of turf's radiation resistance.
var/tmp/list/current_sources = list()
var/tmp/list/current_res_cache = list()
var/tmp/list/listeners = list()
var/list/current_sources = list()
var/list/current_res_cache = list()
var/list/listeners = list()
/datum/controller/subsystem/radiation/fire(resumed, no_mc_tick)
if (!resumed)

View File

@@ -33,7 +33,7 @@ SUBSYSTEM_DEF(shuttles)
var/list/sectors_to_initialize // Used to find all sector objects at the appropriate time.
var/block_init_queue = TRUE // Block initialization of new shuttles/sectors
var/tmp/list/current_run // Shuttles remaining to process this fire() tick
var/list/current_run // Shuttles remaining to process this fire() tick
/datum/controller/subsystem/shuttles/OnNew()
global.shuttle_controller = src // TODO - Remove this! Change everything to point at SSshuttles instead

View File

@@ -6,16 +6,16 @@ SUBSYSTEM_DEF(tgui)
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
/// The current queue of UIs to be processed
var/static/tmp/list/current = list()
var/static/list/current = list()
/// The whole set of open UIs
var/static/tmp/list/open_uis = list()
var/static/list/open_uis = list()
/// The whole set of open UIs as ("\ref[owner]" = /datum/tgui?)
var/static/tmp/list/open_uis_by_src = list()
var/static/list/open_uis_by_src = list()
/// The template document used by all tgui instances
var/static/tmp/base_html
var/static/base_html
/datum/controller/subsystem/tgui/Recover()
@@ -346,4 +346,4 @@ SUBSYSTEM_DEF(tgui)
target.tgui_open_uis.Add(ui)
// Clear the old list.
source.tgui_open_uis.Cut()
return TRUE
return TRUE

View File

@@ -14,8 +14,8 @@
var/datum_flags = EMPTY_BITFIELD
#ifdef TESTING
var/tmp/running_find_references
var/tmp/last_find_references = 0
var/running_find_references
var/last_find_references = 0
#endif
// Default implementation of clean-up code.

View File

@@ -1,91 +0,0 @@
#define TELECOMMS_RECEPTION_NONE 0
#define TELECOMMS_RECEPTION_SENDER 1
#define TELECOMMS_RECEPTION_RECEIVER 2
#define TELECOMMS_RECEPTION_BOTH 3
/proc/register_radio(source, old_frequency, new_frequency, radio_filter)
if(old_frequency)
radio_controller.remove_object(source, old_frequency)
if(new_frequency)
return radio_controller.add_object(source, new_frequency, radio_filter)
/proc/unregister_radio(source, frequency)
if(radio_controller)
radio_controller.remove_object(source, frequency)
/proc/get_frequency_name(var/display_freq)
var/freq_text
// the name of the channel
if(display_freq in ANTAG_FREQS)
freq_text = "#unkn"
else
for(var/channel in radiochannels)
if(radiochannels[channel] == display_freq)
freq_text = channel
break
// --- If the frequency has not been assigned a name, just use the frequency as the name ---
if(!freq_text)
freq_text = format_frequency(display_freq)
return freq_text
/datum/reception
var/obj/machinery/message_server/message_server = null
var/telecomms_reception = TELECOMMS_RECEPTION_NONE
var/message = ""
/datum/receptions
var/obj/machinery/message_server/message_server = null
var/sender_reception = TELECOMMS_RECEPTION_NONE
var/list/receiver_reception = new
/proc/get_message_server()
if(message_servers)
for (var/obj/machinery/message_server/MS in message_servers)
if(MS.active)
return MS
return null
/proc/check_signal(var/datum/signal/signal)
return signal && signal.data["done"]
/proc/get_sender_reception(var/atom/sender, var/datum/signal/signal)
return check_signal(signal) ? TELECOMMS_RECEPTION_SENDER : TELECOMMS_RECEPTION_NONE
/proc/get_receiver_reception(var/receiver, var/datum/signal/signal)
if(receiver && check_signal(signal))
var/turf/pos = get_turf(receiver)
if(pos && (pos.z in signal.data["level"]))
return TELECOMMS_RECEPTION_RECEIVER
return TELECOMMS_RECEPTION_NONE
/proc/get_reception(var/atom/sender, var/receiver, var/message = "", var/do_sleep = 1)
var/datum/reception/reception = new
// check if telecomms I/O route 1459 is stable
reception.message_server = get_message_server()
var/datum/signal/signal = sender.telecomms_process(do_sleep) // Be aware that this proc calls sleep, to simulate transmition delays
reception.telecomms_reception |= get_sender_reception(sender, signal)
reception.telecomms_reception |= get_receiver_reception(receiver, signal)
reception.message = signal && signal.data["compression"] > 0 ? Gibberish(message, signal.data["compression"] + 50) : message
return reception
/proc/get_receptions(var/atom/sender, var/list/atom/receivers, var/do_sleep = 1)
var/datum/receptions/receptions = new
receptions.message_server = get_message_server()
var/datum/signal/signal
if(sender)
signal = sender.telecomms_process(do_sleep)
receptions.sender_reception = get_sender_reception(sender, signal)
for(var/atom/receiver in receivers)
if(!signal)
signal = receiver.telecomms_process()
receptions.receiver_reception[receiver] = get_receiver_reception(receiver, signal)
return receptions

View File

@@ -540,3 +540,16 @@ Class Procs:
// Stub for above proc. Implemented on exosuit fabricators and prosthetics fabricators.
/obj/machinery/proc/refresh_queue()
return
/obj/machinery/proc/get_multitool(mob/user)
var/obj/item/multitool/P = null
if (!issilicon(user) && istype(user.get_active_hand(), /obj/item/multitool))
P = user.get_active_hand()
else if (isAI(user))
var/mob/living/silicon/ai/U = user
P = U.aiMulti
else if (isrobot(user) && in_range(user, src))
if (istype(user.get_active_hand(), /obj/item/multitool))
P = user.get_active_hand()
return P

View File

@@ -103,22 +103,6 @@
NEWSCASTER.newsAlert(annoncement)
NEWSCASTER.update_icon()
// var/list/receiving_pdas = new
// for (var/obj/item/pda/P in PDAs)
// if(!P.owner)
// continue
// if(P.toff)
// continue
// receiving_pdas += P
// spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere
// var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception
// for(var/obj/item/pda/PDA in receiving_pdas)
// if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER))
// continue
// PDA.new_news(annoncement)
var/global/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list.

View File

@@ -0,0 +1,122 @@
/* All In One Telecomms Machine
* Basically just an empty shell for receiving and broadcasting radio messages. Not
* very flexible, but it gets the job done. Listens on *every* zlevel unless subtyped.
*/
/obj/machinery/telecomms/allinone
name = "Telecommunications Mainframe"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "allinone"
desc = "A compact machine used for portable subspace telecommuniations processing."
density = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 20
anchored = TRUE
machinetype = 6
produces_heat = FALSE
var/list/linked_radios_weakrefs = list()
var/intercept = FALSE // if nonzero, broadcasts all messages to syndicate channel
var/overmap_range = 0
/obj/machinery/telecomms/allinone/proc/link_radio(obj/item/radio/radio)
if (!istype(radio))
return
linked_radios_weakrefs |= weakref(radio)
/obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal)
if (!on)
return
if (!using_map.use_overmap)
return
if (signal.data["done"])
return
var/map_levels = using_map.get_map_levels(z, TRUE, overmap_range)
if (signal.transmission_method != TRANSMISSION_BLUESPACE)
var/list/signal_levels = list()
signal_levels += signal.data["level"]
var/list/overlap = map_levels & signal_levels
if (!length(overlap))
return
if(!is_freq_listening(signal))
return
signal.data["done"] = TRUE
signal.data["compression"] = 0
var/datum/signal/original = signal.data["original"]
if (original)
original.data["done"] = TRUE
signal.data["level"] = map_levels
if (signal.data["slow"] > 0)
sleep(signal.data["slow"])
var/datum/radio_frequency/connection = signal.data["connection"]
var/list/forced_radios
for (var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/radio = wr.resolve()
if (istype(radio))
LAZYDISTINCTADD(forced_radios, radio)
Broadcast_Message(
signal.data["connection"],
signal.data["mob"],
signal.data["vmask"],
signal.data["vmessage"],
signal.data["radio"],
signal.data["message"],
signal.data["name"],
signal.data["job"],
signal.data["realname"],
signal.data["vname"],
DATA_NORMAL,
signal.data["compression"],
signal.data["level"],
connection.frequency,
signal.data["verb"],
signal.data["language"],
forced_radios
)
/obj/machinery/telecomms/allinone/antag
use_power = USE_POWER_OFF
idle_power_usage = 0
/obj/machinery/telecomms/allinone/antag/receive_signal(datum/signal/signal)
if (!on)
return
if (!is_freq_listening(signal))
return
signal.data["done"] = TRUE
signal.data["compression"] = 0
var/datum/signal/original = signal.data["original"]
if (original)
original.data["done"] = TRUE
signal.data["level"] = using_map.contact_levels.Copy()
if (signal.data["slow"] > 0)
sleep(signal.data["slow"])
var/datum/radio_frequency/connection = signal.data["connection"]
var/list/forced_radios
for (var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/radio = wr.resolve()
if (istype(radio))
LAZYDISTINCTADD(forced_radios, radio)
if (connection.frequency in ANTAG_FREQS)
Broadcast_Message(
signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_NORMAL,
signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], forced_radios
)
else if(intercept)
Broadcast_Message(
signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_ANTAG,
signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], forced_radios
)

View File

@@ -1,748 +1,112 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
/*
The broadcaster sends processed messages to all radio devices in the game. They
do not have to be headsets; intercoms and station-bounced radios suffice.
They receive their message from a server after the message has been logged.
/* Telecomms Broadcaster
* The broadcaster sends processed messages to all radio devices in the game. They
* do not have to be headsets; intercoms and station-bounced radios suffice. They
* receive their message from a server after the message has been logged.
*/
var/global/list/recentmessages = list() // global list of recent messages broadcasted : used to circumvent massive radio spam
var/global/message_delay = 0 // To make sure restarting the recentmessages list is kept in sync
/obj/machinery/telecomms/broadcaster
name = "Subspace Broadcaster"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "broadcaster"
desc = "A dish-shaped machine used to broadcast processed subspace signals."
density = 1
anchored = 1
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 25
machinetype = 5
produces_heat = 0
produces_heat = FALSE
delay = 7
circuit = /obj/item/circuitboard/telecomms/broadcaster
//Vars only used if you're using the overmap
interact_offline = TRUE
var/list/linked_radios_weakrefs = list()
var/overmap_range = 0
var/overmap_range_min = 0
var/overmap_range_max = 5
//Linked bluespace radios
var/list/linked_radios_weakrefs = list()
/obj/machinery/telecomms/broadcaster/proc/link_radio(var/obj/item/radio/R)
if(!istype(R))
return
linked_radios_weakrefs |= weakref(R)
/obj/machinery/telecomms/broadcaster/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
// Don't broadcast rejected signals
if(signal.data["reject"])
return
if(signal.data["message"])
// Prevents massive radio spam
signal.data["done"] = 1 // mark the signal as being broadcasted
// Search for the original signal and mark it as done as well
var/datum/signal/original = signal.data["original"]
if(original)
original.data["done"] = 1
original.data["compression"] = signal.data["compression"]
original.data["level"] = signal.data["level"]
var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]"
if(signal_message in recentmessages)
return
recentmessages.Add(signal_message)
if(signal.data["slow"] > 0)
sleep(signal.data["slow"]) // simulate the network lag if necessary
signal.data["level"] |= using_map.get_map_levels(listening_level, TRUE, overmap_range)
var/list/forced_radios
for(var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/R = wr.resolve()
if(istype(R))
LAZYDISTINCTADD(forced_radios, R)
/** #### - Normal Broadcast - #### **/
if(signal.data["type"] == SIGNAL_NORMAL)
/* ###### Broadcast a message using signal.data ###### */
Broadcast_Message(signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_NORMAL,
signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], forced_radios)
/** #### - Simple Broadcast - #### **/
if(signal.data["type"] == SIGNAL_SIMPLE)
/* ###### Broadcast a message using signal.data ###### */
Broadcast_SimpleMessage(signal.data["name"], signal.frequency,
signal.data["message"], DATA_NORMAL, null,
signal.data["compression"], listening_level, forced_radios)
/** #### - Artificial Broadcast - #### **/
// (Imitates a mob)
if(signal.data["type"] == SIGNAL_FAKE)
/* ###### Broadcast a message using signal.data ###### */
// Parameter "data" as DATA_FAKE: AI can't track this person/mob
Broadcast_Message(signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_FAKE,
signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], forced_radios)
if(!message_delay)
message_delay = 1
spawn(10)
message_delay = 0
recentmessages = list()
/* --- Do a snazzy animation! --- */
flick("broadcaster_send", src)
/obj/machinery/telecomms/broadcaster/Destroy()
// In case message_delay is left on 1, otherwise it won't reset the list and people can't say the same thing twice anymore.
if(message_delay)
if (message_delay)
message_delay = 0
..()
return ..()
/*
Basically just an empty shell for receiving and broadcasting radio messages. Not
very flexible, but it gets the job done.
NOTE: This AIO device listens on *every* zlevel (it does not even check)
*/
/obj/machinery/telecomms/allinone
name = "Telecommunications Mainframe"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "allinone"
desc = "A compact machine used for portable subspace telecommuniations processing."
density = 1
use_power = USE_POWER_IDLE
idle_power_usage = 20
anchored = 1
machinetype = 6
produces_heat = 0
var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel
var/overmap_range = 0 //Same turf
var/list/linked_radios_weakrefs = list()
/obj/machinery/telecomms/allinone/proc/link_radio(var/obj/item/radio/R)
if(!istype(R))
/obj/machinery/telecomms/broadcaster/proc/link_radio(obj/item/radio/radio)
if (!istype(radio))
return
linked_radios_weakrefs |= weakref(R)
linked_radios_weakrefs |= weakref(radio)
/obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal)
// Has to be on to receive messages
if(!on)
/obj/machinery/telecomms/broadcaster/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (signal.data["reject"])
return
// Why did you use this subtype?
if(!using_map.use_overmap)
if (!signal.data["message"])
return
// Someone else handling it?
if(signal.data["done"])
signal.data["done"] = TRUE
var/datum/signal/original = signal.data["original"]
if (original)
original.data["done"] = TRUE
original.data["compression"] = signal.data["compression"]
original.data["level"] = signal.data["level"]
var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]"
if (signal_message in recentmessages)
return
// Where are we able to hear from (and talk to, since we're AIO) anyway?
var/map_levels = using_map.get_map_levels(z, TRUE, overmap_range)
//Bluespace can skip this check
if(signal.transmission_method != TRANSMISSION_BLUESPACE)
var/list/signal_levels = list()
signal_levels += signal.data["level"] //If it's text/number, it'll be the only entry, if it's a list, it'll get combined
var/list/overlap = map_levels & signal_levels //Returns a list of similar levels
if(!overlap.len)
return
if(is_freq_listening(signal)) // detect subspace signals
signal.data["done"] = 1 // mark the signal as being broadcasted since we're a broadcaster
signal.data["compression"] = 0 // decompress since we're a processor
// Search for the original signal and mark it as done as well
var/datum/signal/original = signal.data["original"]
if(original)
original.data["done"] = 1
// For some reason level is both used as a list and not a list, and now it needs to be a list.
signal.data["level"] = map_levels
if(signal.data["slow"] > 0)
sleep(signal.data["slow"]) // simulate the network lag if necessary
/* ###### Broadcast a message using signal.data ###### */
var/datum/radio_frequency/connection = signal.data["connection"]
var/list/forced_radios
for(var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/R = wr.resolve()
if(istype(R))
LAZYDISTINCTADD(forced_radios, R)
recentmessages += signal_message
if (signal.data["slow"] > 0)
sleep(signal.data["slow"])
signal.data["level"] |= using_map.get_map_levels(listening_level, TRUE, overmap_range)
var/list/forced_radios
for (var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/R = wr.resolve()
if (istype(R))
LAZYDISTINCTADD(forced_radios, R)
if (signal.data["type"] == SIGNAL_NORMAL)
Broadcast_Message(
signal.data["connection"],
signal.data["mob"],
signal.data["vmask"],
signal.data["vmessage"],
signal.data["radio"],
signal.data["message"],
signal.data["name"],
signal.data["job"],
signal.data["realname"],
signal.data["vname"],
DATA_NORMAL,
signal.data["compression"],
signal.data["level"],
connection.frequency,
signal.data["verb"],
signal.data["language"],
forced_radios
signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_NORMAL,
signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], forced_radios
)
//Antag version with unlimited range (doesn't even check) and uses no power, to enable antag comms to work anywhere.
/obj/machinery/telecomms/allinone/antag
use_power = USE_POWER_OFF
idle_power_usage = 0
/obj/machinery/telecomms/allinone/antag/receive_signal(datum/signal/signal)
if(!on) // has to be on to receive messages
return
if(is_freq_listening(signal)) // detect subspace signals
signal.data["done"] = 1 // mark the signal as being broadcasted
signal.data["compression"] = 0
// Search for the original signal and mark it as done as well
var/datum/signal/original = signal.data["original"]
if(original)
original.data["done"] = 1
// For some reason level is both used as a list and not a list, and now it needs to be a list.
// Because this is a 'all in one' machine, we're gonna just cheat.
signal.data["level"] = using_map.contact_levels.Copy()
if(signal.data["slow"] > 0)
sleep(signal.data["slow"]) // simulate the network lag if necessary
/* ###### Broadcast a message using signal.data ###### */
var/datum/radio_frequency/connection = signal.data["connection"]
var/list/forced_radios
for(var/weakref/wr in linked_radios_weakrefs)
var/obj/item/radio/R = wr.resolve()
if(istype(R))
LAZYDISTINCTADD(forced_radios, R)
if(connection.frequency in ANTAG_FREQS) // if antag broadcast, just
Broadcast_Message(signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_NORMAL,
signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], forced_radios)
else
if(intercept)
Broadcast_Message(signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_ANTAG,
signal.data["compression"], list(0), connection.frequency,
signal.data["verb"], forced_radios)
/**
Here is the big, bad function that broadcasts a message given the appropriate
parameters.
@param connection:
The datum generated in radio.dm, stored in signal.data["connection"].
@param M:
Reference to the mob/speaker, stored in signal.data["mob"]
@param vmask:
Boolean value if the mob is "hiding" its identity via voice mask, stored in
signal.data["vmask"]
@param vmessage:
If specified, will display this as the message; such as "chimpering"
for monkies if the mob is not understood. Stored in signal.data["vmessage"].
@param radio:
Reference to the radio broadcasting the message, stored in signal.data["radio"]
@param message:
The actual string message to display to mobs who understood mob M. Stored in
signal.data["message"]
@param name:
The name to display when a mob receives the message. signal.data["name"]
@param job:
The name job to display for the AI when it receives the message. signal.data["job"]
@param realname:
The "real" name associated with the mob. signal.data["realname"]
@param vname:
If specified, will use this name when mob M is not understood. signal.data["vname"]
@param data:
If specified:
1 -- Will only broadcast to intercoms
2 -- Will only broadcast to intercoms and station-bounced radios
3 -- Broadcast to syndicate frequency
4 -- AI can't track down this person. Useful for imitation broadcasts where you can't find the actual mob
@param compression:
If 0, the signal is audible
If nonzero, the signal may be partially inaudible or just complete gibberish.
@param level:
The list of Z levels that the sending radio is broadcasting to. Having 0 in the list broadcasts on all levels
@param freq
The frequency of the signal
**/
/proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M,
var/vmask, var/list/vmessage_pieces, var/obj/item/radio/radio,
var/list/message_pieces, var/name, var/job, var/realname, var/vname,
var/data, var/compression, var/list/level, var/freq, var/verbage = "says",
var/list/forced_radios)
/* ###### Prepare the radio connection ###### */
var/display_freq = freq
var/list/obj/item/radio/radios = list()
for(var/obj/item/radio/R in forced_radios)
//Cursory check to ensure they are 'on' and stuff
if(R.receive_range(display_freq, list(0)) > -1)
radios |= R
// --- Broadcast only to intercom devices ---
if(data == DATA_INTERCOM)
for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"])
if(R.receive_range(display_freq, level) > -1)
radios |= R
// --- Broadcast only to intercoms and station-bounced radios ---
else if(data == DATA_LOCAL)
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(istype(R, /obj/item/radio/headset) && !R.adhoc_fallback)
continue
if(R.receive_range(display_freq, level) > -1)
radios |= R
// --- Broadcast to antag radios! ---
else if(data == DATA_ANTAG)
for(var/antag_freq in ANTAG_FREQS)
var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq)
for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"])
if(R.receive_range(antag_freq, level) > -1)
radios |= R
// --- Broadcast to ALL radio devices ---
else
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(R.receive_range(display_freq, level) > -1)
radios |= R
// Get a list of mobs who can hear from the radios we collected.
var/list/receive = get_mobs_in_radio_ranges(radios)
/* ###### Organize the receivers into categories for displaying the message ###### */
// Understood the message:
var/list/heard_masked = list() // masked name or no real name
var/list/heard_normal = list() // normal message
// Did not understand the message:
var/list/heard_voice = list() // voice message (ie "chimpers")
var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!")
var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!")
for (var/mob/R in receive)
/* --- Loop through the receivers and categorize them --- */
if(!R.is_preference_enabled(/datum/client_preference/holder/hear_radio))
continue
if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes.
continue
// Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates
if(data == DATA_ANTAG && istype(R, /mob/observer/dead) && R.is_preference_enabled(/datum/client_preference/ghost_radio))
continue
// --- Check for compression ---
if(compression > 0)
heard_gibberish += R
continue
// --- Can understand the speech ---
if(!M || R.say_understands(M))
// - Not human or wearing a voice mask -
if(!M || !ishuman(M) || vmask)
heard_masked += R
// - Human and not wearing voice mask -
else
heard_normal += R
// --- Can't understand the speech ---
else
// - The speaker has a prespecified "voice message" to display if not understood -
if(vmessage_pieces)
heard_voice += R
// - Just display a garbled message -
else
heard_garbled += R
/* ###### Begin formatting and sending the message ###### */
if(length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish))
/* --- Some miscellaneous variables to format the string output --- */
var/freq_text = get_frequency_name(display_freq)
var/part_b_extra = ""
if(data == DATA_ANTAG) // intercepted radio message
part_b_extra = " <i>(Intercepted)</i>"
var/part_a = "<span class='[frequency_span_class(display_freq)]'>"
var/part_b = "[bicon(radio)]<b>\[[freq_text]\][part_b_extra]</b> <span class='name'>" // goes in the actual output
// --- Some more pre-message formatting ---
var/part_c = "</span> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_d = "</span>"
var/part_e = "</span>"
// --- Filter the message; place it in quotes apply a verb ---
var/quotedmsg = null
if(M)
quotedmsg = "[M.say_quote(multilingual_to_message(message_pieces))], \"[multilingual_to_message(message_pieces)]\""
else
quotedmsg = "says, \"[multilingual_to_message(message_pieces)]\""
// --- This following recording is intended for research and feedback in the use of department radio channels ---
var/part_blackbox_c = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/blackbox_msg = "[part_a][part_b][name][part_blackbox_c][quotedmsg][part_d][part_e]"
//var/blackbox_admin_msg = "[part_a][M.name] (Real name: [M.real_name])[part_blackbox_b][quotedmsg][part_c]"
//BR.messages_admin += blackbox_admin_msg
if(istype(blackbox))
switch(display_freq)
if(PUB_FREQ)
blackbox.msg_common += blackbox_msg
if(SCI_FREQ)
blackbox.msg_science += blackbox_msg
if(COMM_FREQ)
blackbox.msg_command += blackbox_msg
if(MED_FREQ)
blackbox.msg_medical += blackbox_msg
if(ENG_FREQ)
blackbox.msg_engineering += blackbox_msg
if(SEC_FREQ)
blackbox.msg_security += blackbox_msg
if(DTH_FREQ)
blackbox.msg_deathsquad += blackbox_msg
if(SYND_FREQ)
blackbox.msg_syndicate += blackbox_msg
if(RAID_FREQ)
blackbox.msg_raider += blackbox_msg
if(SUP_FREQ)
blackbox.msg_cargo += blackbox_msg
if(SRV_FREQ)
blackbox.msg_service += blackbox_msg
if(EXP_FREQ)
blackbox.msg_explorer += blackbox_msg
else
blackbox.messages += blackbox_msg
//End of research and feedback code.
/* ###### Send the message ###### */
/* --- Process all the mobs that heard a masked voice (understood) --- */
if(length(heard_masked))
for (var/mob/R in heard_masked)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 0, name)
/* --- Process all the mobs that heard the voice normally (understood) --- */
if(length(heard_normal))
for (var/mob/R in heard_normal)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 0, realname)
/* --- Process all the mobs that heard the voice normally (did not understand) --- */
if(length(heard_voice))
for (var/mob/R in heard_voice)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M,0, vname)
/* --- Process all the mobs that heard a garbled voice (did not understand) --- */
// Displays garbled message (ie "f*c* **u, **i*er!")
if(length(heard_garbled))
for (var/mob/R in heard_garbled)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 1, vname)
/* --- Complete gibberish. Usually happens when there's a compressed message --- */
if(length(heard_gibberish))
for (var/mob/R in heard_gibberish)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 1)
return 1
/proc/Broadcast_SimpleMessage(var/source, var/frequency, list/message_pieces, var/data, var/mob/M, var/compression, var/level, var/list/forced_radios)
var/text = multilingual_to_message(message_pieces)
/* ###### Prepare the radio connection ###### */
if(!M)
var/mob/living/carbon/human/H = new
M = H
var/datum/radio_frequency/connection = radio_controller.return_frequency(frequency)
var/display_freq = connection.frequency
var/list/receive = list()
for(var/obj/item/radio/R in forced_radios)
receive |= R.send_hear(display_freq)
// --- Broadcast only to intercom devices ---
if(data == DATA_INTERCOM)
for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq, level)
// --- Broadcast only to intercoms and station-bounced radios ---
else if(data == DATA_LOCAL)
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(istype(R, /obj/item/radio/headset))
continue
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq)
// --- Broadcast to antag radios! ---
else if(data == DATA_ANTAG)
for(var/freq in ANTAG_FREQS)
var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq)
for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(freq)
// --- Broadcast to ALL radio devices ---
else
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq)
/* ###### Organize the receivers into categories for displaying the message ###### */
// Understood the message:
var/list/heard_normal = list() // normal message
// Did not understand the message:
var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!")
var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!")
for (var/mob/R in receive)
/* --- Loop through the receivers and categorize them --- */
if(!R.is_preference_enabled(/datum/client_preference/holder/hear_radio)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios.
continue
// --- Check for compression ---
if(compression > 0)
heard_gibberish += R
continue
// --- Can understand the speech ---
if(R.say_understands(M))
heard_normal += R
// --- Can't understand the speech ---
else
// - Just display a garbled message -
heard_garbled += R
/* ###### Begin formatting and sending the message ###### */
if(length(heard_normal) || length(heard_garbled) || length(heard_gibberish))
/* --- Some miscellaneous variables to format the string output --- */
var/part_a = "<span class='[frequency_span_class(display_freq)]'><span class='name'>" // goes in the actual output
var/freq_text = get_frequency_name(display_freq)
// --- Some more pre-message formatting ---
var/part_b_extra = ""
if(data == DATA_ANTAG) // intercepted radio message
part_b_extra = " <i>(Intercepted)</i>"
// Create a radio headset for the sole purpose of using its icon
var/obj/item/radio/headset/radio = new
var/part_b = "</span><b> [bicon(radio)]\[[freq_text]\][part_b_extra]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_blackbox_b = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_c = "</span></span>"
var/blackbox_msg = "[part_a][source][part_blackbox_b]\"[text]\"[part_c]"
//BR.messages_admin += blackbox_admin_msg
if(istype(blackbox))
switch(display_freq)
if(PUB_FREQ)
blackbox.msg_common += blackbox_msg
if(SCI_FREQ)
blackbox.msg_science += blackbox_msg
if(COMM_FREQ)
blackbox.msg_command += blackbox_msg
if(MED_FREQ)
blackbox.msg_medical += blackbox_msg
if(ENG_FREQ)
blackbox.msg_engineering += blackbox_msg
if(SEC_FREQ)
blackbox.msg_security += blackbox_msg
if(DTH_FREQ)
blackbox.msg_deathsquad += blackbox_msg
if(SYND_FREQ)
blackbox.msg_syndicate += blackbox_msg
if(RAID_FREQ)
blackbox.msg_raider += blackbox_msg
if(SUP_FREQ)
blackbox.msg_cargo += blackbox_msg
if(SRV_FREQ)
blackbox.msg_service += blackbox_msg
else
blackbox.messages += blackbox_msg
//End of research and feedback code.
/* ###### Send the message ###### */
/* --- Process all the mobs that heard the voice normally (understood) --- */
if(length(heard_normal))
var/rendered = "[part_a][source][part_b]\"[text]\"[part_c]"
for (var/mob/R in heard_normal)
R.show_message(rendered, 2)
/* --- Process all the mobs that heard a garbled voice (did not understand) --- */
// Displays garbled message (ie "f*c* **u, **i*er!")
if(length(heard_garbled))
var/quotedmsg = "\"[stars(text)]\""
var/rendered = "[part_a][source][part_b][quotedmsg][part_c]"
for (var/mob/R in heard_garbled)
R.show_message(rendered, 2)
/* --- Complete gibberish. Usually happens when there's a compressed message --- */
if(length(heard_gibberish))
var/quotedmsg = "\"[Gibberish(text, compression + 50)]\""
var/rendered = "[part_a][Gibberish(source, compression + 50)][part_b][quotedmsg][part_c]"
for (var/mob/R in heard_gibberish)
R.show_message(rendered, 2)
//Use this to test if an obj can communicate with a Telecommunications Network
/atom/proc/test_telecomms()
var/datum/signal/signal = src.telecomms_process()
var/pos_z = get_z(src)
return (pos_z in signal.data["level"] && signal.data["done"])
/atom/proc/telecomms_process(var/do_sleep = 1)
// First, we want to generate a new radio signal
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_SUBSPACE
var/pos_z = get_z(src)
// --- Finally, tag the actual signal with the appropriate values ---
signal.data = list(
"slow" = 0, // how much to sleep() before broadcasting - simulates net lag
"message" = "TEST",
"compression" = rand(45, 50), // If the signal is compressed, compress our message too.
"traffic" = 0, // dictates the total traffic sum that the signal went through
"type" = SIGNAL_TEST, // determines what type of radio input it is: test broadcast
"reject" = 0,
"done" = 0,
"level" = pos_z // The level it is being broadcasted at.
)
signal.frequency = PUB_FREQ// Common channel
//#### Sending the signal to all subspace receivers ####//
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
R.receive_signal(signal)
if(do_sleep)
sleep(rand(10,25))
//to_world_log("Level: [signal.data["level"]] - Done: [signal.data["done"]]")
return signal
if (signal.data["type"] == SIGNAL_SIMPLE)
Broadcast_SimpleMessage(
signal.data["name"], signal.frequency,
signal.data["message"], DATA_NORMAL, null,
signal.data["compression"], listening_level, forced_radios
)
if (signal.data["type"] == SIGNAL_FAKE)
Broadcast_Message( // Uses DATA_FAKE to prevent AI from tracking the source
signal.data["connection"], signal.data["mob"],
signal.data["vmask"], signal.data["vmessage"],
signal.data["radio"], signal.data["message"],
signal.data["name"], signal.data["job"],
signal.data["realname"], signal.data["vname"], DATA_FAKE,
signal.data["compression"], signal.data["level"], signal.frequency,
signal.data["verb"], forced_radios
)
if (!message_delay)
message_delay = TRUE
spawn(10)
message_delay = FALSE
recentmessages = list()
flick("broadcaster_send", src)
/obj/machinery/telecomms/broadcaster/OptionsMenu()
var/list/data = ..()
data["use_broadcast_range"] = TRUE
data["range"] = overmap_range
data["minRange"] = overmap_range_min
data["maxRange"] = overmap_range_max
return data
/obj/machinery/telecomms/broadcaster/OptionsHandler(action, params)
if (..())
return TRUE
switch (action)
if ("range")
var/new_range = params["range"]
overmap_range = clamp(new_range, overmap_range_min, overmap_range_max)
update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1))

View File

@@ -0,0 +1,71 @@
/* Telecomms Bus
* The bus mainframe idles and waits for hubs to relay them signals. They act
* as junctions for the network. They transfer uncompressed subspace packets
* to processor units, and then take the processed packet to a server for
* logging. Link to a subspace hub if it can't send to a server.
*/
/obj/machinery/telecomms/bus
name = "Bus Mainframe"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "bus"
desc = "A mighty piece of hardware used to send massive amounts of data quickly."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 1000
machinetype = 2
circuit = /obj/item/circuitboard/telecomms/bus
netspeed = 40
var/change_frequency = 0
/obj/machinery/telecomms/bus/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (!is_freq_listening(signal))
return
if (change_frequency)
signal.frequency = change_frequency
if (sender != src && !istype(sender, /obj/machinery/telecomms/processor))
var/send_success = relay_information(signal, /obj/machinery/telecomms/processor)
if (send_success)
return
signal.data["slow"] += rand(1, 5)
receive_information(signal, src)
var/list/attempt_types = list(
/obj/machinery/telecomms/server,
/obj/machinery/telecomms/hub,
/obj/machinery/telecomms/broadcaster,
/obj/machinery/telecomms/bus
)
for (var/i = 1 to length(attempt_types))
var/send_success = relay_information(signal, attempt_types[i])
if (send_success)
return
signal.data["slow"] += rand(0, 1)
/obj/machinery/telecomms/bus/OptionsMenu()
var/list/data = ..()
data["use_change_freq"] = TRUE
data["change_freq"] = change_frequency
return data
/obj/machinery/telecomms/bus/OptionsHandler(action, params)
if (..())
return TRUE
switch (action)
if ("change_freq")
. = TRUE
var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null | num
if (!canAccess(usr))
return
if (newfreq)
if (findtext(num2text(newfreq), "."))
newfreq *= 10
if (newfreq < 10000)
change_frequency = newfreq
set_temp("-% New frequency to change to assigned: \"[newfreq] GHz\" %-", "average")
else
change_frequency = 0
set_temp("-% Frequency changing deactivated %-", "average")

View File

@@ -0,0 +1,32 @@
/* Telecomms Hub
* The hub idles until it receives information. It then passes on that information
* depending on where it came from. This is the heart of the Telecommunications
* Network, sending information where it is needed. It mainly receives information
* from long-distance Relays and then sends that information to be processed.
* Afterwards it gets the uncompressed information from Servers/Buses and sends
* that back to the relay, to then be broadcasted.
*/
/obj/machinery/telecomms/hub
name = "Telecommunication Hub"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "hub"
desc = "A mighty piece of hardware used to send/receive massive amounts of data."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 1600
machinetype = 7
circuit = /obj/item/circuitboard/telecomms/hub
long_range_link = TRUE
netspeed = 40
/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (!is_freq_listening(signal))
return
if (istype(sender, /obj/machinery/telecomms/receiver))
relay_information(signal, /obj/machinery/telecomms/bus, TRUE)
return
relay_information(signal, /obj/machinery/telecomms/relay, TRUE)
relay_information(signal, /obj/machinery/telecomms/broadcaster, TRUE)

View File

@@ -1,156 +1,131 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
/obj/machinery/computer/telecomms
icon_keyboard = "tech_key"
/obj/machinery/computer/telecomms/server
name = "Telecommunications Server Monitor"
desc = "View communication logs here. Translation not guaranteed."
icon_screen = "comm_logs"
var/list/servers = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedServer
icon_keyboard = "tech_key"
circuit = /obj/item/circuitboard/comm_server
var/network = "NULL" // the network to probe
var/list/temp = null // temporary feedback messages
var/universal_translate = 0 // set to 1 if it can translate nonhuman speech
req_access = list(access_tcomsat)
var/list/servers = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedServer
var/network = "NULL" // the network to probe
var/list/temp // temporary feedback messages
var/universal_translate = FALSE // set to 1 if it can translate nonhuman speech
/obj/machinery/computer/telecomms/server/tgui_data(mob/user)
var/list/data = list()
data["universal_translate"] = universal_translate
data["network"] = network
data["temp"] = temp
var/list/servers = list()
for(var/obj/machinery/telecomms/T in src.servers)
servers.Add(list(list(
"id" = T.id,
"name" = T.name,
)))
for(var/obj/machinery/telecomms/machine in servers)
servers += list(list(
"id" = machine.id,
"name" = machine.name,
))
data["servers"] = servers
data["selectedServer"] = null
if(SelectedServer)
if (SelectedServer)
data["selectedServer"] = list(
"id" = SelectedServer.id,
"totalTraffic" = SelectedServer.totaltraffic,
)
var/list/logs = list()
var/i = 0
for(var/c in SelectedServer.log_entries)
i++
var/datum/comm_log_entry/C = c
// This is necessary to prevent leaking information to the clientside
var/list/logs = list()
for (var/datum/comm_log_entry/log as anything in SelectedServer.log_entries)
var/static/list/acceptable_params = list("uspeech", "intelligible", "message", "name", "race", "job", "timecode")
var/list/parameters = list()
for(var/log_param in acceptable_params)
parameters["[log_param]"] = C.parameters["[log_param]"]
logs.Add(list(list(
"name" = C.name,
"input_type" = C.input_type,
"id" = i,
for (var/log_param in acceptable_params)
parameters["[log_param]"] = log.parameters["[log_param]"]
logs += list(list(
"name" = log.name,
"input_type" = log.input_type,
"id" = ++i,
"parameters" = parameters,
)))
))
data["selectedServer"]["logs"] = logs
return data
/obj/machinery/computer/telecomms/server/attack_hand(mob/user)
if(stat & (BROKEN|NOPOWER))
if (stat & (BROKEN|NOPOWER))
return
tgui_interact(user)
/obj/machinery/computer/telecomms/server/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TelecommsLogBrowser", name)
if (!ui)
ui = new (user, src, "TelecommsLogBrowser", name)
ui.open()
/obj/machinery/computer/telecomms/server/tgui_act(action, params)
if(..())
if (..())
return TRUE
add_fingerprint(usr)
switch(action)
if("view")
for(var/obj/machinery/telecomms/T in servers)
if(T.id == params["id"])
SelectedServer = T
if ("view")
for (var/obj/machinery/telecomms/machine in servers)
if (machine.id == params["id"])
SelectedServer = machine
break
. = TRUE
if("mainmenu")
if ("mainmenu")
SelectedServer = null
. = TRUE
if("release")
if ("release")
servers = list()
SelectedServer = null
. = TRUE
if("scan")
if(servers.len > 0)
if ("scan")
if (length(servers))
set_temp("FAILED: CANNOT PROBE WHEN BUFFER FULL", "bad")
return TRUE
for(var/obj/machinery/telecomms/server/T in range(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
set_temp("FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\]", "bad")
else
for (var/obj/machinery/telecomms/server/server in range(25, src))
if (server.network == network)
servers += server
if (length(servers))
set_temp("[servers.len] SERVERS PROBED & BUFFERED", "good")
else
set_temp("FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\]", "bad")
. = TRUE
if("delete")
if(!allowed(usr) && !emagged)
if ("delete")
if (!allowed(usr) && !emagged)
to_chat(usr, "<span class='warning'>ACCESS DENIED.</span>")
return
if(SelectedServer)
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(params["id"])]
set_temp("DELETED ENTRY: [D.name]", "bad")
SelectedServer.log_entries.Remove(D)
qdel(D)
if (SelectedServer)
var/datum/comm_log_entry/log = SelectedServer.log_entries[text2num(params["id"])]
set_temp("DELETED ENTRY: [log.name]", "bad")
SelectedServer.log_entries -= log
qdel(log)
else
set_temp("FAILED: NO SELECTED MACHINE", "bad")
. = TRUE
if("network")
var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text
if(newnet && ((usr in range(1, src) || issilicon(usr))))
if(length(newnet) > 15)
if ("network")
var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null | text
if (newnet && (issilicon(usr) || (usr in range(1, src))))
if (length(newnet) > 15)
set_temp("FAILED: NETWORK TAG STRING TOO LENGTHY", "bad")
return TRUE
network = newnet
servers = list()
set_temp("NEW NETWORK TAG SET IN ADDRESS \[[network]\]", "good")
. = TRUE
if("cleartemp")
if ("cleartemp")
temp = null
. = TRUE
/obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
emagged = 1
to_chat(user, "<span class='notice'>You you disable the security protocols</span>")
src.updateUsrDialog()
return 1
/obj/machinery/computer/telecomms/server/proc/set_temp(var/text, var/color = "average")
/obj/machinery/computer/telecomms/server/emag_act(remaining_charges, mob/user)
if (emagged)
return
playsound(src, 'sound/effects/sparks4.ogg', 75, TRUE)
emagged = TRUE
to_chat(user, SPAN_NOTICE("You you disable the security protocols"))
updateUsrDialog()
return 1
/obj/machinery/computer/telecomms/server/proc/set_temp(text, color = "average")
temp = list("color" = color, "text" = text)

View File

@@ -1,386 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/*
All telecommunications interactions:
*/
#define STATION_Z 1
#define TELECOMM_Z 3
/obj/machinery/telecomms
var/list/temp = null // output message
/obj/machinery/telecomms/attackby(obj/item/P as obj, mob/user as mob)
// Using a multitool lets you access the receiver's interface
if(istype(P, /obj/item/multitool))
attack_hand(user)
// REPAIRING: Use Nanopaste to repair 10-20 integrity points.
if(istype(P, /obj/item/stack/nanopaste))
var/obj/item/stack/nanopaste/T = P
if (integrity < 100) //Damaged, let's repair!
if (T.use(1))
integrity = between(0, integrity + rand(10,20), 100)
to_chat(usr, "You apply the Nanopaste to [src], repairing some of the damage.")
else
to_chat(usr, "This machine is already in perfect condition.")
return
if(default_deconstruction_screwdriver(user, P))
return
if(default_deconstruction_crowbar(user, P))
return
/obj/machinery/telecomms/attack_ai(var/mob/user as mob)
attack_hand(user)
/obj/machinery/telecomms/tgui_data(mob/user)
var/list/data = list()
data["temp"] = temp
data["on"] = on
data["id"] = null
data["network"] = null
data["autolinkers"] = FALSE
data["shadowlink"] = FALSE
data["options"] = list()
data["linked"] = list()
data["filter"] = list()
data["multitool"] = FALSE
data["multitool_buffer"] = null
if(on || interact_offline)
data["id"] = id
data["network"] = network
data["autolinkers"] = !!LAZYLEN(autolinkers)
data["shadowlink"] = !!hide
data["options"] = Options_Menu()
var/obj/item/multitool/P = get_multitool(user)
data["multitool"] = !!P
data["multitool_buffer"] = null
if(P && P.buffer)
P.update_icon()
data["multitool_buffer"] = list("name" = "[P.buffer]", "id" = "[P.buffer.id]")
var/i = 0
var/list/linked = list()
for(var/obj/machinery/telecomms/T in links)
i++
linked.Add(list(list(
"ref" = "\ref[T]",
"name" = "[T]",
"id" = T.id,
"index" = i,
)))
data["linked"] = linked
var/list/filter = list()
if(LAZYLEN(freq_listening))
for(var/x in freq_listening)
filter.Add(list(list(
"name" = "[format_frequency(x)]",
"freq" = x,
)))
data["filter"] = filter
return data
/obj/machinery/telecomms/tgui_status(mob/user)
if(!issilicon(user))
if(!istype(user.get_active_hand(), /obj/item/multitool))
return STATUS_CLOSE
. = ..()
/obj/machinery/telecomms/attack_hand(var/mob/user as mob)
tgui_interact(user)
/obj/machinery/telecomms/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TelecommsMultitoolMenu", name)
ui.open()
// Off-Site Relays
//
// You are able to send/receive signals from the station's z level (changeable in the STATION_Z #define) if
// the relay is on the telecomm satellite (changable in the TELECOMM_Z #define)
/obj/machinery/telecomms/relay/proc/toggle_level()
var/turf/position = get_turf(src)
// Toggle on/off getting signals from the station or the current Z level
if(src.listening_level == STATION_Z) // equals the station
src.listening_level = position.z
return 1
else if(position.z == TELECOMM_Z)
src.listening_level = STATION_Z
return 1
return 0
// Returns a multitool from a user depending on their mobtype.
/obj/machinery/proc/get_multitool(mob/user as mob) //No need to have this being a telecomms specific proc.
var/obj/item/multitool/P = null
// Let's double check
if(!issilicon(user) && istype(user.get_active_hand(), /obj/item/multitool))
P = user.get_active_hand()
else if(isAI(user))
var/mob/living/silicon/ai/U = user
P = U.aiMulti
else if(isrobot(user) && in_range(user, src))
if(istype(user.get_active_hand(), /obj/item/multitool))
P = user.get_active_hand()
return P
// Additional Options for certain machines. Use this when you want to add an option to a specific machine.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Menu()
return list()
/*
// Add an option to the processor to switch processing mode. (COMPRESS -> UNCOMPRESS or UNCOMPRESS -> COMPRESS)
/obj/machinery/telecomms/processor/Options_Menu()
var/dat = "<br>Processing Mode: <A href='?src=\ref[src];process=1'>[process_mode ? "UNCOMPRESS" : "COMPRESS"]</a>"
return dat
*/
// The topic for Additional Options. Use this for checking href links for your specific option.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Act(action, params)
return
/*
/obj/machinery/telecomms/processor/Options_Act(action, params)
if(href_list["process"])
set_temp("-% Processing mode changed. %-", "average")
src.process_mode = !src.process_mode
*/
// RELAY
/obj/machinery/telecomms/relay/Options_Menu()
var/list/data = ..()
data["use_listening_level"] = TRUE
data["use_broadcasting"] = TRUE
data["use_receiving"] = TRUE
data["listening_level"] = (listening_level == STATION_Z)
data["broadcasting"] = broadcasting
data["receiving"] = receiving
return data
/obj/machinery/telecomms/relay/Options_Act(action, params)
if(..())
return TRUE
switch(action)
if("receive")
. = TRUE
receiving = !receiving
set_temp("-% Receiving mode changed. %-", "average")
if("broadcast")
. = TRUE
broadcasting = !broadcasting
set_temp("-% Broadcasting mode changed. %-", "average")
if("change_listening")
. = TRUE
//Lock to the station OR lock to the current position!
//You need at least two receivers and two broadcasters for this to work, this includes the machine.
var/result = toggle_level()
if(result)
set_temp("-% [src]'s signal has been successfully changed.", "average")
else
set_temp("-% [src] could not lock it's signal onto the station. Two broadcasters or receivers required.", "average")
// BUS
/obj/machinery/telecomms/bus/Options_Menu()
var/list/data = ..()
data["use_change_freq"] = TRUE
data["change_freq"] = change_frequency
return data
/obj/machinery/telecomms/bus/Options_Act(action, params)
if(..())
return TRUE
switch(action)
if("change_freq")
. = TRUE
var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num
if(canAccess(usr))
if(newfreq)
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(newfreq < 10000)
change_frequency = newfreq
set_temp("-% New frequency to change to assigned: \"[newfreq] GHz\" %-", "average")
else
change_frequency = 0
set_temp("-% Frequency changing deactivated %-", "average")
// BROADCASTER
/obj/machinery/telecomms/broadcaster/Options_Menu()
var/list/data = ..()
data["use_broadcast_range"] = TRUE
data["range"] = overmap_range
data["minRange"] = overmap_range_min
data["maxRange"] = overmap_range_max
return data
/obj/machinery/telecomms/broadcaster
interact_offline = TRUE // because you can accidentally nuke power grids with these, need to be able to fix mistake
/obj/machinery/telecomms/broadcaster/Options_Act(action, params)
if(..())
return TRUE
switch(action)
if("range")
var/new_range = params["range"]
overmap_range = clamp(new_range, overmap_range_min, overmap_range_max)
update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1))
// RECEIVER
/obj/machinery/telecomms/receiver/Options_Menu()
var/list/data = ..()
data["use_receive_range"] = TRUE
data["range"] = overmap_range
data["minRange"] = overmap_range_min
data["maxRange"] = overmap_range_max
return data
/obj/machinery/telecomms/receiver
interact_offline = TRUE // because you can accidentally nuke power grids with these, need to be able to fix mistake
/obj/machinery/telecomms/receiver/Options_Act(action, params)
if(..())
return TRUE
switch(action)
if("range")
var/new_range = params["range"]
overmap_range = clamp(new_range, overmap_range_min, overmap_range_max)
update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1))
/obj/machinery/telecomms/tgui_act(action, params)
if(..())
return TRUE
var/obj/item/multitool/P = get_multitool(usr)
switch(action)
if("toggle")
src.toggled = !src.toggled
set_temp("-% [src] has been [src.toggled ? "activated" : "deactivated"].", "average")
update_power()
. = TRUE
if("id")
var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN)
if(newid && canAccess(usr))
id = newid
set_temp("-% New ID assigned: \"[id]\" %-", "average")
. = TRUE
if("network")
var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null|text
if(newnet && canAccess(usr))
if(length(newnet) > 15)
set_temp("-% Too many characters in new network tag %-", "average")
else
for(var/obj/machinery/telecomms/T in links)
T.links.Remove(src)
network = newnet
links = list()
set_temp("-% New network tag assigned: \"[network]\" %-", "average")
. = TRUE
if("freq")
var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num
if(newfreq && canAccess(usr))
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(!(newfreq in freq_listening) && newfreq < 10000)
freq_listening.Add(newfreq)
set_temp("-% New frequency filter assigned: \"[newfreq] GHz\" %-", "average")
. = TRUE
if("delete")
var/x = text2num(params["delete"])
set_temp("-% Removed frequency filter [x] %-", "average")
freq_listening.Remove(x)
. = TRUE
if("unlink")
if(text2num(params["unlink"]) <= length(links))
var/obj/machinery/telecomms/T = links[text2num(params["unlink"])]
set_temp("-% Removed \ref[T] [T.name] from linked entities. %-", "average")
// Remove link entries from both T and src.
if(src in T.links)
T.links.Remove(src)
links.Remove(T)
. = TRUE
if("link")
if(P)
if(P.buffer && P.buffer != src)
if(!(src in P.buffer.links))
P.buffer.links.Add(src)
if(!(P.buffer in src.links))
src.links.Add(P.buffer)
set_temp("-% Successfully linked with \ref[P.buffer] [P.buffer.name] %-", "average")
else
set_temp("-% Unable to acquire buffer %-", "average")
. = TRUE
if("buffer")
P.buffer = src
set_temp("-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-", "average")
. = TRUE
if("flush")
set_temp("-% Buffer successfully flushed. %-", "average")
P.buffer = null
. = TRUE
if("cleartemp")
temp = null
. = TRUE
if(Options_Act(action, params))
. = TRUE
add_fingerprint(usr)
/obj/machinery/telecomms/proc/canAccess(var/mob/user)
if(issilicon(user) || in_range(user, src))
return 1
return 0
/obj/machinery/telecomms/proc/set_temp(var/text, var/color = "average")
temp = list("color" = color, "text" = text)
#undef TELECOMM_Z
#undef STATION_Z

View File

@@ -0,0 +1,567 @@
#define TELECOMMS_RECEPTION_NONE 0
#define TELECOMMS_RECEPTION_SENDER 1
#define TELECOMMS_RECEPTION_RECEIVER 2
#define TELECOMMS_RECEPTION_BOTH 3
/// The list of all telecomms machines
var/global/list/obj/machinery/telecomms/telecomms_list = list()
/// global list of recent messages broadcasted : used to circumvent massive radio spam
var/global/list/recentmessages = list()
/// To make sure restarting the recentmessages list is kept in sync
var/global/message_delay = 0
/datum/comm_log_entry
var/name = "data packet (#)"
var/input_type = "Speech File"
var/parameters = list()
/datum/reception
var/obj/machinery/message_server/message_server
var/telecomms_reception = TELECOMMS_RECEPTION_NONE
var/message = ""
/datum/receptions
var/obj/machinery/message_server/message_server
var/sender_reception = TELECOMMS_RECEPTION_NONE
var/list/receiver_reception = new
/atom/proc/telecomms_process(skip_sleep)
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_SUBSPACE
var/pos_z = get_z(src)
signal.data = list(
"slow" = 0, // how much to sleep() before broadcasting - simulates net lag
"message" = "TEST",
"compression" = rand(45, 50), // If the signal is compressed, compress our message too.
"traffic" = 0, // dictates the total traffic sum that the signal went through
"type" = SIGNAL_TEST, // determines what type of radio input it is: test broadcast
"reject" = 0,
"done" = 0,
"level" = pos_z // The level it is being broadcasted at.
)
signal.frequency = PUB_FREQ
for(var/obj/machinery/telecomms/receiver/receiver in telecomms_list)
receiver.receive_signal(signal)
if(!skip_sleep)
sleep(rand(10, 25))
return signal
/proc/register_radio(source, old_frequency, new_frequency, radio_filter)
if(old_frequency)
radio_controller.remove_object(source, old_frequency)
if(new_frequency)
return radio_controller.add_object(source, new_frequency, radio_filter)
/proc/unregister_radio(source, frequency)
if(radio_controller)
radio_controller.remove_object(source, frequency)
/proc/get_frequency_name(var/display_freq)
var/freq_text
if (display_freq in ANTAG_FREQS)
freq_text = "#unkn"
else
for (var/channel in radiochannels)
if (radiochannels[channel] == display_freq)
freq_text = channel
break
if (!freq_text)
freq_text = format_frequency(display_freq)
return freq_text
/proc/get_message_server()
if(message_servers)
for (var/obj/machinery/message_server/MS in message_servers)
if(MS.active)
return MS
return null
/proc/get_sender_reception(atom/sender, datum/signal/signal)
if (signal?.data["done"])
return TELECOMMS_RECEPTION_SENDER
return TELECOMMS_RECEPTION_NONE
/proc/get_receiver_reception(receiver, datum/signal/signal)
if (receiver && signal?.data["done"])
var/turf/pos = get_turf(receiver)
if (pos?.z in signal.data["level"])
return TELECOMMS_RECEPTION_RECEIVER
return TELECOMMS_RECEPTION_NONE
/proc/get_reception(atom/sender, receiver, message = "", skip_sleep)
var/datum/reception/reception = new
reception.message_server = get_message_server()
var/datum/signal/signal = sender.telecomms_process(skip_sleep)
reception.telecomms_reception |= get_sender_reception(sender, signal)
reception.telecomms_reception |= get_receiver_reception(receiver, signal)
reception.message = signal && signal.data["compression"] > 0 ? Gibberish(message, signal.data["compression"] + 50) : message
return reception
/proc/get_receptions(atom/sender, list/atom/receivers, skip_sleep)
var/datum/receptions/receptions = new
receptions.message_server = get_message_server()
var/datum/signal/signal
if (sender)
signal = sender.telecomms_process(skip_sleep)
receptions.sender_reception = get_sender_reception(sender, signal)
for (var/atom/receiver in receivers)
if (!signal)
signal = receiver.telecomms_process()
receptions.receiver_reception[receiver] = get_receiver_reception(receiver, signal)
return receptions
/**
Here is the big, bad function that broadcasts a message given the appropriate
parameters.
@param connection:
The datum generated in radio.dm, stored in signal.data["connection"].
@param M:
Reference to the mob/speaker, stored in signal.data["mob"]
@param vmask:
Boolean value if the mob is "hiding" its identity via voice mask, stored in
signal.data["vmask"]
@param vmessage:
If specified, will display this as the message; such as "chimpering"
for monkies if the mob is not understood. Stored in signal.data["vmessage"].
@param radio:
Reference to the radio broadcasting the message, stored in signal.data["radio"]
@param message:
The actual string message to display to mobs who understood mob M. Stored in
signal.data["message"]
@param name:
The name to display when a mob receives the message. signal.data["name"]
@param job:
The name job to display for the AI when it receives the message. signal.data["job"]
@param realname:
The "real" name associated with the mob. signal.data["realname"]
@param vname:
If specified, will use this name when mob M is not understood. signal.data["vname"]
@param data:
If specified:
1 -- Will only broadcast to intercoms
2 -- Will only broadcast to intercoms and station-bounced radios
3 -- Broadcast to syndicate frequency
4 -- AI can't track down this person. Useful for imitation broadcasts where you can't find the actual mob
@param compression:
If 0, the signal is audible
If nonzero, the signal may be partially inaudible or just complete gibberish.
@param level:
The list of Z levels that the sending radio is broadcasting to. Having 0 in the list broadcasts on all levels
@param freq
The frequency of the signal
*/
/proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M,
var/vmask, var/list/vmessage_pieces, var/obj/item/radio/radio,
var/list/message_pieces, var/name, var/job, var/realname, var/vname,
var/data, var/compression, var/list/level, var/freq, var/verbage = "says",
var/list/forced_radios)
/* ###### Prepare the radio connection ###### */
var/display_freq = freq
var/list/obj/item/radio/radios = list()
for(var/obj/item/radio/R in forced_radios)
//Cursory check to ensure they are 'on' and stuff
if(R.receive_range(display_freq, list(0)) > -1)
radios |= R
// --- Broadcast only to intercom devices ---
if(data == DATA_INTERCOM)
for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"])
if(R.receive_range(display_freq, level) > -1)
radios |= R
// --- Broadcast only to intercoms and station-bounced radios ---
else if(data == DATA_LOCAL)
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(istype(R, /obj/item/radio/headset) && !R.adhoc_fallback)
continue
if(R.receive_range(display_freq, level) > -1)
radios |= R
// --- Broadcast to antag radios! ---
else if(data == DATA_ANTAG)
for(var/antag_freq in ANTAG_FREQS)
var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq)
for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"])
if(R.receive_range(antag_freq, level) > -1)
radios |= R
// --- Broadcast to ALL radio devices ---
else
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(R.receive_range(display_freq, level) > -1)
radios |= R
// Get a list of mobs who can hear from the radios we collected.
var/list/receive = get_mobs_in_radio_ranges(radios)
/* ###### Organize the receivers into categories for displaying the message ###### */
// Understood the message:
var/list/heard_masked = list() // masked name or no real name
var/list/heard_normal = list() // normal message
// Did not understand the message:
var/list/heard_voice = list() // voice message (ie "chimpers")
var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!")
var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!")
for (var/mob/R in receive)
/* --- Loop through the receivers and categorize them --- */
if(!R.is_preference_enabled(/datum/client_preference/holder/hear_radio))
continue
if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes.
continue
// Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates
if(data == DATA_ANTAG && istype(R, /mob/observer/dead) && R.is_preference_enabled(/datum/client_preference/ghost_radio))
continue
// --- Check for compression ---
if(compression > 0)
heard_gibberish += R
continue
// --- Can understand the speech ---
if(!M || R.say_understands(M))
// - Not human or wearing a voice mask -
if(!M || !ishuman(M) || vmask)
heard_masked += R
// - Human and not wearing voice mask -
else
heard_normal += R
// --- Can't understand the speech ---
else
// - The speaker has a prespecified "voice message" to display if not understood -
if(vmessage_pieces)
heard_voice += R
// - Just display a garbled message -
else
heard_garbled += R
/* ###### Begin formatting and sending the message ###### */
if(length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish))
/* --- Some miscellaneous variables to format the string output --- */
var/freq_text = get_frequency_name(display_freq)
var/part_b_extra = ""
if(data == DATA_ANTAG) // intercepted radio message
part_b_extra = " <i>(Intercepted)</i>"
var/part_a = "<span class='[frequency_span_class(display_freq)]'>"
var/part_b = "[bicon(radio)]<b>\[[freq_text]\][part_b_extra]</b> <span class='name'>" // goes in the actual output
// --- Some more pre-message formatting ---
var/part_c = "</span> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_d = "</span>"
var/part_e = "</span>"
// --- Filter the message; place it in quotes apply a verb ---
var/quotedmsg = null
if(M)
quotedmsg = "[M.say_quote(multilingual_to_message(message_pieces))], \"[multilingual_to_message(message_pieces)]\""
else
quotedmsg = "says, \"[multilingual_to_message(message_pieces)]\""
// --- This following recording is intended for research and feedback in the use of department radio channels ---
var/part_blackbox_c = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/blackbox_msg = "[part_a][part_b][name][part_blackbox_c][quotedmsg][part_d][part_e]"
//var/blackbox_admin_msg = "[part_a][M.name] (Real name: [M.real_name])[part_blackbox_b][quotedmsg][part_c]"
//BR.messages_admin += blackbox_admin_msg
if(istype(blackbox))
switch(display_freq)
if(PUB_FREQ)
blackbox.msg_common += blackbox_msg
if(SCI_FREQ)
blackbox.msg_science += blackbox_msg
if(COMM_FREQ)
blackbox.msg_command += blackbox_msg
if(MED_FREQ)
blackbox.msg_medical += blackbox_msg
if(ENG_FREQ)
blackbox.msg_engineering += blackbox_msg
if(SEC_FREQ)
blackbox.msg_security += blackbox_msg
if(DTH_FREQ)
blackbox.msg_deathsquad += blackbox_msg
if(SYND_FREQ)
blackbox.msg_syndicate += blackbox_msg
if(RAID_FREQ)
blackbox.msg_raider += blackbox_msg
if(SUP_FREQ)
blackbox.msg_cargo += blackbox_msg
if(SRV_FREQ)
blackbox.msg_service += blackbox_msg
if(EXP_FREQ)
blackbox.msg_explorer += blackbox_msg
else
blackbox.messages += blackbox_msg
//End of research and feedback code.
/* ###### Send the message ###### */
/* --- Process all the mobs that heard a masked voice (understood) --- */
if(length(heard_masked))
for (var/mob/R in heard_masked)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 0, name)
/* --- Process all the mobs that heard the voice normally (understood) --- */
if(length(heard_normal))
for (var/mob/R in heard_normal)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 0, realname)
/* --- Process all the mobs that heard the voice normally (did not understand) --- */
if(length(heard_voice))
for (var/mob/R in heard_voice)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M,0, vname)
/* --- Process all the mobs that heard a garbled voice (did not understand) --- */
// Displays garbled message (ie "f*c* **u, **i*er!")
if(length(heard_garbled))
for (var/mob/R in heard_garbled)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 1, vname)
/* --- Complete gibberish. Usually happens when there's a compressed message --- */
if(length(heard_gibberish))
for (var/mob/R in heard_gibberish)
R.hear_radio(message_pieces, verbage, part_a, part_b, part_c, part_d, part_e, M, 1)
return 1
/proc/Broadcast_SimpleMessage(var/source, var/frequency, list/message_pieces, var/data, var/mob/M, var/compression, var/level, var/list/forced_radios)
var/text = multilingual_to_message(message_pieces)
/* ###### Prepare the radio connection ###### */
if(!M)
var/mob/living/carbon/human/H = new
M = H
var/datum/radio_frequency/connection = radio_controller.return_frequency(frequency)
var/display_freq = connection.frequency
var/list/receive = list()
for(var/obj/item/radio/R in forced_radios)
receive |= R.send_hear(display_freq)
// --- Broadcast only to intercom devices ---
if(data == DATA_INTERCOM)
for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq, level)
// --- Broadcast only to intercoms and station-bounced radios ---
else if(data == DATA_LOCAL)
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
if(istype(R, /obj/item/radio/headset))
continue
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq)
// --- Broadcast to antag radios! ---
else if(data == DATA_ANTAG)
for(var/freq in ANTAG_FREQS)
var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq)
for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(freq)
// --- Broadcast to ALL radio devices ---
else
for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
if(position && position.z == level)
receive |= R.send_hear(display_freq)
/* ###### Organize the receivers into categories for displaying the message ###### */
// Understood the message:
var/list/heard_normal = list() // normal message
// Did not understand the message:
var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!")
var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!")
for (var/mob/R in receive)
/* --- Loop through the receivers and categorize them --- */
if(!R.is_preference_enabled(/datum/client_preference/holder/hear_radio)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios.
continue
// --- Check for compression ---
if(compression > 0)
heard_gibberish += R
continue
// --- Can understand the speech ---
if(R.say_understands(M))
heard_normal += R
// --- Can't understand the speech ---
else
// - Just display a garbled message -
heard_garbled += R
/* ###### Begin formatting and sending the message ###### */
if(length(heard_normal) || length(heard_garbled) || length(heard_gibberish))
/* --- Some miscellaneous variables to format the string output --- */
var/part_a = "<span class='[frequency_span_class(display_freq)]'><span class='name'>" // goes in the actual output
var/freq_text = get_frequency_name(display_freq)
// --- Some more pre-message formatting ---
var/part_b_extra = ""
if(data == DATA_ANTAG) // intercepted radio message
part_b_extra = " <i>(Intercepted)</i>"
// Create a radio headset for the sole purpose of using its icon
var/obj/item/radio/headset/radio = new
var/part_b = "</span><b> [bicon(radio)]\[[freq_text]\][part_b_extra]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_blackbox_b = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
var/part_c = "</span></span>"
var/blackbox_msg = "[part_a][source][part_blackbox_b]\"[text]\"[part_c]"
//BR.messages_admin += blackbox_admin_msg
if(istype(blackbox))
switch(display_freq)
if(PUB_FREQ)
blackbox.msg_common += blackbox_msg
if(SCI_FREQ)
blackbox.msg_science += blackbox_msg
if(COMM_FREQ)
blackbox.msg_command += blackbox_msg
if(MED_FREQ)
blackbox.msg_medical += blackbox_msg
if(ENG_FREQ)
blackbox.msg_engineering += blackbox_msg
if(SEC_FREQ)
blackbox.msg_security += blackbox_msg
if(DTH_FREQ)
blackbox.msg_deathsquad += blackbox_msg
if(SYND_FREQ)
blackbox.msg_syndicate += blackbox_msg
if(RAID_FREQ)
blackbox.msg_raider += blackbox_msg
if(SUP_FREQ)
blackbox.msg_cargo += blackbox_msg
if(SRV_FREQ)
blackbox.msg_service += blackbox_msg
else
blackbox.messages += blackbox_msg
//End of research and feedback code.
/* ###### Send the message ###### */
/* --- Process all the mobs that heard the voice normally (understood) --- */
if(length(heard_normal))
var/rendered = "[part_a][source][part_b]\"[text]\"[part_c]"
for (var/mob/R in heard_normal)
R.show_message(rendered, 2)
/* --- Process all the mobs that heard a garbled voice (did not understand) --- */
// Displays garbled message (ie "f*c* **u, **i*er!")
if(length(heard_garbled))
var/quotedmsg = "\"[stars(text)]\""
var/rendered = "[part_a][source][part_b][quotedmsg][part_c]"
for (var/mob/R in heard_garbled)
R.show_message(rendered, 2)
/* --- Complete gibberish. Usually happens when there's a compressed message --- */
if(length(heard_gibberish))
var/quotedmsg = "\"[Gibberish(text, compression + 50)]\""
var/rendered = "[part_a][Gibberish(source, compression + 50)][part_b][quotedmsg][part_c]"
for (var/mob/R in heard_gibberish)
R.show_message(rendered, 2)
#undef TELECOMMS_RECEPTION_NONE
#undef TELECOMMS_RECEPTION_SENDER
#undef TELECOMMS_RECEPTION_RECEIVER
#undef TELECOMMS_RECEPTION_BOTH

View File

@@ -1,40 +1,37 @@
// ### Preset machines ###
//Relay
/obj/machinery/telecomms/relay/preset
network = "tcommsat"
/obj/machinery/telecomms/relay/preset/station
id = "Station Relay"
listening_level = 1
autolinkers = list("s_relay")
/obj/machinery/telecomms/relay/preset/telecomms
id = "Telecomms Relay"
autolinkers = list("relay")
/obj/machinery/telecomms/relay/preset/mining
id = "Mining Relay"
autolinkers = list("m_relay")
/obj/machinery/telecomms/relay/preset/ruskie
id = "Ruskie Relay"
hide = 1
toggled = 0
hide = TRUE
toggled = FALSE
autolinkers = list("r_relay")
/obj/machinery/telecomms/relay/preset/centcom
id = "CentCom Relay"
hide = 1
toggled = 1
//anchored = 1
//use_power = 0
//idle_power_usage = 0
produces_heat = 0
hide = TRUE
toggled = TRUE
produces_heat = FALSE
autolinkers = list("c_relay")
//HUB
/obj/machinery/telecomms/hub/preset
id = "Hub"
@@ -43,14 +40,14 @@
"supply", "service", "common", "command", "engineering", "security", "unused",
"receiverA", "broadcasterA")
/obj/machinery/telecomms/hub/preset_cent
id = "CentCom Hub"
network = "tcommsat"
produces_heat = 0
produces_heat = FALSE
autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay",
"centcom", "receiverCent", "broadcasterCent")
//Receivers
/obj/machinery/telecomms/receiver/preset_right
id = "Receiver A"
@@ -58,40 +55,42 @@
autolinkers = list("receiverA") // link to relay
freq_listening = list(AI_FREQ, SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ, ENT_FREQ)
//Common and other radio frequencies for people to freely use
/obj/machinery/telecomms/receiver/preset_right/Initialize()
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
for(var/i = PUBLIC_LOW_FREQ to PUBLIC_HIGH_FREQ step 2)
freq_listening |= i
. = ..()
return ..()
/obj/machinery/telecomms/receiver/preset_cent
id = "CentCom Receiver"
network = "tcommsat"
produces_heat = 0
produces_heat = FALSE
autolinkers = list("receiverCent")
freq_listening = list(ERT_FREQ, DTH_FREQ, SYND_FREQ)
//Buses
/obj/machinery/telecomms/bus/preset_one
id = "Bus 1"
network = "tcommsat"
freq_listening = list(SCI_FREQ, MED_FREQ)
autolinkers = list("processor1", "science", "medical")
/obj/machinery/telecomms/bus/preset_two
id = "Bus 2"
network = "tcommsat"
freq_listening = list(SUP_FREQ, SRV_FREQ)
autolinkers = list("processor2", "supply", "service", "unused")
/obj/machinery/telecomms/bus/preset_two/Initialize()
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
if(i == PUB_FREQ)
for(var/i = PUBLIC_LOW_FREQ to PUBLIC_HIGH_FREQ step 2)
if (i == PUB_FREQ)
continue
freq_listening |= i
. = ..()
return ..()
/obj/machinery/telecomms/bus/preset_three
id = "Bus 3"
@@ -99,124 +98,134 @@
freq_listening = list(SEC_FREQ, COMM_FREQ)
autolinkers = list("processor3", "security", "command")
/obj/machinery/telecomms/bus/preset_four
id = "Bus 4"
network = "tcommsat"
freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ, ENT_FREQ)
autolinkers = list("processor4", "engineering", "common")
/obj/machinery/telecomms/bus/preset_cent
id = "CentCom Bus"
network = "tcommsat"
freq_listening = list(ERT_FREQ, DTH_FREQ, SYND_FREQ)
produces_heat = 0
produces_heat = FALSE
autolinkers = list("processorCent", "centcom")
//Processors
/obj/machinery/telecomms/processor/preset_one
id = "Processor 1"
network = "tcommsat"
autolinkers = list("processor1") // processors are sort of isolated; they don't need backward links
autolinkers = list("processor1")
/obj/machinery/telecomms/processor/preset_two
id = "Processor 2"
network = "tcommsat"
autolinkers = list("processor2")
/obj/machinery/telecomms/processor/preset_three
id = "Processor 3"
network = "tcommsat"
autolinkers = list("processor3")
/obj/machinery/telecomms/processor/preset_four
id = "Processor 4"
network = "tcommsat"
autolinkers = list("processor4")
/obj/machinery/telecomms/processor/preset_cent
id = "CentCom Processor"
network = "tcommsat"
produces_heat = 0
produces_heat = FALSE
autolinkers = list("processorCent")
//Servers
/obj/machinery/telecomms/server/presets
network = "tcommsat"
/obj/machinery/telecomms/server/presets/science
id = "Science Server"
freq_listening = list(SCI_FREQ)
autolinkers = list("science")
/obj/machinery/telecomms/server/presets/medical
id = "Medical Server"
freq_listening = list(MED_FREQ)
autolinkers = list("medical")
/obj/machinery/telecomms/server/presets/supply
id = "Supply Server"
freq_listening = list(SUP_FREQ)
autolinkers = list("supply")
/obj/machinery/telecomms/server/presets/service
id = "Service Server"
freq_listening = list(SRV_FREQ)
autolinkers = list("service")
/obj/machinery/telecomms/server/presets/common
id = "Common Server"
freq_listening = list(PUB_FREQ, AI_FREQ, ENT_FREQ) // AI Private and Common
freq_listening = list(PUB_FREQ, AI_FREQ, ENT_FREQ)
autolinkers = list("common")
// "Unused" channels, AKA all others.
/obj/machinery/telecomms/server/presets/unused
id = "Unused Server"
freq_listening = list()
autolinkers = list("unused")
/obj/machinery/telecomms/server/presets/unused/Initialize()
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
if(i == AI_FREQ || i == PUB_FREQ)
for(var/i = PUBLIC_LOW_FREQ to PUBLIC_HIGH_FREQ step 2)
if (i == AI_FREQ || i == PUB_FREQ)
continue
freq_listening |= i
. = ..()
return ..()
/obj/machinery/telecomms/server/presets/command
id = "Command Server"
freq_listening = list(COMM_FREQ)
autolinkers = list("command")
/obj/machinery/telecomms/server/presets/engineering
id = "Engineering Server"
freq_listening = list(ENG_FREQ)
autolinkers = list("engineering")
/obj/machinery/telecomms/server/presets/security
id = "Security Server"
freq_listening = list(SEC_FREQ)
autolinkers = list("security")
/obj/machinery/telecomms/server/presets/centcomm
id = "CentCom Server"
freq_listening = list(ERT_FREQ, DTH_FREQ, SYND_FREQ)
produces_heat = 0
produces_heat = FALSE
autolinkers = list("centcom")
//Broadcasters
//--PRESET LEFT--//
/obj/machinery/telecomms/broadcaster/preset_right
id = "Broadcaster A"
network = "tcommsat"
autolinkers = list("broadcasterA")
/obj/machinery/telecomms/broadcaster/preset_cent
id = "CentCom Broadcaster"
network = "tcommsat"
produces_heat = 0
autolinkers = list("broadcasterCent")
produces_heat = FALSE
autolinkers = list("broadcasterCent")

View File

@@ -0,0 +1,27 @@
/obj/machinery/telecomms/processor
name = "Processor Unit"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "processor"
desc = "This machine is used to process large quantities of information."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 3
delay = 5
circuit = /obj/item/circuitboard/telecomms/processor
var/uncompress = TRUE // When FALSE, compress signals instead
/obj/machinery/telecomms/processor/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (!is_freq_listening(signal))
return
if (uncompress)
signal.data["compression"] = 0
else
signal.data["compression"] = 100
if (istype(sender, /obj/machinery/telecomms/bus))
relay_direct_information(signal, sender)
else
signal.data["slow"] += rand(5, 10)
relay_information(signal, /obj/machinery/telecomms/server)

View File

@@ -0,0 +1,89 @@
/* Telecomms Receiver
* The receiver idles and receives messages from subspace-compatible radio equipment;
* primarily headsets. They then just relay this information to all linked devices,
* which can would probably be network hubs. Link to Processor Units in case receiver
* can't send to bus units.
*/
/obj/machinery/telecomms/receiver
name = "Subspace Receiver"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "broadcast receiver"
desc = "This machine has a dish-like shape and green lights. It is designed to detect and process subspace radio activity."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 1
produces_heat = 0
circuit = /obj/item/circuitboard/telecomms/receiver
interact_offline = TRUE
var/list/linked_radios_weakrefs = list()
var/overmap_range = 0
var/overmap_range_min = 0
var/overmap_range_max = 5
/obj/machinery/telecomms/receiver/proc/link_radio(obj/item/radio/radio)
if (!istype(radio))
return
linked_radios_weakrefs |= weakref(radio)
/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal)
if (!on)
return
if (!signal)
return
if (!check_receive_level(signal))
return
if (signal.transmission_method != TRANSMISSION_SUBSPACE)
return
if (!is_freq_listening(signal))
return
signal.data["level"] = list()
var/send_succeeded = relay_information(signal, /obj/machinery/telecomms/hub)
if (send_succeeded)
return
relay_information(signal, /obj/machinery/telecomms/bus)
/obj/machinery/telecomms/receiver/proc/check_receive_level(datum/signal/signal)
if (signal.transmission_method == TRANSMISSION_BLUESPACE)
var/obj/item/radio/radio = signal.data["radio"]
if (!(weakref(radio) in linked_radios_weakrefs))
signal.data["reject"] = TRUE
return FALSE
signal.data["level"] = z
signal.transmission_method = TRANSMISSION_SUBSPACE
return TRUE
var/list/listening_levels = using_map.get_map_levels(listening_level, TRUE, overmap_range)
if (signal.data["level"] in listening_levels)
return TRUE
for (var/obj/machinery/telecomms/hub/hub in links)
var/list/relayed_levels = list()
for (var/obj/machinery/telecomms/relay/relay in hub.links)
if (relay.can_receive(signal))
relayed_levels |= relay.listening_level
if (signal.data["level"] in relayed_levels)
return TRUE
return FALSE
/obj/machinery/telecomms/receiver/OptionsMenu()
var/list/data = ..()
data["use_receive_range"] = TRUE
data["range"] = overmap_range
data["minRange"] = overmap_range_min
data["maxRange"] = overmap_range_max
return data
/obj/machinery/telecomms/receiver/OptionsHandler(action, params)
if (..())
return TRUE
switch (action)
if ("range")
var/new_range = params["range"]
overmap_range = clamp(new_range, overmap_range_min, overmap_range_max)
update_idle_power_usage(initial(idle_power_usage) ** (overmap_range + 1))

View File

@@ -0,0 +1,79 @@
/* Telecomms Relay
* The relay idles until it receives information. It then passes on that information
* depending on where it came from. The relay is needed in order to send information
* pass Z levels. It must be linked with a HUB, the only other machine that can
* send/receive pass Z levels.
*/
/obj/machinery/telecomms/relay
name = "Telecommunication Relay"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "relay"
desc = "A mighty piece of hardware used to send massive amounts of data far away."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 8
produces_heat = TRUE
circuit = /obj/item/circuitboard/telecomms/relay
netspeed = 5
long_range_link = TRUE
var/broadcasting = TRUE
var/receiving = TRUE
/obj/machinery/telecomms/relay/forceMove(newloc)
. = ..(newloc)
listening_level = z
/obj/machinery/telecomms/relay/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (can_send(signal))
signal.data["level"] |= using_map.get_map_levels(listening_level)
/obj/machinery/telecomms/relay/OptionsMenu()
var/list/data = ..()
data["use_broadcasting"] = TRUE
data["use_receiving"] = TRUE
data["broadcasting"] = broadcasting
data["receiving"] = receiving
return data
/obj/machinery/telecomms/relay/OptionsHandler(action, params)
if (..())
return TRUE
switch (action)
if ("receive")
. = TRUE
receiving = !receiving
set_temp("-% Receiving mode changed. %-", "average")
if ("broadcast")
. = TRUE
broadcasting = !broadcasting
set_temp("-% Broadcasting mode changed. %-", "average")
/obj/machinery/telecomms/relay/proc/can(datum/signal/signal)
if (!on)
return FALSE
if (!listening_level)
return FALSE
if (!is_freq_listening(signal))
return FALSE
return TRUE
/obj/machinery/telecomms/relay/proc/can_send(datum/signal/signal)
if (!can(signal))
return FALSE
return broadcasting
/obj/machinery/telecomms/relay/proc/can_receive(datum/signal/signal)
if (!can(signal))
return FALSE
return receiving

View File

@@ -0,0 +1,109 @@
/obj/machinery/telecomms/server
name = "Telecommunication Server"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "comm_server"
desc = "A machine used to store data and network statistics."
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 300
machinetype = 4
circuit = /obj/item/circuitboard/telecomms/server
var/list/stored_names = list()
var/list/TrafficActions = list()
var/list/log_entries = list()
var/logs = 0 // number of logs
var/max_logs = 400 // maximum number of logs
var/log_cull_count = 10 // number of logs to cull at a time
var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes)
var/encryption = "null" // encryption key: ie "password"
var/salt = "null" // encryption salt: ie "123comsat"
var/obj/item/radio/headset/server_radio
/obj/machinery/telecomms/server/Destroy()
QDEL_NULL_LIST(log_entries)
QDEL_NULL(server_radio)
return ..()
/obj/machinery/telecomms/server/Initialize()
server_radio = new
return ..()
/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
if (!signal.data["message"])
return
if (is_freq_listening(signal))
if (traffic > 0)
totaltraffic += traffic
if (signal.data["type"] != SIGNAL_TEST)
update_logs()
var/datum/comm_log_entry/log = new
var/mob/M = signal.data["mob"]
log.parameters["mobtype"] = signal.data["mobtype"]
log.parameters["job"] = signal.data["job"]
log.parameters["key"] = signal.data["key"]
log.parameters["vmessage"] = multilingual_to_message(signal.data["message"])
log.parameters["vname"] = signal.data["vname"]
log.parameters["message"] = multilingual_to_message(signal.data["message"])
log.parameters["name"] = signal.data["name"]
log.parameters["realname"] = signal.data["realname"]
log.parameters["timecode"] = worldtime2stationtime(world.time)
var/race = "unknown"
if (ishuman(M))
var/mob/living/carbon/human/H = M
race = "[H.species.name]"
log.parameters["intelligible"] = TRUE
else if (isbrain(M))
race = "Brain"
log.parameters["intelligible"] = TRUE
else if (M.isMonkey())
race = "Monkey"
else if (issilicon(M))
race = "Artificial Life"
log.parameters["intelligible"] = TRUE
else if (isslime(M))
race = "Slime"
else if (isanimal(M))
race = "Domestic Animal"
log.parameters["race"] = race
if (M && !istype(M, /mob/new_player))
log.parameters["uspeech"] = M.universal_speak
else
log.parameters["uspeech"] = FALSE
if (signal.data["compression"] > 0) // If the signal is still compressed, make the log entry gibberish
log.parameters["message"] = Gibberish(multilingual_to_message(signal.data["message"]), signal.data["compression"] + 50)
log.parameters["job"] = Gibberish(signal.data["job"], signal.data["compression"] + 50)
log.parameters["name"] = Gibberish(signal.data["name"], signal.data["compression"] + 50)
log.parameters["realname"] = Gibberish(signal.data["realname"], signal.data["compression"] + 50)
log.parameters["vname"] = Gibberish(signal.data["vname"], signal.data["compression"] + 50)
log.input_type = "Corrupt File"
log_entries += log
if (!(signal.data["name"] in stored_names))
stored_names += signal.data["name"]
logs++
signal.data["server"] = src
var/identifier = num2text(rand(-1000, 1000) + world.time)
log.name = "data packet ([sha1(identifier)])"
var/send_success = relay_information(signal, /obj/machinery/telecomms/hub)
if (!send_success)
relay_information(signal, /obj/machinery/telecomms/broadcaster)
/obj/machinery/telecomms/server/proc/add_entry(content, input)
var/datum/comm_log_entry/log = new
var/identifier = num2text(rand(-1000, 1000) + world.time)
log.name = "[input] ([sha1(identifier)])"
log.input_type = input
log.parameters["message"] = content
log.parameters["timecode"] = stationtime2text()
log_entries += log
update_logs()
/obj/machinery/telecomms/server/proc/update_logs()
if (logs >= max_logs)
log_entries.Cut(0, log_cull_count)
logs -= log_cull_count

View File

@@ -0,0 +1,380 @@
/obj/machinery/telecomms
icon = 'icons/obj/stationobjs.dmi'
var/list/links = list() // list of machines this machine is linked to
var/traffic = 0 // value increases as traffic increases
var/netspeed = 5 // how much traffic to lose per tick (50 gigabytes/second * netspeed)
var/list/autolinkers = list() // list of text/number values to link with
var/id = "NULL" // identification string
var/network = "NULL" // the network of the machinery
var/list/freq_listening = list() // list of frequencies to tune into: if none, will listen to all
var/machinetype = 0 // just a hacky way of preventing alike machines from pairing
var/toggled = TRUE // Is it toggled on
var/on = TRUE
var/integrity = 100 // basically HP, loses integrity by heat
var/produces_heat = TRUE //whether the machine will produce heat when on.
var/delay = 10 // how many process() ticks to delay per heat
var/long_range_link = 0 // Can you link it across Z levels or on the otherside of the map? (Relay & Hub)
var/hide = FALSE // Is it a hidden machine?
var/listening_level = 0 // 0 = auto set in New() - this is the z level that the machine is listening to.
var/list/temp // output message for interactions
/obj/machinery/telecomms/Destroy()
telecomms_list -= src
for(var/obj/machinery/telecomms/comm in telecomms_list)
comm.links -= src
links = list()
return ..()
/obj/machinery/telecomms/Initialize()
telecomms_list += src
..()
default_apply_parts()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/telecomms/LateInitialize()
if (!listening_level)
var/turf/position = get_turf(src)
listening_level = position.z
if (!length(autolinkers))
return
var/list/linkables = telecomms_list
if (!long_range_link)
linkables = orange(20, src)
for (var/obj/machinery/telecomms/machine in linkables)
add_link(machine)
/obj/machinery/telecomms/attackby(obj/item/P, mob/user)
if (istype(P, /obj/item/multitool))
attack_hand(user)
if (istype(P, /obj/item/stack/nanopaste))
var/obj/item/stack/nanopaste/T = P
if (integrity < 100)
if (T.use(1))
integrity = between(0, integrity + rand(10, 20), 100)
to_chat(usr, "You apply the Nanopaste to [src], repairing some of the damage.")
else
to_chat(usr, "This machine is already in perfect condition.")
return
if (default_deconstruction_screwdriver(user, P))
return
if (default_deconstruction_crowbar(user, P))
return
/obj/machinery/telecomms/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/telecomms/attack_hand(mob/user)
tgui_interact(user)
/obj/machinery/telecomms/emp_act(severity)
if (prob(100 / severity))
if (!(stat & EMPED))
stat |= EMPED
var/duration = (300 * 10) / severity
spawn(rand(duration - 20, duration + 20))
stat &= ~EMPED
..()
/obj/machinery/telecomms/process()
update_power()
checkheat()
update_icon()
if (traffic > 0)
traffic -= netspeed
/obj/machinery/telecomms/tgui_act(action, params)
if (..())
return TRUE
var/obj/item/multitool/P = get_multitool(usr)
switch (action)
if ("toggle")
toggled = !toggled
set_temp("-% [src] has been [toggled ? "activated" : "deactivated"].", "average")
update_power()
. = TRUE
if ("id")
var/response = input(usr, "Specify the new ID for this machine", src, id) as null | text
var/newid = copytext(reject_bad_text(response), 1, MAX_MESSAGE_LEN)
if(newid && canAccess(usr))
id = newid
set_temp("-% New ID assigned: \"[id]\" %-", "average")
. = TRUE
if ("network")
var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null | text
if (newnet && canAccess(usr))
if (length(newnet) > 15)
set_temp("-% Too many characters in new network tag %-", "average")
else
for (var/obj/machinery/telecomms/T in links)
T.links -= src
network = newnet
links = list()
set_temp("-% New network tag assigned: \"[network]\" %-", "average")
. = TRUE
if ("freq")
var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null | num
if (newfreq && canAccess(usr))
if (findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if (!(newfreq in freq_listening) && newfreq < 10000)
freq_listening += newfreq
set_temp("-% New frequency filter assigned: \"[newfreq] GHz\" %-", "average")
. = TRUE
if ("delete")
var/x = text2num(params["delete"])
set_temp("-% Removed frequency filter [x] %-", "average")
freq_listening-= x
. = TRUE
if ("unlink")
if (text2num(params["unlink"]) <= length(links))
var/obj/machinery/telecomms/T = links[text2num(params["unlink"])]
set_temp("-% Removed \ref[T] [T.name] from linked entities. %-", "average")
if (src in T.links)
T.links -= src
links -= T
. = TRUE
if ("link")
if (P)
if (P.buffer && P.buffer != src)
if (!(src in P.buffer.links))
P.buffer.links += src
if (!(P.buffer in links))
links += P.buffer
set_temp("-% Successfully linked with \ref[P.buffer] [P.buffer.name] %-", "average")
else
set_temp("-% Unable to acquire buffer %-", "average")
. = TRUE
if ("buffer")
P.buffer = src
set_temp("-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-", "average")
. = TRUE
if ("flush")
set_temp("-% Buffer successfully flushed. %-", "average")
P.buffer = null
. = TRUE
if ("cleartemp")
temp = null
. = TRUE
if (OptionsHandler(action, params))
. = TRUE
add_fingerprint(usr)
/obj/machinery/telecomms/tgui_data(mob/user)
var/list/data = list()
data["temp"] = temp
data["on"] = on
data["id"] = null
data["network"] = null
data["autolinkers"] = FALSE
data["shadowlink"] = FALSE
data["options"] = list()
data["linked"] = list()
data["filter"] = list()
data["multitool"] = FALSE
data["multitool_buffer"] = null
if (on || interact_offline)
data["id"] = id
data["network"] = network
data["autolinkers"] = !!LAZYLEN(autolinkers)
data["shadowlink"] = !!hide
data["options"] = OptionsMenu()
var/obj/item/multitool/P = get_multitool(user)
data["multitool"] = !!P
data["multitool_buffer"] = null
if (P && P.buffer)
P.update_icon()
data["multitool_buffer"] = list("name" = "[P.buffer]", "id" = "[P.buffer.id]")
var/i = 0
var/list/linked = list()
for (var/obj/machinery/telecomms/T in links)
i++
linked += list(list(
"ref" = "\ref[T]",
"name" = "[T]",
"id" = T.id,
"index" = i,
))
data["linked"] = linked
var/list/filter = list()
if (length(freq_listening))
for (var/x in freq_listening)
filter += list(list(
"name" = "[format_frequency(x)]",
"freq" = x,
))
data["filter"] = filter
return data
/obj/machinery/telecomms/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "TelecommsMultitoolMenu", name)
ui.open()
/obj/machinery/telecomms/tgui_status(mob/user)
if (!issilicon(user))
if (!istype(user.get_active_hand(), /obj/item/multitool))
return STATUS_CLOSE
return ..()
/obj/machinery/telecomms/update_icon()
if (on)
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]_off"
/obj/machinery/telecomms/proc/add_link(obj/machinery/telecomms/machine)
if (machine == src)
return
if (machine in links)
return
var/src_z = get_z(src)
var/machine_z = get_z(machine)
if (src_z != machine_z && !(long_range_link && machine.long_range_link))
return
for (var/entry in autolinkers)
if (entry in machine.autolinkers)
links |= machine
break
/obj/machinery/telecomms/proc/canAccess(mob/user)
return issilicon(user) || in_range(user, src)
/obj/machinery/telecomms/proc/checkheat()
var/turf/simulated/turf = get_turf(src)
if (!istype(turf))
return
var/datum/gas_mixture/environment = turf.return_air()
var/damage_chance = 0
switch(environment.temperature)
if ((T0C + 40) to (T0C + 70))
damage_chance = 10
if ((T0C + 70) to (T0C + 130))
damage_chance = 25
if ((T0C + 130) to (T0C + 200))
damage_chance = 50
if ((T0C + 200) to INFINITY)
damage_chance = 100
if (damage_chance && prob(damage_chance))
integrity = between(0, integrity - 1, 100)
if (delay > 0)
delay--
else if (on)
produce_heat()
delay = initial(delay)
/obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal)
if (!signal)
return FALSE
if (!length(freq_listening) || (signal.frequency in freq_listening))
return TRUE
return FALSE
/obj/machinery/telecomms/proc/produce_heat()
if (!produces_heat)
return
if (!use_power)
return
if (stat & (NOPOWER|BROKEN))
return
var/turf/simulated/turf = get_turf(src)
if (!istype(turf))
return
var/datum/gas_mixture/env = turf.return_air()
var/transfer_moles = 0.25 * env.total_moles
var/datum/gas_mixture/removed = env.remove(transfer_moles)
if (removed)
var/heat_produced = idle_power_usage
if (traffic <= 0)
heat_produced *= 0.30
removed.add_thermal_energy(heat_produced)
env.merge(removed)
/obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/sender)
return
/obj/machinery/telecomms/proc/relay_direct_information(datum/signal/signal, obj/machinery/telecomms/receiver)
receiver.receive_information(signal, src)
/obj/machinery/telecomms/proc/relay_information(datum/signal/signal, filter, copysig, amount = 20)
if (!on)
return
var/send_count = 0
signal.data["slow"] += rand(0, round(100 - integrity))
for (var/obj/machinery/telecomms/machine in links)
if (filter && !istype(machine, filter))
continue
if (!machine.on)
continue
if (amount && send_count >= amount)
break
if (machine.loc.z != listening_level)
if (!long_range_link && !machine.long_range_link)
continue
var/datum/signal/copy
if (copysig)
copy = new
copy.transmission_method = TRANSMISSION_SUBSPACE
copy.frequency = signal.frequency
copy.data = signal.data.Copy()
if (!signal.data["original"])
copy.data["original"] = signal
else
copy.data["original"] = signal.data["original"]
send_count++
if (machine.is_freq_listening(signal))
machine.traffic++
if (copysig && copy)
machine.receive_information(copy, src)
else
machine.receive_information(signal, src)
if (send_count > 0 && is_freq_listening(signal))
traffic++
return send_count
/obj/machinery/telecomms/proc/set_temp(text, color = "average")
temp = list("color" = color, "text" = text)
/obj/machinery/telecomms/proc/update_power()
if (integrity < 1)
on = FALSE
else if (stat & (BROKEN|NOPOWER|EMPED))
on = FALSE
else
on = toggled
/* Additional interface options for certain machines. Eg:
* /obj/machinery/telecomms/processor/OptionsMenu()
* return "<br>Processing Mode: <A href='?src=\ref[src];process=1'>[uncompress ? "UNCOMPRESS" : "COMPRESS"]</a>"
*/
/obj/machinery/telecomms/proc/OptionsMenu()
return list()
/// Topic handler for OptionsMenu href links.
/obj/machinery/telecomms/proc/OptionsHandler(action, params)
return

View File

@@ -1,691 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/*
Hello, friends, this is Doohl from sexylands. You may be wondering what this
monstrous code file is. Sit down, boys and girls, while I tell you the tale.
The machines defined in this file were designed to be compatible with any radio
signals, provided they use subspace transmission. Currently they are only used for
headsets, but they can eventually be outfitted for real COMPUTER networks. This
is just a skeleton, ladies and gentlemen.
Look at radio.dm for the prequel to this code.
*/
var/global/list/obj/machinery/telecomms/telecomms_list = list()
/obj/machinery/telecomms
icon = 'icons/obj/stationobjs.dmi'
var/list/links = list() // list of machines this machine is linked to
var/traffic = 0 // value increases as traffic increases
var/netspeed = 5 // how much traffic to lose per tick (50 gigabytes/second * netspeed)
var/list/autolinkers = list() // list of text/number values to link with
var/id = "NULL" // identification string
var/network = "NULL" // the network of the machinery
var/list/freq_listening = list() // list of frequencies to tune into: if none, will listen to all
var/machinetype = 0 // just a hacky way of preventing alike machines from pairing
var/toggled = 1 // Is it toggled on
var/on = 1
var/integrity = 100 // basically HP, loses integrity by heat
var/produces_heat = 1 //whether the machine will produce heat when on.
var/delay = 10 // how many process() ticks to delay per heat
var/long_range_link = 0 // Can you link it across Z levels or on the otherside of the map? (Relay & Hub)
var/hide = 0 // Is it a hidden machine?
var/listening_level = 0 // 0 = auto set in New() - this is the z level that the machine is listening to.
/obj/machinery/telecomms/proc/relay_information(datum/signal/signal, filter, copysig, amount = 20)
// relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending
if(!on)
return
//to_world("[src] ([src.id]) - [signal.debug_print()]")
var/send_count = 0
signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity
/*
// Edit by Atlantis: Commented out as emergency fix due to causing extreme delays in communications.
// Apply some lag based on traffic rates
var/netlag = round(traffic / 50)
if(netlag > signal.data["slow"])
signal.data["slow"] = netlag
*/
// Loop through all linked machines and send the signal or copy.
for(var/obj/machinery/telecomms/machine in links)
if(filter && !istype(machine, filter))
continue
if(!machine.on)
continue
if(amount && send_count >= amount)
break
if(machine.loc.z != listening_level)
if(long_range_link == 0 && machine.long_range_link == 0)
continue
// If we're sending a copy, be sure to create the copy for EACH machine and paste the data
var/datum/signal/copy
if(copysig)
copy = new
copy.transmission_method = TRANSMISSION_SUBSPACE
copy.frequency = signal.frequency
copy.data = signal.data.Copy()
// Keep the "original" signal constant
if(!signal.data["original"])
copy.data["original"] = signal
else
copy.data["original"] = signal.data["original"]
send_count++
if(machine.is_freq_listening(signal))
machine.traffic++
if(copysig && copy)
machine.receive_information(copy, src)
else
machine.receive_information(signal, src)
if(send_count > 0 && is_freq_listening(signal))
traffic++
return send_count
/obj/machinery/telecomms/proc/relay_direct_information(datum/signal/signal, obj/machinery/telecomms/machine)
// send signal directly to a machine
machine.receive_information(signal, src)
/obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
// receive information from linked machinery
return
/obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal)
// return 1 if found, 0 if not found
if(!signal)
return 0
if((signal.frequency in freq_listening) || (!freq_listening.len))
return 1
else
return 0
/obj/machinery/telecomms/Initialize()
telecomms_list += src
..()
default_apply_parts()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/telecomms/LateInitialize()
. = ..()
//Set the listening_level if there's none.
if(!listening_level)
//Defaults to our Z level!
var/turf/position = get_turf(src)
listening_level = position.z
if(autolinkers.len)
// Links nearby machines
if(!long_range_link)
for(var/obj/machinery/telecomms/T in orange(20, src))
add_link(T)
else
for(var/obj/machinery/telecomms/T in telecomms_list)
add_link(T)
/obj/machinery/telecomms/Destroy()
telecomms_list -= src
for(var/obj/machinery/telecomms/comm in telecomms_list)
comm.links -= src
links = list()
..()
// Used in auto linking
/obj/machinery/telecomms/proc/add_link(var/obj/machinery/telecomms/T)
var/pos_z = get_z(src)
var/tpos_z = get_z(T)
if((pos_z == tpos_z) || (src.long_range_link && T.long_range_link))
for(var/x in autolinkers)
if(T.autolinkers.Find(x))
if(src != T)
links |= T
/obj/machinery/telecomms/update_icon()
if(on)
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]_off"
/obj/machinery/telecomms/proc/update_power()
if(toggled)
if(stat & (BROKEN|NOPOWER|EMPED) || integrity <= 0) // if powered, on. if not powered, off. if too damaged, off
on = 0
else
on = 1
else
on = 0
/obj/machinery/telecomms/process()
update_power()
// Check heat and generate some
checkheat()
// Update the icon
update_icon()
if(traffic > 0)
traffic -= netspeed
/obj/machinery/telecomms/emp_act(severity)
if(prob(100/severity))
if(!(stat & EMPED))
stat |= EMPED
var/duration = (300 * 10)/severity
spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot.
stat &= ~EMPED
..()
/obj/machinery/telecomms/proc/checkheat()
// Checks heat from the environment and applies any integrity damage
var/datum/gas_mixture/environment = loc.return_air()
var/damage_chance = 0 // Percent based chance of applying 1 integrity damage this tick
switch(environment.temperature)
if((T0C + 40) to (T0C + 70)) // 40C-70C, minor overheat, 10% chance of taking damage
damage_chance = 10
if((T0C + 70) to (T0C + 130)) // 70C-130C, major overheat, 25% chance of taking damage
damage_chance = 25
if((T0C + 130) to (T0C + 200)) // 130C-200C, dangerous overheat, 50% chance of taking damage
damage_chance = 50
if((T0C + 200) to INFINITY) // More than 200C, INFERNO. Takes damage every tick.
damage_chance = 100
if (damage_chance && prob(damage_chance))
integrity = between(0, integrity - 1, 100)
if(delay > 0)
delay--
else if(on)
produce_heat()
delay = initial(delay)
/obj/machinery/telecomms/proc/produce_heat()
if (!produces_heat)
return
if (!use_power)
return
if(!(stat & (NOPOWER|BROKEN)))
var/turf/simulated/L = loc
if(istype(L))
var/datum/gas_mixture/env = L.return_air()
var/transfer_moles = 0.25 * env.total_moles
var/datum/gas_mixture/removed = env.remove(transfer_moles)
if(removed)
var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source
if (traffic <= 0)
heat_produced *= 0.30 //if idle, produce less heat.
removed.add_thermal_energy(heat_produced)
env.merge(removed)
/*
The receiver idles and receives messages from subspace-compatible radio equipment;
primarily headsets. They then just relay this information to all linked devices,
which can would probably be network hubs.
Link to Processor Units in case receiver can't send to bus units.
*/
/obj/machinery/telecomms/receiver
name = "Subspace Receiver"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "broadcast receiver"
desc = "This machine has a dish-like shape and green lights. It is designed to detect and process subspace radio activity."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 1
produces_heat = 0
circuit = /obj/item/circuitboard/telecomms/receiver
//Vars only used if you're using the overmap
var/overmap_range = 0
var/overmap_range_min = 0
var/overmap_range_max = 5
var/list/linked_radios_weakrefs = list()
/obj/machinery/telecomms/receiver/proc/link_radio(var/obj/item/radio/R)
if(!istype(R))
return
linked_radios_weakrefs |= weakref(R)
/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal)
if(!on) // has to be on to receive messages
return
if(!signal)
return
if(!check_receive_level(signal))
return
if(signal.transmission_method == TRANSMISSION_SUBSPACE)
if(is_freq_listening(signal)) // detect subspace signals
//Remove the level and then start adding levels that it is being broadcasted in.
signal.data["level"] = list()
var/can_send = relay_information(signal, /obj/machinery/telecomms/hub) // ideally relay the copied information to relays
if(!can_send)
relay_information(signal, /obj/machinery/telecomms/bus) // Send it to a bus instead, if it's linked to one
/obj/machinery/telecomms/receiver/proc/check_receive_level(datum/signal/signal)
// If it's a direct message from a bluespace radio, we eat it and convert it into a subspace signal locally
if(signal.transmission_method == TRANSMISSION_BLUESPACE)
var/obj/item/radio/R = signal.data["radio"]
//Who're you?
if(!(weakref(R) in linked_radios_weakrefs))
signal.data["reject"] = 1
return 0
//We'll resend this for you
signal.data["level"] = z
signal.transmission_method = TRANSMISSION_SUBSPACE
return 1
//Where can we hear?
var/list/listening_levels = using_map.get_map_levels(listening_level, TRUE, overmap_range)
// We couldn't 'hear' it, maybe a relay linked to our hub can 'hear' it
if(!(signal.data["level"] in listening_levels))
for(var/obj/machinery/telecomms/hub/H in links)
var/list/relayed_levels = list()
for(var/obj/machinery/telecomms/relay/R in H.links)
if(R.can_receive(signal))
relayed_levels |= R.listening_level
if(signal.data["level"] in relayed_levels)
return 1
return 0
return 1
/*
The HUB idles until it receives information. It then passes on that information
depending on where it came from.
This is the heart of the Telecommunications Network, sending information where it
is needed. It mainly receives information from long-distance Relays and then sends
that information to be processed. Afterwards it gets the uncompressed information
from Servers/Buses and sends that back to the relay, to then be broadcasted.
*/
/obj/machinery/telecomms/hub
name = "Telecommunication Hub"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "hub"
desc = "A mighty piece of hardware used to send/receive massive amounts of data."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 1600
machinetype = 7
circuit = /obj/item/circuitboard/telecomms/hub
long_range_link = 1
netspeed = 40
/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(is_freq_listening(signal))
if(istype(machine_from, /obj/machinery/telecomms/receiver))
//If the signal is compressed, send it to the bus.
relay_information(signal, /obj/machinery/telecomms/bus, 1) // ideally relay the copied information to bus units
else
// Get a list of relays that we're linked to, then send the signal to their levels.
relay_information(signal, /obj/machinery/telecomms/relay, 1)
relay_information(signal, /obj/machinery/telecomms/broadcaster, 1) // Send it to a broadcaster.
/*
The relay idles until it receives information. It then passes on that information
depending on where it came from.
The relay is needed in order to send information pass Z levels. It must be linked
with a HUB, the only other machine that can send/receive pass Z levels.
*/
/obj/machinery/telecomms/relay
name = "Telecommunication Relay"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "relay"
desc = "A mighty piece of hardware used to send massive amounts of data far away."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 8
produces_heat = 0
circuit = /obj/item/circuitboard/telecomms/relay
netspeed = 5
long_range_link = 1
var/broadcasting = 1
var/receiving = 1
/obj/machinery/telecomms/relay/forceMove(var/newloc)
. = ..(newloc)
listening_level = z
/obj/machinery/telecomms/relay/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
// Add our level and send it back
if(can_send(signal))
signal.data["level"] |= using_map.get_map_levels(listening_level)
// Checks to see if it can send/receive.
/obj/machinery/telecomms/relay/proc/can(datum/signal/signal)
if(!on)
return 0
if(!is_freq_listening(signal))
return 0
return 1
/obj/machinery/telecomms/relay/proc/can_send(datum/signal/signal)
if(!can(signal))
return 0
return broadcasting
/obj/machinery/telecomms/relay/proc/can_receive(datum/signal/signal)
if(!can(signal))
return 0
return receiving
/*
The bus mainframe idles and waits for hubs to relay them signals. They act
as junctions for the network.
They transfer uncompressed subspace packets to processor units, and then take
the processed packet to a server for logging.
Link to a subspace hub if it can't send to a server.
*/
/obj/machinery/telecomms/bus
name = "Bus Mainframe"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "bus"
desc = "A mighty piece of hardware used to send massive amounts of data quickly."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 1000
machinetype = 2
circuit = /obj/item/circuitboard/telecomms/bus
netspeed = 40
var/change_frequency = 0
/obj/machinery/telecomms/bus/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(is_freq_listening(signal))
if(change_frequency)
signal.frequency = change_frequency
if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it
// send to one linked processor unit
var/send_to_processor = relay_information(signal, /obj/machinery/telecomms/processor)
if(send_to_processor)
return
// failed to send to a processor, relay information anyway
signal.data["slow"] += rand(1, 5) // slow the signal down only slightly
src.receive_information(signal, src)
// Try sending it!
var/list/try_send = list(/obj/machinery/telecomms/server, /obj/machinery/telecomms/hub, /obj/machinery/telecomms/broadcaster, /obj/machinery/telecomms/bus)
var/i = 0
for(var/send in try_send)
if(i)
signal.data["slow"] += rand(0, 1) // slow the signal down only slightly
i++
var/can_send = relay_information(signal, send)
if(can_send)
break
/*
The processor is a very simple machine that decompresses subspace signals and
transfers them back to the original bus. It is essential in producing audible
data.
Link to servers if bus is not present
*/
/obj/machinery/telecomms/processor
name = "Processor Unit"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "processor"
desc = "This machine is used to process large quantities of information."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 600
machinetype = 3
delay = 5
circuit = /obj/item/circuitboard/telecomms/processor
var/process_mode = 1 // 1 = Uncompress Signals, 0 = Compress Signals
/obj/machinery/telecomms/processor/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(is_freq_listening(signal))
if(process_mode)
signal.data["compression"] = 0 // uncompress subspace signal
else
signal.data["compression"] = 100 // even more compressed signal
if(istype(machine_from, /obj/machinery/telecomms/bus))
relay_direct_information(signal, machine_from) // send the signal back to the machine
else // no bus detected - send the signal to servers instead
signal.data["slow"] += rand(5, 10) // slow the signal down
relay_information(signal, /obj/machinery/telecomms/server)
/*
The server logs all traffic and signal data. Once it records the signal, it sends
it to the subspace broadcaster.
Store a maximum of 100 logs and then deletes them.
*/
/obj/machinery/telecomms/server
name = "Telecommunication Server"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "comm_server"
desc = "A machine used to store data and network statistics."
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 300
machinetype = 4
circuit = /obj/item/circuitboard/telecomms/server
var/list/log_entries = list()
var/list/stored_names = list()
var/list/TrafficActions = list()
var/logs = 0 // number of logs
var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes)
var/list/memory = list() // stored memory
var/rawcode = "" // the code to compile (raw text)
var/datum/TCS_Compiler/Compiler // the compiler that compiles and runs the code
var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up
var/encryption = "null" // encryption key: ie "password"
var/salt = "null" // encryption salt: ie "123comsat"
// would add up to md5("password123comsat")
var/obj/item/radio/headset/server_radio = null
/obj/machinery/telecomms/server/Initialize()
Compiler = new
Compiler.Holder = src
server_radio = new
. = ..()
/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(signal.data["message"])
if(is_freq_listening(signal))
if(traffic > 0)
totaltraffic += traffic // add current traffic to total traffic
//Is this a test signal? Bypass logging
if(signal.data["type"] != SIGNAL_TEST)
// If signal has a message and appropriate frequency
update_logs()
var/datum/comm_log_entry/log = new
var/mob/M = signal.data["mob"]
// Copy the signal.data entries we want
log.parameters["mobtype"] = signal.data["mobtype"]
log.parameters["job"] = signal.data["job"]
log.parameters["key"] = signal.data["key"]
log.parameters["vmessage"] = multilingual_to_message(signal.data["message"])
log.parameters["vname"] = signal.data["vname"]
log.parameters["message"] = multilingual_to_message(signal.data["message"])
log.parameters["name"] = signal.data["name"]
log.parameters["realname"] = signal.data["realname"]
log.parameters["timecode"] = worldtime2stationtime(world.time)
var/race = "unknown"
if(ishuman(M))
var/mob/living/carbon/human/H = M
race = "[H.species.name]"
log.parameters["intelligible"] = 1
else if(isbrain(M))
race = "Brain"
log.parameters["intelligible"] = 1
else if(M.isMonkey())
race = "Monkey"
else if(issilicon(M))
race = "Artificial Life"
log.parameters["intelligible"] = 1
else if(isslime(M))
race = "Slime"
else if(isanimal(M))
race = "Domestic Animal"
log.parameters["race"] = race
if(!istype(M, /mob/new_player) && M)
log.parameters["uspeech"] = M.universal_speak
else
log.parameters["uspeech"] = 0
// If the signal is still compressed, make the log entry gibberish
if(signal.data["compression"] > 0)
log.parameters["message"] = Gibberish(multilingual_to_message(signal.data["message"]), signal.data["compression"] + 50)
log.parameters["job"] = Gibberish(signal.data["job"], signal.data["compression"] + 50)
log.parameters["name"] = Gibberish(signal.data["name"], signal.data["compression"] + 50)
log.parameters["realname"] = Gibberish(signal.data["realname"], signal.data["compression"] + 50)
log.parameters["vname"] = Gibberish(signal.data["vname"], signal.data["compression"] + 50)
log.input_type = "Corrupt File"
// Log and store everything that needs to be logged
log_entries.Add(log)
if(!(signal.data["name"] in stored_names))
stored_names.Add(signal.data["name"])
logs++
signal.data["server"] = src
// Give the log a name
var/identifier = num2text( rand(-1000,1000) + world.time )
log.name = "data packet ([md5(identifier)])"
if(Compiler && autoruncode)
Compiler.Run(signal) // execute the code
var/can_send = relay_information(signal, /obj/machinery/telecomms/hub)
if(!can_send)
relay_information(signal, /obj/machinery/telecomms/broadcaster)
/obj/machinery/telecomms/server/proc/setcode(var/t)
if(t)
if(istext(t))
rawcode = t
/obj/machinery/telecomms/server/proc/compile()
if(Compiler)
return Compiler.Compile(rawcode)
/obj/machinery/telecomms/server/proc/update_logs()
// start deleting the very first log entry
if(logs >= 400)
for(var/i = 1, i <= logs, i++) // locate the first garbage collectable log entry and remove it
var/datum/comm_log_entry/L = log_entries[i]
if(L.garbage_collector)
log_entries.Remove(L)
logs--
break
/obj/machinery/telecomms/server/proc/add_entry(var/content, var/input)
var/datum/comm_log_entry/log = new
var/identifier = num2text( rand(-1000,1000) + world.time )
log.name = "[input] ([md5(identifier)])"
log.input_type = input
log.parameters["message"] = content
log.parameters["timecode"] = stationtime2text()
log_entries.Add(log)
update_logs()
// Simple log entry datum
/datum/comm_log_entry
var/parameters = list() // carbon-copy to signal.data[]
var/name = "data packet (#)"
var/garbage_collector = 1 // if set to 0, will not be garbage collected
var/input_type = "Speech File"
//Generic telecomm connectivity test proc
/proc/can_telecomm(var/atom/A, var/atom/B, var/ad_hoc = FALSE)
if(!A || !B)
log_debug("can_telecomm(): Undefined endpoints!")
return FALSE
//Can't in this case, obviously!
if(is_jammed(A) || is_jammed(B))
return FALSE
//Items don't have a Z when inside an object or mob
var/turf/src_z = get_z(A)
var/turf/dst_z = get_z(B)
//Nullspace, probably.
if(!src_z || !dst_z)
return FALSE
//We can do the simple check first, if you have ad_hoc radios.
if(ad_hoc && src_z == dst_z)
return TRUE
return src_z in using_map.get_map_levels(dst_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)

View File

@@ -1,128 +1,124 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/*
Telecomms monitor tracks the overall trafficing of a telecommunications network
and displays a heirarchy of linked machines.
/* Telecomms Monitor
* Tracks the overall trafficing of a telecommunications network and
* displays a heirarchy of linked machines.
*/
/obj/machinery/computer/telecomms/monitor
name = "Telecommunications Monitor"
desc = "Used to traverse a telecommunication network. Helpful for debugging connection issues."
icon_screen = "comm_monitor"
var/screen = 0 // the screen number:
var/list/machinelist = list() // the machines located by the computer
var/obj/machinery/telecomms/SelectedMachine
icon_keyboard = "tech_key"
circuit = /obj/item/circuitboard/comm_monitor
var/screen = 0 // the screen number
var/obj/machinery/telecomms/SelectedMachine
var/list/machinelist = list() // the machines located by the computer
var/network = "NULL" // the network to probe
var/list/temp // temporary feedback messages
var/network = "NULL" // the network to probe
var/list/temp = null // temporary feedback messages
/obj/machinery/computer/telecomms/monitor/Destroy()
LAZYCLEARLIST(machinelist)
SelectedMachine = null
return ..()
/obj/machinery/computer/telecomms/monitor/tgui_data(mob/user)
var/list/data = list()
data["network"] = network
data["temp"] = temp
var/list/machinelist = list()
for(var/obj/machinery/telecomms/T in src.machinelist)
machinelist.Add(list(list(
"id" = T.id,
"name" = T.name,
)))
data["machinelist"] = machinelist
data["selectedMachine"] = null
if(SelectedMachine)
data["selectedMachine"] = list(
"id" = SelectedMachine.id,
"name" = SelectedMachine.name,
)
var/list/links = list()
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
if(!T.hide)
links.Add(list(list(
"id" = T.id,
"name" = T.name
)))
data["selectedMachine"]["links"] = links
return data
/obj/machinery/computer/telecomms/monitor/attack_hand(mob/user)
if(stat & (BROKEN|NOPOWER))
if (stat & (BROKEN|NOPOWER))
return
tgui_interact(user)
/obj/machinery/computer/telecomms/monitor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TelecommsMachineBrowser", name)
ui.open()
/obj/machinery/computer/telecomms/monitor/emag_act(remaining_charges, mob/user)
if (emagged)
return
playsound(src, 'sound/effects/sparks4.ogg', 75, TRUE)
emagged = TRUE
to_chat(user, SPAN_NOTICE("You you disable the security protocols"))
updateUsrDialog()
return 1
/obj/machinery/computer/telecomms/monitor/tgui_act(action, params)
if(..())
if (..())
return TRUE
add_fingerprint(usr)
switch(action)
if("view")
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == params["id"])
SelectedMachine = T
switch (action)
if ("view")
for (var/obj/machinery/telecomms/machine in machinelist)
if (machine.id == params["id"])
SelectedMachine = machine
break
. = TRUE
if("mainmenu")
if ("mainmenu")
SelectedMachine = null
. = TRUE
if("release")
if ("release")
machinelist = list()
SelectedMachine = null
. = TRUE
if("scan")
if(machinelist.len > 0)
if ("scan")
if (length(machinelist))
set_temp("FAILED: CANNOT PROBE WHEN BUFFER FULL", "bad")
return TRUE
for(var/obj/machinery/telecomms/T in range(25, src))
if(T.network == network)
machinelist.Add(T)
if(!machinelist.len)
set_temp("FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\]", "bad")
else
for (var/obj/machinery/telecomms/machine in range(25, src))
if (machine.network == network)
machinelist += machine
if(length(machinelist))
set_temp("[machinelist.len] ENTITIES LOCATED & BUFFERED", "good")
else
set_temp("FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\]", "bad")
. = TRUE
if("network")
var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text
if(newnet && ((usr in range(1, src) || issilicon(usr))))
if(length(newnet) > 15)
if ("network")
var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null | text
if (newnet && (issilicon(usr) || (usr in range(1, src))))
if (length(newnet) > 15)
set_temp("FAILED: NETWORK TAG STRING TOO LENGTHY", "bad")
return TRUE
network = newnet
machinelist = list()
set_temp("NEW NETWORK TAG SET IN ADDRESS \[[network]\]", "good")
. = TRUE
if("cleartemp")
if ("cleartemp")
temp = null
. = TRUE
/obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
emagged = 1
to_chat(user, "<span class='notice'>You you disable the security protocols</span>")
src.updateUsrDialog()
return 1
/obj/machinery/computer/telecomms/monitor/tgui_data(mob/user)
var/list/data = list()
data["network"] = network
data["temp"] = temp
var/list/machinelist = list()
for (var/obj/machinery/telecomms/machine in machinelist)
machinelist += list(list(
"id" = machine.id,
"name" = machine.name,
))
data["machinelist"] = machinelist
data["selectedMachine"] = null
if (!SelectedMachine)
return data
data["selectedMachine"] = list(
"id" = SelectedMachine.id,
"name" = SelectedMachine.name,
)
var/list/links = list()
for (var/obj/machinery/telecomms/machine in SelectedMachine.links)
if (machine.hide)
continue
links += list(list(
"id" = machine.id,
"name" = machine.name
))
data["selectedMachine"]["links"] = links
return data
/obj/machinery/computer/telecomms/monitor/proc/set_temp(var/text, var/color = "average")
/obj/machinery/computer/telecomms/monitor/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "TelecommsMachineBrowser", name)
ui.open()
/obj/machinery/computer/telecomms/monitor/proc/set_temp(text, color = "average")
temp = list("color" = color, "text" = text)

View File

@@ -1,217 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/obj/machinery/computer/telecomms/traffic
name = "Telecommunications Traffic Control"
desc = "Used to upload code to telecommunication consoles for execution."
icon_screen = "generic"
var/screen = 0 // the screen number:
var/list/servers = list() // the servers located by the computer
var/mob/editingcode
var/mob/lasteditor
var/list/viewingcode = list()
var/obj/machinery/telecomms/server/SelectedServer
circuit = /obj/item/circuitboard/comm_traffic
req_access = list(access_tcomsat)
var/network = "NULL" // the network to probe
var/temp = "" // temporary feedback messages
var/storedcode = "" // code stored
/obj/machinery/computer/telecomms/traffic/proc/update_ide()
// loop if there's someone manning the keyboard
while(editingcode)
if(!editingcode.client)
editingcode = null
break
// For the typer, the input is enabled. Buffer the typed text
if(editingcode)
storedcode = "[winget(editingcode, "tcscode", "text")]"
if(editingcode) // double if's to work around a runtime error
winset(editingcode, "tcscode", "is-disabled=false")
// If the player's not manning the keyboard anymore, adjust everything
if( (!(editingcode in range(1, src)) && !issilicon(editingcode)) || (editingcode.machine != src && !issilicon(editingcode)))
if(editingcode)
winshow(editingcode, "Telecomms IDE", 0) // hide the window!
editingcode = null
break
// For other people viewing the typer type code, the input is disabled and they can only view the code
// (this is put in place so that there's not any magical shenanigans with 50 people inputting different code all at once)
if(length(viewingcode))
// This piece of code is very important - it escapes quotation marks so string aren't cut off by the input element
var/showcode = replacetext(storedcode, "\\\"", "\\\\\"")
showcode = replacetext(storedcode, "\"", "\\\"")
for(var/mob/M in viewingcode)
if( (M.machine == src && (M in view(1, src)) ) || issilicon(M))
winset(M, "tcscode", "is-disabled=true")
winset(M, "tcscode", "text=\"[showcode]\"")
else
viewingcode.Remove(M)
winshow(M, "Telecomms IDE", 0) // hide the window!
sleep(5)
if(length(viewingcode) > 0)
editingcode = pick(viewingcode)
viewingcode.Remove(editingcode)
update_ide()
/obj/machinery/computer/telecomms/traffic/attack_hand(mob/user as mob)
if(stat & (BROKEN|NOPOWER))
return
user.set_machine(src)
var/dat = "<TITLE>Telecommunication Traffic Control</TITLE><center><b>Telecommunications Traffic Control</b></center>"
switch(screen)
// --- Main Menu ---
if(0)
dat += "<br>[temp]<br>"
dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
if(servers.len)
dat += "<br>Detected Telecommunication Servers:<ul>"
for(var/obj/machinery/telecomms/T in servers)
dat += "<li><a href='?src=\ref[src];viewserver=[T.id]'>\ref[T] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=\ref[src];operation=release'>\[Flush Buffer\]</a>"
else
dat += "<br>No servers detected. Scan for servers: <a href='?src=\ref[src];operation=scan'>\[Scan\]</a>"
// --- Viewing Server ---
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=\ref[src];operation=refresh'>\[Refresh\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]<br><br>"
dat += "<br><a href='?src=\ref[src];operation=editcode'>\[Edit Code\]</a>"
dat += "<br>Signal Execution: "
if(SelectedServer.autoruncode)
dat += "<a href='?src=\ref[src];operation=togglerun'>ALWAYS</a>"
else
dat += "<a href='?src=\ref[src];operation=togglerun'>NEVER</a>"
user << browse(dat, "window=traffic_control;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/traffic/Topic(href, href_list)
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(!src.allowed(usr) && !emagged)
to_chat(usr, "<span class='warning'>ACCESS DENIED.</span>")
return
if(href_list["viewserver"])
screen = 1
for(var/obj/machinery/telecomms/T in servers)
if(T.id == href_list["viewserver"])
SelectedServer = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font>"
else
for(var/obj/machinery/telecomms/server/T in range(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font>"
screen = 0
if("editcode")
if(editingcode == usr) return
if(usr in viewingcode) return
if(!editingcode)
lasteditor = usr
editingcode = usr
winshow(editingcode, "Telecomms IDE", 1) // show the IDE
winset(editingcode, "tcscode", "is-disabled=false")
winset(editingcode, "tcscode", "text=\"\"")
var/showcode = replacetext(storedcode, "\\\"", "\\\\\"")
showcode = replacetext(storedcode, "\"", "\\\"")
winset(editingcode, "tcscode", "text=\"[showcode]\"")
spawn()
update_ide()
else
viewingcode.Add(usr)
winshow(usr, "Telecomms IDE", 1) // show the IDE
winset(usr, "tcscode", "is-disabled=true")
winset(editingcode, "tcscode", "text=\"\"")
var/showcode = replacetext(storedcode, "\"", "\\\"")
winset(usr, "tcscode", "text=\"[showcode]\"")
if("togglerun")
SelectedServer.autoruncode = !(SelectedServer.autoruncode)
if(href_list["network"])
var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text
if(newnet && ((usr in range(1, src) || issilicon(usr))))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font>"
else
network = newnet
screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/traffic/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
emagged = 1
to_chat(user, "<span class='notice'>You you disable the security protocols</span>")
src.updateUsrDialog()
return 1

View File

@@ -7,7 +7,7 @@
name="beam"
icon='icons/effects/beam.dmi'
icon_state="b_beam"
var/tmp/atom/BeamSource
var/atom/BeamSource
/obj/effect/overlay/beam/Initialize()
. = ..()
@@ -111,7 +111,7 @@
pixel_x = -32
pixel_y = -32
// For skathari empress' telegrab warning, could replace down the line.
// For skathari empress' telegrab warning, could replace down the line.
/obj/effect/overlay/skathari_telegrab
name = "bluespace displacement"
desc = "An eerie field of bluespace energy, you might want to run!"
@@ -119,7 +119,7 @@
icon_state = "emfield_s3"
alpha = 100
pixel_x = -32
pixel_y = -16 /// Line up with the big sprite that spawns it!
pixel_y = -16 /// Line up with the big sprite that spawns it!
plane = MOB_PLANE
layer = BELOW_MOB_LAYER
@@ -128,4 +128,4 @@
plane = FLOAT_PLANE
layer = FLOAT_LAYER
vis_flags = VIS_INHERIT_ID
appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE
appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE

View File

@@ -193,9 +193,17 @@ var/global/list/obj/item/communicator/all_communicators = list()
// Parameters: None
// Description: Simple check to see if the exonet node is active.
/obj/item/communicator/proc/get_connection_to_tcomms()
if(node && node.on && node.allow_external_communicators)
return can_telecomm(src,node)
return 0
if (!node?.on || !node.allow_external_communicators)
return FALSE
if (is_jammed(src) || is_jammed(node))
return FALSE
var/sender_z = get_z(src)
var/receiver_z = get_z(node)
if (!sender_z || !receiver_z)
return FALSE
if (sender_z == receiver_z)
return TRUE
return sender_z in using_map.get_map_levels(receiver_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE)
// Proc: process()
// Parameters: None
@@ -371,4 +379,4 @@ var/global/list/obj/item/communicator/all_communicators = list()
/obj/item/communicator/rugged
desc = "The RB-65, voted most robust communicator 2566!"
icon_state = "commrugged"
note = "Thank you for choosing the RB-65 Communicator, this is your notepad!" //Current note in the notepad function
note = "Thank you for choosing the RB-65 Communicator, this is your notepad!" //Current note in the notepad function

View File

@@ -1,5 +1,5 @@
#ifndef T_BOARD
#error T_BOARD macro is not defined but we need it!
#error T_BOARD macro is not defined but we need it!
#endif
/obj/item/circuitboard/comm_monitor
@@ -11,8 +11,3 @@
name = T_BOARD("telecommunications server monitor console")
build_path = /obj/machinery/computer/telecomms/server
origin_tech = list(TECH_DATA = 3)
/obj/item/circuitboard/comm_traffic
name = T_BOARD("telecommunications traffic control console")
build_path = /obj/machinery/computer/telecomms/traffic
origin_tech = list(TECH_DATA = 3)

View File

@@ -107,7 +107,7 @@ var/global/list/newscaster_standard_feeds = list(/datum/news_announcement/bluesp
/proc/process_newscaster()
check_for_newscaster_updates(ticker.mode.newscaster_announcements)
var/global/tmp/announced_news_types = list()
var/global/announced_news_types = list()
/proc/check_for_newscaster_updates(type)
for(var/subtype in typesof(type)-type)
var/datum/news_announcement/news = new subtype()

View File

@@ -34,7 +34,7 @@
var/block_tele = FALSE // If true, most forms of teleporting to or from this turf tile will fail.
var/can_build_into_floor = FALSE // Used for things like RCDs (and maybe lattices/floor tiles in the future), to see if a floor should replace it.
var/list/dangerous_objects // List of 'dangerous' objs that the turf holds that can cause something bad to happen when stepped on, used for AI mobs.
var/tmp/changing_turf
var/changing_turf
/turf/Initialize(mapload)
. = ..()

View File

@@ -32,9 +32,9 @@
'sound/misc/dingaling3.ogg',
'sound/misc/dingaling4.ogg'
)
var/tmp/dingaling_volume = 260
var/tmp/dingaling_chance = 30
var/tmp/dingaling_vary = FALSE
var/dingaling_volume = 260
var/dingaling_chance = 30
var/dingaling_vary = FALSE
/obj/item/clothing/accessory/teshtail/bells/is_mob_movement_sensitive()
return TRUE
@@ -83,4 +83,4 @@
/obj/item/clothing/accessory/teshtail/plumage
name = "artifical tailplume"
desc = "A set of tied together tail feathers for a teshari that has lost their real ones. Often used with prosthetic tails."
icon_state = "tailplume"
icon_state = "tailplume"

View File

@@ -3,8 +3,8 @@
startWhen = 30 // 1 minute
endWhen = 60 // Set in setup()
has_skybox_image = TRUE
var/tmp/lightning_color
var/tmp/list/valid_apcs // List of valid APCs.
var/lightning_color
var/list/valid_apcs // List of valid APCs.
/datum/event/electrical_storm/get_skybox_image()
if(!lightning_color)
@@ -62,4 +62,4 @@
// Overmap version
/datum/event/electrical_storm/overmap/announce()
return
return

View File

@@ -2,7 +2,7 @@
// Tracks precooked food to stop deep fried baked grilled grilled grilled Diona nymph cereal.
/obj/item/reagent_containers/food/snacks
var/tmp/list/cooked = list()
var/list/cooked = list()
// Root type for cooking machines. See following files for specific implementations.
/obj/machinery/appliance

View File

@@ -17,9 +17,9 @@ var/global/total_lighting_sources = 0
var/lum_b
// The lumcount values used to apply the light.
var/tmp/applied_lum_r
var/tmp/applied_lum_g
var/tmp/applied_lum_b
var/applied_lum_r
var/applied_lum_g
var/applied_lum_b
var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
var/list/turf/affecting_turfs

View File

@@ -2,12 +2,12 @@
var/dynamic_lighting = TRUE // Does the turf use dynamic lighting?
luminosity = 1
var/tmp/lighting_corners_initialised = FALSE
var/lighting_corners_initialised = FALSE
var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
var/tmp/list/datum/lighting_corner/corners
var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
var/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
var/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
var/list/datum/lighting_corner/corners
var/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()

View File

@@ -134,8 +134,8 @@ swapmap
var/x2 // maximum x,y,z coords (also used as width,height,depth until positioned)
var/y2
var/z2
var/tmp/locked // don't move anyone to this map; it's saving or loading
var/tmp/mode // save as text-mode
var/locked // don't move anyone to this map; it's saving or loading
var/mode // save as text-mode
var/ischunk // tells the load routine to load to the specified location
New(_id,x,y,z)

View File

@@ -24,10 +24,10 @@
var/has_had_player = FALSE
var/const/platform_respawn_time = 3 MINUTES
var/tmp/last_recharge_state = FALSE
var/tmp/recharge_complete = FALSE
var/tmp/recharger_charge_amount = 10 KILOWATTS
var/tmp/recharger_tick_cost = 80 KILOWATTS
var/last_recharge_state = FALSE
var/recharge_complete = FALSE
var/recharger_charge_amount = 10 KILOWATTS
var/recharger_tick_cost = 80 KILOWATTS
var/weakref/recharging
/mob/living/silicon/robot/platform/Login()

View File

@@ -73,12 +73,12 @@ You can eat glowing tree fruit to fuel your <b>ranged spitting attack</b> and <b
var/attacking_with_claws = TRUE
// Set during initialize and used to generate overlays.
var/tmp/current_icon_state // used to track our 'actual' icon state due to overlay nonsense in update_icon
var/tmp/fur_colour
var/tmp/claw_colour
var/tmp/glow_colour
var/tmp/base_colour
var/tmp/eye_colour
var/current_icon_state // used to track our 'actual' icon state due to overlay nonsense in update_icon
var/fur_colour
var/claw_colour
var/glow_colour
var/base_colour
var/eye_colour
var/offset_compiled_icon = -16
var/is_baby = FALSE

View File

@@ -50,8 +50,8 @@
// helper lists
var/tmp/list/desc_list = list()
var/tmp/list/damage_list = list()
var/list/desc_list = list()
var/list/damage_list = list()
/datum/wound/New(var/damage)

View File

@@ -144,8 +144,6 @@
return
last_text = world.time
// check if telecomms I/O route 1459 is stable
//var/telecomms_intact = telecomms_process(P.owner, owner, t)
var/obj/machinery/message_server/useMS = null
if(message_servers)
for(var/A in message_servers)
@@ -244,4 +242,4 @@
for(var/obj/item/pda/target in targets)
var/datum/data/pda/app/messenger/P = target.find_program(/datum/data/pda/app/messenger)
if(P)
P.receive_message(modified_message, "\ref[M]")
P.receive_message(modified_message, "\ref[M]")

View File

@@ -85,10 +85,10 @@
var/keep_aim = 1 //1 for keep shooting until aim is lowered
//0 for one bullet after tarrget moves and aim is lowered
var/multi_aim = 0 //Used to determine if you can target multiple people.
var/tmp/list/mob/living/aim_targets //List of who yer targeting.
var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person.
var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them.
var/tmp/lock_time = -100
var/list/mob/living/aim_targets //List of who yer targeting.
var/mob/living/last_moved_mob //Used to fire faster at more than one person.
var/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them.
var/lock_time = -100
var/dna_lock = 0 //whether or not the gun is locked to dna
var/obj/item/dnalockingchip/attached_lock

View File

@@ -1,127 +0,0 @@
/*
File: AST Nodes
An abstract syntax tree (AST) is a representation of source code in a computer-friendly format. It is composed of nodes,
each of which represents a certain part of the source code. For example, an <IfStatement> node represents an if statement in the
script's source code. Because it is a representation of the source code in memory, it is independent of any specific scripting language.
This allows a script in any language for which a parser exists to be run by the interpreter.
The AST is produced by an <n_Parser> object. It consists of a <GlobalBlock> with an arbitrary amount of statements. These statements are
run in order by an <n_Interpreter> object. A statement may in turn run another block (such as an if statement might if its condition is
met).
Articles:
- <http://en.wikipedia.org/wiki/Abstract_syntax_tree>
*/
/*
Constants: Operator Precedence
OOP_OR - Logical or
OOP_AND - Logical and
OOP_BIT - Bitwise operations
OOP_EQUAL - Equality checks
OOP_COMPARE - Greater than, less then, etc
OOP_ADD - Addition and subtraction
OOP_MULTIPLY - Multiplication and division
OOP_POW - Exponents
OOP_UNARY - Unary Operators
OOP_GROUP - Parentheses
*/
var/global/const/OOP_OR = 1 //||
var/global/const/OOP_AND = OOP_OR + 1 //&&
var/global/const/OOP_BIT = OOP_AND + 1 //&, |
var/global/const/OOP_EQUAL = OOP_BIT + 1 //==, !=
var/global/const/OOP_COMPARE = OOP_EQUAL + 1 //>, <, >=, <=
var/global/const/OOP_ADD = OOP_COMPARE + 1 //+, -
var/global/const/OOP_MULTIPLY= OOP_ADD + 1 //*, /, %
var/global/const/OOP_POW = OOP_MULTIPLY+ 1 //^
var/global/const/OOP_UNARY = OOP_POW + 1 //!
var/global/const/OOP_GROUP = OOP_UNARY + 1 //()
/*
Class: node
*/
/node/proc/ToString()
return "[src.type]"
/*
Class: identifier
*/
/node/identifier
var/id_name
/node/identifier/New(id)
.=..()
src.id_name=id
/node/identifier/ToString()
return id_name
/*
Class: expression
*/
/node/expression
/*
Class: operator
See <Binary Operators> and <Unary Operators> for subtypes.
*/
/node/expression/operator_node
var/node/expression/exp
var/tmp/name
var/tmp/precedence
/node/expression/operator_node/New()
.=..()
if(!src.name) src.name="[src.type]"
/node/expression/operator_node/ToString()
return "operator: [name]"
/*
Class: FunctionCall
*/
/node/expression/FunctionCall
//Function calls can also be expressions or statements.
var/func_name
var/node/identifier/object
var/list/parameters = list()
/*
Class: literal
*/
/node/expression/value/literal
var/value
/node/expression/value/literal/New(value)
.=..()
src.value=value
/node/expression/value/literal/ToString()
return src.value
/*
Class: variable
*/
/node/expression/value/variable
var/node/object //Either a node/identifier or another node/expression/value/variable which points to the object
var/node/identifier/id
/node/expression/value/variable/New(ident)
.=..()
id=ident
if(istext(id))id=new(id)
/node/expression/value/variable/ToString()
return src.id.ToString()
/*
Class: reference
*/
/node/expression/value/reference
var/datum/value
/node/expression/value/reference/New(value)
.=..()
src.value=value
/node/expression/value/reference/ToString()
return "ref: [src.value] ([src.value.type])"

View File

@@ -1,45 +0,0 @@
/*
File: Block Types
*/
/*
Class: BlockDefinition
An object representing a set of actions to perform independently from the rest of the script. Blocks are basically just
lists of statements to execute which also contain some local variables and methods. Note that since functions are local to a block,
it is possible to have a function definition inside of any type of block (such as in an if statement or another function),
and not just in the global scope as in many languages.
*/
/node/BlockDefinition
var/list/statements = list()
var/list/functions = list()
var/list/initial_variables = list()
/*
Proc: SetVar
Defines a permanent variable. The variable will not be deleted when it goes out of scope.
Notes:
Since all pre-existing temporary variables are deleted, it is not generally desirable to use this proc after the interpreter has been instantiated.
Instead, use <n_Interpreter.SetVar()>.
See Also:
- <n_Interpreter.SetVar()>
*/
/node/BlockDefinition/proc/SetVar(name, value)
initial_variables[name]=value
/*
Class: GlobalBlock
A block object representing the global scope.
*/
//
/node/BlockDefinition/GlobalBlock/New()
initial_variables["null"]=null
return ..()
/*
Class: FunctionBlock
A block representing a function body.
*/
//
/node/BlockDefinition/FunctionBlock

View File

@@ -1,174 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Binary Operators
*/
/*
Class: binary
Represents a binary operator in the AST. A binary operator takes two operands (ie x and y) and returns a value.
*/
/node/expression/operator_node/binary
var/node/expression/exp2
////////// Comparison Operators //////////
/*
Class: Equal
Returns true if x = y.
*/
//
/node/expression/operator_node/binary/Equal
precedence=OOP_EQUAL
/*
Class: NotEqual
Returns true if x and y aren't equal.
*/
//
/node/expression/operator_node/binary/NotEqual
precedence=OOP_EQUAL
/*
Class: Greater
Returns true if x > y.
*/
//
/node/expression/operator_node/binary/Greater
precedence=OOP_COMPARE
/*
Class: Less
Returns true if x < y.
*/
//
/node/expression/operator_node/binary/Less
precedence=OOP_COMPARE
/*
Class: GreaterOrEqual
Returns true if x >= y.
*/
//
/node/expression/operator_node/binary/GreaterOrEqual
precedence=OOP_COMPARE
/*
Class: LessOrEqual
Returns true if x <= y.
*/
//
/node/expression/operator_node/binary/LessOrEqual
precedence=OOP_COMPARE
////////// Logical Operators //////////
/*
Class: LogicalAnd
Returns true if x and y are true.
*/
//
/node/expression/operator_node/binary/LogicalAnd
precedence=OOP_AND
/*
Class: LogicalOr
Returns true if x, y, or both are true.
*/
//
/node/expression/operator_node/binary/LogicalOr
precedence=OOP_OR
/*
Class: LogicalXor
Returns true if either x or y but not both are true.
*/
//
/node/expression/operator_node/binary/LogicalXor //Not implemented in nS
precedence=OOP_OR
////////// Bitwise Operators //////////
/*
Class: BitwiseAnd
Performs a bitwise and operation.
Example:
011 & 110 = 010
*/
//
/node/expression/operator_node/binary/BitwiseAnd
precedence=OOP_BIT
/*
Class: BitwiseOr
Performs a bitwise or operation.
Example:
011 | 110 = 111
*/
//
/node/expression/operator_node/binary/BitwiseOr
precedence=OOP_BIT
/*
Class: BitwiseXor
Performs a bitwise exclusive or operation.
Example:
011 xor 110 = 101
*/
//
/node/expression/operator_node/binary/BitwiseXor
precedence=OOP_BIT
////////// Arithmetic Operators //////////
/*
Class: Add
Returns the sum of x and y.
*/
//
/node/expression/operator_node/binary/Add
precedence=OOP_ADD
/*
Class: Subtract
Returns the difference of x and y.
*/
//
/node/expression/operator_node/binary/Subtract
precedence=OOP_ADD
/*
Class: Multiply
Returns the product of x and y.
*/
//
/node/expression/operator_node/binary/Multiply
precedence=OOP_MULTIPLY
/*
Class: Divide
Returns the quotient of x and y.
*/
//
/node/expression/operator_node/binary/Divide
precedence=OOP_MULTIPLY
/*
Class: Power
Returns x raised to the power of y.
*/
//
/node/expression/operator_node/binary/Power
precedence=OOP_POW
/*
Class: Modulo
Returns the remainder of x / y.
*/
//
/node/expression/operator_node/binary/Modulo
precedence=OOP_MULTIPLY

View File

@@ -1,51 +0,0 @@
/*
File: Unary Operators
*/
/*
Class: unary
Represents a unary operator in the AST. Unary operators take a single operand (referred to as x below) and return a value.
*/
/node/expression/operator_node/unary
precedence=OOP_UNARY
/*
Class: LogicalNot
Returns !x.
Example:
!true = false and !false = true
*/
//
/node/expression/operator_node/unary/LogicalNot
name="logical not"
/*
Class: BitwiseNot
Returns the value of a bitwise not operation performed on x.
Example:
~10 (decimal 2) = 01 (decimal 1).
*/
//
/node/expression/operator_node/unary/BitwiseNot
name="bitwise not"
/*
Class: Minus
Returns -x.
*/
//
/node/expression/operator_node/unary/Minus
name="minus"
/*
Class: group
A special unary operator representing a value in parentheses.
*/
//
/node/expression/operator_node/unary/group
precedence=OOP_GROUP
/node/expression/operator_node/unary/New(node/expression/exp)
src.exp=exp
return ..()

View File

@@ -1,106 +0,0 @@
/*
File: Statement Types
*/
/*
Class: statement
An object representing a single instruction run by an interpreter.
*/
/node/statement
/*
Class: FunctionCall
Represents a call to a function.
*/
//
/node/statement/FunctionCall
var/func_name
var/node/identifier/object
var/list/parameters=list()
/*
Class: FunctionDefinition
Defines a function.
*/
//
/node/statement/FunctionDefinition
var/func_name
var/list/parameters=list()
var/node/BlockDefinition/FunctionBlock/block
/*
Class: VariableAssignment
Sets a variable in an accessible scope to the given value if one exists, otherwise initializes a new local variable to the given value.
Notes:
If a variable with the same name exists in a higher block, the value will be assigned to it. If not,
a new variable is created in the current block. To force creation of a new variable, use <VariableDeclaration>.
See Also:
- <VariableDeclaration>
*/
//
/node/statement/VariableAssignment
var/node/identifier/object
var/node/identifier/var_name
var/node/expression/value
/*
Class: VariableDeclaration
Intializes a local variable to a null value.
See Also:
- <VariableAssignment>
*/
//
/node/statement/VariableDeclaration
var/node/identifier/object
var/node/identifier/var_name
/*
Class: IfStatement
*/
//
/node/statement/IfStatement
var/node/BlockDefinition/block
var/node/BlockDefinition/else_block // may be null
var/node/expression/cond
/*
Class: WhileLoop
Loops while a given condition is true.
*/
//
/node/statement/WhileLoop
var/node/BlockDefinition/block
var/node/expression/cond
/*
Class: ForLoop
Loops while test is true, initializing a variable, increasing the variable
*/
/node/statement/ForLoop
var/node/BlockDefinition/block
var/node/expression/test
var/node/expression/init
var/node/expression/increment
/*
Class: BreakStatement
Ends a loop.
*/
//
/node/statement/BreakStatement
/*
Class: ContinueStatement
Skips to the next iteration of a loop.
*/
//
/node/statement/ContinueStatement
/*
Class: ReturnStatement
Ends the function and returns a value.
*/
//
/node/statement/ReturnStatement
var/node/expression/value

View File

@@ -1,122 +0,0 @@
/*
File: Errors
*/
/*
Class: scriptError
An error scanning or parsing the source code.
*/
/scriptError
var/message /// A message describing the problem.
/scriptError/New(msg=null)
if(msg)message=msg
/scriptError/BadToken
message="Unexpected token: "
var/token/token
/scriptError/BadToken/New(token/t)
token=t
if(t&&t.line) message="[t.line]: [message]"
if(istype(t))message+="[t.value]"
else message+="[t]"
/scriptError/InvalidID
parent_type=/scriptError/BadToken
message="Invalid identifier name: "
/scriptError/ReservedWord
parent_type=/scriptError/BadToken
message="Identifer using reserved word: "
/scriptError/BadNumber
parent_type=/scriptError/BadToken
message = "Bad number: "
/scriptError/BadReturn
var/token/token
message = "Unexpected return statement outside of a function."
/scriptError/BadReturn/New(token/t)
src.token=t
/scriptError/EndOfFile
message = "Unexpected end of file."
/scriptError/ExpectedToken
message="Expected: '"
/scriptError/ExpectedToken/New(id, token/T)
if(T && T.line) message="[T.line]: [message]"
message+="[id]'. "
if(T)message+="Found '[T.value]'."
/scriptError/UnterminatedComment
message="Unterminated multi-line comment statement: expected */"
/scriptError/DuplicateFunction
message="Function defined twice."
/scriptError/DuplicateFunction/New(name, token/t)
message="Function '[name]' defined twice."
/*
Class: runtimeError
An error thrown by the interpreter in running the script.
*/
/runtimeError
var/name
var/message /// A basic description as to what went wrong.
var/stack/stack
/**
* Proc: ToString
* Returns a description of the error suitable for showing to the user.
*/
/runtimeError/proc/ToString()
. = "[name]: [message]"
if(!stack.Top()) return
.+="\nStack:"
while(stack.Top())
var/node/statement/FunctionCall/stmt=stack.Pop()
. += "\n\t [stmt.func_name]()"
/runtimeError/TypeMismatch
name="TypeMismatchError"
/runtimeError/TypeMismatch/New(op, a, b)
message="Type mismatch: '[a]' [op] '[b]'"
/runtimeError/UnexpectedReturn
name="UnexpectedReturnError"
message="Unexpected return statement."
/runtimeError/UnknownInstruction
name="UnknownInstructionError"
message="Unknown instruction type. This may be due to incompatible compiler and interpreter versions or a lack of implementation."
/runtimeError/UndefinedVariable
name="UndefinedVariableError"
/runtimeError/UndefinedVariable/New(variable)
message="Variable '[variable]' has not been declared."
/runtimeError/UndefinedFunction
name="UndefinedFunctionError"
/runtimeError/UndefinedFunction/New(function)
message="Function '[function]()' has not been defined."
/runtimeError/DuplicateVariableDeclaration
name="DuplicateVariableError"
/runtimeError/DuplicateVariableDeclaration/New(variable)
message="Variable '[variable]' was already declared."
/runtimeError/IterationLimitReached
name="MaxIterationError"
message="A loop has reached its maximum number of iterations."
/runtimeError/RecursionLimitReached
name="MaxRecursionError"
message="The maximum amount of recursion has been reached."
/runtimeError/DivisionByZero
name="DivideByZeroError"
message="Division by zero attempted."
/runtimeError/MaxCPU
name="MaxComputationalUse"
message="Maximum amount of computational cycles reached (>= 1000)."

View File

@@ -1,211 +0,0 @@
/client/verb/tcssave()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || issilicon(mob))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
var/tcscode=winget(src, "tcscode", "text")
var/msg="[mob.name] is adding script to server [Server]: [tcscode]"
log_misc(msg)
message_admins("[mob.name] has uploaded a NTLS script to [Machine.SelectedServer] ([mob.x],[mob.y],[mob.z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[mob.x];Y=[mob.y];Z=[mob.z]'>JMP</a>)",0,1)
Server.setcode( tcscode ) // this actually saves the code from input to the server
src << output(null, "tcserror") // clear the errors
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to save: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
/client/verb/tcscompile()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.setcode( winget(src, "tcscode", "text") ) // save code first
var/list/compileerrors = Server.compile() // then compile the code!
// Output all the compile-time errors
src << output(null, "tcserror")
if(compileerrors.len)
src << output("<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
src << output("<font color = red>\t>[e.message]</font>", "tcserror")
src << output("([compileerrors.len] errors)", "tcserror")
// Output compile errors to all other people viewing the code too
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output(null, "tcserror")
M << output("<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
M << output("<font color = red>\t>[e.message]</font>", "tcserror")
M << output("([compileerrors.len] errors)", "tcserror")
else
src << output("<font color = blue>TCS compilation successful!</font>", "tcserror")
src << output("(0 errors)", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output("<font color = blue>TCS compilation successful!</font>", "tcserror")
M << output("(0 errors)", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to compile: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
/client/verb/tcsrun()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.setcode( winget(src, "tcscode", "text") ) // save code first
var/list/compileerrors = Server.compile() // then compile the code!
// Output all the compile-time errors
src << output(null, "tcserror")
if(compileerrors.len)
src << output("<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
src << output("<font color = red>\t>[e.message]</font>", "tcserror")
src << output("([compileerrors.len] errors)", "tcserror")
// Output compile errors to all other people viewing the code too
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output(null, "tcserror")
M << output("<b>Compile Errors</b>", "tcserror")
for(var/scriptError/e in compileerrors)
M << output("<font color = red>\t>[e.message]</font>", "tcserror")
M << output("([compileerrors.len] errors)", "tcserror")
else
// Finally, we run the code!
src << output("<font color = blue>TCS compilation successful! Code executed.</font>", "tcserror")
src << output("(0 errors)", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output("<font color = blue>TCS compilation successful!</font>", "tcserror")
M << output("(0 errors)", "tcserror")
var/datum/signal/signal = new()
signal.data["message"] = ""
if(Server.freq_listening.len > 0)
signal.frequency = Server.freq_listening[1]
else
signal.frequency = PUB_FREQ
signal.data["name"] = ""
signal.data["job"] = ""
signal.data["reject"] = 0
signal.data["server"] = Server
Server.Compiler.Run(signal)
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate server machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to run: Unable to locate machine. (Back up your code before exiting the window!)</font>", "tcserror")
/client/verb/exittcs()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode == mob)
Machine.storedcode = "[winget(mob, "tcscode", "text")]"
Machine.editingcode = null
else
if(mob in Machine.viewingcode)
Machine.viewingcode.Remove(mob)
/client/verb/tcsrevert()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
// Replace quotation marks with quotation macros for proper winset() compatibility
var/showcode = replacetext(Server.rawcode, "\\\"", "\\\\\"")
showcode = replacetext(showcode, "\"", "\\\"")
winset(mob, "tcscode", "text=\"[showcode]\"")
src << output(null, "tcserror") // clear the errors
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate server machine.</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate machine.</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to revert: Unable to locate machine.</font>", "tcserror")
/client/verb/tcsclearmem()
set hidden = 1
if(mob.machine || issilicon(mob))
if((istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && (mob.machine in view(1, mob))) || (issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) ))
var/obj/machinery/computer/telecomms/traffic/Machine = mob.machine
if(Machine.editingcode != mob)
return
if(Machine.SelectedServer)
var/obj/machinery/telecomms/server/Server = Machine.SelectedServer
Server.memory = list() // clear the memory
// Show results
src << output(null, "tcserror")
src << output("<font color = blue>Server memory cleared!</font>", "tcserror")
for(var/mob/M in Machine.viewingcode)
if(M.client)
M << output("<font color = blue>Server memory cleared!</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate server machine.</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate machine.</font>", "tcserror")
else
src << output(null, "tcserror")
src << output("<font color = red>Failed to clear memory: Unable to locate machine.</font>", "tcserror")

View File

@@ -1,281 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/* --- Traffic Control Scripting Language --- */
// NanoTrasen TCS Language - Made by Doohl
/n_Interpreter/TCS_Interpreter
var/datum/TCS_Compiler/Compiler
/n_Interpreter/TCS_Interpreter/HandleError(runtimeError/e)
Compiler.Holder.add_entry(e.ToString(), "Execution Error")
/datum/TCS_Compiler
var/n_Interpreter/TCS_Interpreter/interpreter
var/obj/machinery/telecomms/server/Holder // the server that is running the code
var/ready = 1 // 1 if ready to run code
/** Proc: Compile
* Compile a raw block of text into a program
* Returns: List of errors
*/
/datum/TCS_Compiler/proc/Compile(code as message)
var/n_scriptOptions/nS_Options/options = new()
var/n_Scanner/nS_Scanner/scanner = new(code, options)
var/list/tokens = scanner.Scan()
var/n_Parser/nS_Parser/parser = new(tokens, options)
var/node/BlockDefinition/GlobalBlock/program = parser.Parse()
var/list/returnerrors = list()
returnerrors += scanner.errors
returnerrors += parser.errors
if(returnerrors.len)
return returnerrors
interpreter = new(program)
interpreter.persist = 1
interpreter.Compiler= src
return returnerrors
/* -- Execute the compiled code -- */
/** Proc: Run
* Executes the compiled code.
* Arguments:
* var/datum/signal/signal - a telecomms signal
* Returns: None
*/
/datum/TCS_Compiler/proc/Run(var/datum/signal/signal)
if(!ready)
return
if(!interpreter)
return
interpreter.container = src
interpreter.SetVar("PI" , 3.141592653) // value of pi
interpreter.SetVar("E" , 2.718281828) // value of e
interpreter.SetVar("SQURT2" , 1.414213562) // value of the square root of 2
interpreter.SetVar("FALSE" , 0) // boolean shortcut to 0
interpreter.SetVar("TRUE" , 1) // boolean shortcut to 1
interpreter.SetVar("NORTH" , NORTH) // NORTH (1)
interpreter.SetVar("SOUTH" , SOUTH) // SOUTH (2)
interpreter.SetVar("EAST" , EAST) // EAST (4)
interpreter.SetVar("WEST" , WEST) // WEST (8)
// Channel macros
interpreter.SetVar("$common", PUB_FREQ)
interpreter.SetVar("$science", SCI_FREQ)
interpreter.SetVar("$command", COMM_FREQ)
interpreter.SetVar("$medical", MED_FREQ)
interpreter.SetVar("$engineering",ENG_FREQ)
interpreter.SetVar("$security", SEC_FREQ)
interpreter.SetVar("$supply", SUP_FREQ)
interpreter.SetVar("$explorer", EXP_FREQ)
// Signal data
interpreter.SetVar("$content", signal.data["message"])
interpreter.SetVar("$freq" , signal.frequency)
interpreter.SetVar("$source" , signal.data["name"])
interpreter.SetVar("$job" , signal.data["job"])
interpreter.SetVar("$sign" , signal)
interpreter.SetVar("$pass" , !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0
// Set up the script procs
/*
-> Send another signal to a server
@format: broadcast(content, frequency, source, job)
@param content: Message to broadcast
@param frequency: Frequency to broadcast to
@param source: The name of the source you wish to imitate. Must be stored in stored_names list.
@param job: The name of the job.
*/
interpreter.SetProc("broadcast", "tcombroadcast", signal, list("message", "freq", "source", "job"))
/*
-> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine)
@format: mem(address, value)
@param address: The memory address (string index) to store a value to
@param value: The value to store to the memory address
*/
interpreter.SetProc("mem", "mem", signal, list("address", "value"))
/*
-> Delay code for a given amount of deciseconds
@format: sleep(time)
@param time: time to sleep in deciseconds (1/10th second)
*/
interpreter.SetProc("sleep", /proc/delay)
/*
-> Replaces a string with another string
@format: replace(string, substring, replacestring)
@param string: the string to search for substrings (best used with $content$ constant)
@param substring: the substring to search for
@param replacestring: the string to replace the substring with
*/
interpreter.SetProc("replace", /proc/string_replacetext)
/*
-> Locates an element/substring inside of a list or string
@format: find(haystack, needle, start = 1, end = 0)
@param haystack: the container to search
@param needle: the element to search for
@param start: the position to start in
@param end: the position to end in
*/
interpreter.SetProc("find", /proc/smartfind)
/*
-> Finds the length of a string or list
@format: length(container)
@param container: the list or container to measure
*/
interpreter.SetProc("length", /proc/smartlength)
/* -- Clone functions, carried from default BYOND procs --- */
// vector namespace
interpreter.SetProc("vector", /proc/n_list)
interpreter.SetProc("at", /proc/n_listpos)
interpreter.SetProc("copy", /proc/n_listcopy)
interpreter.SetProc("push_back", /proc/n_listadd)
interpreter.SetProc("remove", /proc/n_listremove)
interpreter.SetProc("cut", /proc/n_listcut)
interpreter.SetProc("swap", /proc/n_listswap)
interpreter.SetProc("insert", /proc/n_listinsert)
interpreter.SetProc("pick", /proc/n_pick)
interpreter.SetProc("prob", /proc/prob_chance)
interpreter.SetProc("substr", /proc/docopytext)
// Donkie~
// Strings
interpreter.SetProc("lower", /proc/n_lower)
interpreter.SetProc("upper", /proc/n_upper)
interpreter.SetProc("explode", /proc/string_explode)
interpreter.SetProc("repeat", /proc/n_repeat)
interpreter.SetProc("reverse", /proc/n_reverse)
interpreter.SetProc("tonum", /proc/n_str2num)
// Numbers
interpreter.SetProc("tostring", /proc/n_num2str)
interpreter.SetProc("sqrt", /proc/n_sqrt)
interpreter.SetProc("abs", /proc/n_abs)
interpreter.SetProc("floor", /proc/n_floor)
interpreter.SetProc("ceil", /proc/n_ceil)
interpreter.SetProc("round", /proc/n_round)
interpreter.SetProc("clamp", /proc/n_clamp)
interpreter.SetProc("inrange", /proc/n_inrange)
// End of Donkie~
// Run the compiled code
interpreter.Run()
// Backwards-apply variables onto signal data
/* sanitize EVERYTHING. fucking players can't be trusted with SHIT */
signal.data["message"] = interpreter.GetVar("$content")
signal.frequency = interpreter.GetVar("$freq")
var/setname = ""
var/obj/machinery/telecomms/server/S = signal.data["server"]
if(interpreter.GetVar("$source") in S.stored_names)
setname = interpreter.GetVar("$source")
else
setname = "<i>[interpreter.GetVar("$source")]</i>"
if(signal.data["name"] != setname)
signal.data["realname"] = setname
signal.data["name"] = setname
signal.data["job"] = interpreter.GetVar("$job")
signal.data["reject"] = !(interpreter.GetVar("$pass")) // set reject to the opposite of $pass
// If the message is invalid, just don't broadcast it!
if(signal.data["message"] == "" || !signal.data["message"])
signal.data["reject"] = 1
/* -- Actual language proc code -- */
/datum/signal/proc/mem(var/address, var/value)
if(istext(address))
var/obj/machinery/telecomms/server/S = data["server"]
if(!value && value != 0)
return S.memory[address]
else
S.memory[address] = value
/datum/signal/proc/tcombroadcast(var/message, var/freq, var/source, var/job)
var/datum/signal/newsign = new
var/obj/machinery/telecomms/server/S = data["server"]
var/obj/item/radio/hradio = S.server_radio
if(!hradio)
error("[src] has no radio.")
return
if((!message || message == "") && message != 0)
message = "*beep*"
if(!source)
source = "[html_encode(uppertext(S.id))]"
hradio = new // sets the hradio as a radio intercom
if(!freq)
freq = PUB_FREQ
if(findtext(num2text(freq), ".")) // if the frequency has been set as a decimal
freq *= 10 // shift the decimal one place
if(!job)
job = "?"
newsign.data["mob"] = null
newsign.data["mobtype"] = /mob/living/carbon/human
if(source in S.stored_names)
newsign.data["name"] = source
else
newsign.data["name"] = "<i>[html_encode(uppertext(source))]</i>"
newsign.data["realname"] = newsign.data["name"]
newsign.data["job"] = job
newsign.data["compression"] = 0
newsign.data["message"] = message
newsign.data["type"] = 2 // artificial broadcast
if(!isnum(freq))
freq = text2num(freq)
newsign.frequency = freq
var/datum/radio_frequency/connection = radio_controller.return_frequency(freq)
newsign.data["connection"] = connection
newsign.data["radio"] = hradio
newsign.data["vmessage"] = message
newsign.data["vname"] = source
newsign.data["vmask"] = 0
newsign.data["level"] = list()
var/pass = S.relay_information(newsign, /obj/machinery/telecomms/hub)
if(!pass)
S.relay_information(newsign, /obj/machinery/telecomms/broadcaster) // send this simple message to broadcasters

View File

@@ -1,291 +0,0 @@
// Script -> BYOND code procs
#define SCRIPT_MAX_REPLACEMENTS_ALLOWED 200
// --- List operations (lists known as vectors in n_script) ---
// Clone of list()
/proc/n_list()
var/list/returnlist = list()
for(var/e in args)
returnlist.Add(e)
return returnlist
// Clone of pick()
/proc/n_pick()
var/list/finalpick = list()
for(var/e in args)
if(isobject(e))
if(istype(e, /list))
var/list/sublist = e
for(var/sube in sublist)
finalpick.Add(sube)
continue
finalpick.Add(e)
return pick(finalpick)
// Clone of list[]
/proc/n_listpos(var/list/L, var/pos, var/value)
if(!istype(L, /list)) return
if(isnum(pos))
if(!value)
if(L.len >= pos)
return L[pos]
else
if(L.len >= pos)
L[pos] = value
else if(istext(pos))
if(!value)
return L[pos]
else
L[pos] = value
// Clone of list.Copy()
/proc/n_listcopy(var/list/L, var/start, var/end)
if(!istype(L, /list)) return
return L.Copy(start, end)
// Clone of list.Add()
/proc/n_listadd()
var/list/chosenlist
var/i = 1
for(var/e in args)
if(i == 1)
if(isobject(e))
if(istype(e, /list))
chosenlist = e
i = 2
else
if(chosenlist)
chosenlist.Add(e)
// Clone of list.Remove()
/proc/n_listremove()
var/list/chosenlist
var/i = 1
for(var/e in args)
if(i == 1)
if(isobject(e))
if(istype(e, /list))
chosenlist = e
i = 2
else
if(chosenlist)
chosenlist.Remove(e)
// Clone of list.Cut()
/proc/n_listcut(var/list/L, var/start, var/end)
if(!istype(L, /list)) return
return L.Cut(start, end)
// Clone of list.Swap()
/proc/n_listswap(var/list/L, var/firstindex, var/secondindex)
if(!istype(L, /list)) return
if(L.len >= secondindex && L.len >= firstindex)
return L.Swap(firstindex, secondindex)
// Clone of list.Insert()
/proc/n_listinsert(var/list/L, var/index, var/element)
if(!istype(L, /list)) return
return L.Insert(index, element)
// --- Miscellaneous functions ---
// Clone of sleep()
/proc/delay(var/time)
sleep(time)
// Clone of prob()
/proc/prob_chance(var/chance)
return prob(chance)
// Merge of list.Find() and findtext()
/proc/smartfind(var/haystack, var/needle, var/start = 1, var/end = 0)
if(haystack && needle)
if(isobject(haystack))
if(istype(haystack, /list))
if(length(haystack) >= end && start > 0)
var/list/listhaystack = haystack
return listhaystack.Find(needle, start, end)
else
if(istext(haystack))
if(length(haystack) >= end && start > 0)
return findtext(haystack, needle, start, end)
// Clone of copytext()
/proc/docopytext(var/string, var/start = 1, var/end = 0)
if(istext(string) && isnum(start) && isnum(end))
if(start > 0)
return copytext(string, start, end)
// Clone of length()
/proc/smartlength(var/container)
if(container)
if(istype(container, /list) || istext(container))
return length(container)
// BY DONKIE~
// String stuff
/proc/n_lower(var/string)
if(istext(string))
return lowertext(string)
/proc/n_upper(var/string)
if(istext(string))
return uppertext(string)
/*
//Makes a list where all indices in a string is a separate index in the list
// JUST A HELPER DON'T ADD TO NTSCRIPT
/proc/string_tolist(var/string)
var/list/L = new/list()
var/i
for(i=1, i<=length(string), i++)
L.Add(copytext(string, i, i))
return L
/proc/string_explode(var/string, var/separator)
if(istext(string))
if(istext(separator) && separator == "")
return string_tolist(string)
var/i
var/lasti = 1
var/list/L = new/list()
for(i=1, i<=length(string)+1, i++)
if(copytext(string, i, i+1) == separator) // We found a separator
L.Add(copytext(string, lasti, i))
lasti = i+1
L.Add(copytext(string, lasti, length(string)+1)) // Adds the last segment
return L
Just found out there was already a string explode function, did some benchmarking, and that function were a bit faster, sticking to that.
*/
/proc/string_explode(var/string, var/separator)
if(istext(string) && istext(separator))
return splittext(string, separator)
/proc/n_repeat(var/string, var/amount)
if(istext(string) && isnum(amount))
var/i
var/newstring = ""
if(length(newstring)*amount >=1000)
return
for(i=0, i<=amount, i++)
if(i>=1000)
break
newstring = newstring + string
return newstring
/proc/n_reverse(var/string)
if(istext(string))
var/newstring = ""
var/i
for(i=length(string), i>0, i--)
if(i>=1000)
break
newstring = newstring + copytext(string, i, i+1)
return newstring
// I don't know if it's necessary to make my own proc, but I think I have to to be able to check for istext.
/proc/n_str2num(var/string)
if(istext(string))
return text2num(string)
// Number shit
/proc/n_num2str(var/num)
if(isnum(num))
return num2text(num)
// Squareroot
/proc/n_sqrt(var/num)
if(isnum(num))
return sqrt(num)
// Magnitude of num
/proc/n_abs(var/num)
if(isnum(num))
return abs(num)
// Round down
/proc/n_floor(var/num)
if(isnum(num))
return round(num)
// Round up
/proc/n_ceil(var/num)
if(isnum(num))
return round(num)+1
// Round to nearest integer
/proc/n_round(var/num)
if(isnum(num))
if(num-round(num)<0.5)
return round(num)
return n_ceil(num)
// Clamps N between min and max
/proc/n_clamp(var/num, var/min=-1, var/max=1)
if(isnum(num)&&isnum(min)&&isnum(max))
if(num<=min)
return min
if(num>=max)
return max
return num
// Returns 1 if N is inbetween Min and Max
/proc/n_inrange(var/num, var/min=-1, var/max=1)
if(isnum(num)&&isnum(min)&&isnum(max))
return ((min <= num) && (num <= max))
// END OF BY DONKIE :(
// Non-recursive
// Imported from Mono string.ReplaceUnchecked
/proc/string_replacetext(var/haystack,var/a,var/b)
if(istext(haystack)&&istext(a)&&istext(b))
var/i = 1
var/lenh=length(haystack)
var/lena=length(a)
//var/lenb=length(b)
var/count = 0
var/list/dat = list()
while (i < lenh)
var/found = findtext(haystack, a, i, 0)
//log_misc("findtext([haystack], [a], [i], 0)=[found]")
if (found == 0) // Not found
break
else
if (count < SCRIPT_MAX_REPLACEMENTS_ALLOWED)
dat+=found
count+=1
else
//log_misc("Script found [a] [count] times, aborted")
break
//log_misc("Found [a] at [found]! Moving up...")
i = found + lena
if (count == 0)
return haystack
//var/nlen = lenh + ((lenb - lena) * count)
var/buf = copytext(haystack,1,dat[1]) // Prefill
var/lastReadPos = 0
for (i = 1, i <= count, i++)
var/precopy = dat[i] - lastReadPos-1
//internal static unsafe void CharCopy (String target, int targetIndex, String source, int sourceIndex, int count)
//fixed (char* dest = target, src = source)
//CharCopy (dest + targetIndex, src + sourceIndex, count);
//CharCopy (dest + curPos, source + lastReadPos, precopy);
buf+=copytext(haystack,lastReadPos,precopy)
log_misc("buf+=copytext([haystack],[lastReadPos],[precopy])")
log_misc("[buf]")
lastReadPos = dat[i] + lena
//CharCopy (dest + curPos, replace, newValue.length);
buf+=b
log_misc("[buf]")
buf+=copytext(haystack,lastReadPos, 0)
return buf

View File

@@ -1,167 +0,0 @@
/proc/isobject(x)
return !(isnum(x) || istext(x))
/n_Interpreter/proc/Eval(node/expression/exp)
if(istype(exp, /node/expression/FunctionCall))
return RunFunction(exp)
else if(istype(exp, /node/expression/operator_node))
return EvalOperator(exp)
else if(istype(exp, /node/expression/value/literal))
var/node/expression/value/literal/lit=exp
return lit.value
else if(istype(exp, /node/expression/value/reference))
var/node/expression/value/reference/ref=exp
return ref.value
else if(istype(exp, /node/expression/value/variable))
var/node/expression/value/variable/v=exp
if(!v.object)
return Eval(GetVariable(v.id.id_name))
else
var/datum/D
if(istype(v.object, /node/identifier))
D=GetVariable(v.object:id_name)
else
D=v.object
D=Eval(D)
if(!isobject(D))
return null
if(!D.vars.Find(v.id.id_name))
RaiseError(new/runtimeError/UndefinedVariable("[v.object.ToString()].[v.id.id_name]"))
return null
return Eval(D.vars[v.id.id_name])
else if(istype(exp, /node/expression))
RaiseError(new/runtimeError/UnknownInstruction())
else
return exp
/n_Interpreter/proc/EvalOperator(node/expression/operator_node/exp)
if(istype(exp, /node/expression/operator_node/binary))
var/node/expression/operator_node/binary/bin=exp
switch(bin.type)
if(/node/expression/operator_node/binary/Equal)
return Equal(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/NotEqual)
return NotEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Greater)
return Greater(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Less)
return Less(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/GreaterOrEqual)
return GreaterOrEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/LessOrEqual)
return LessOrEqual(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/LogicalAnd)
return LogicalAnd(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/LogicalOr)
return LogicalOr(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/LogicalXor)
return LogicalXor(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/BitwiseAnd)
return BitwiseAnd(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/BitwiseOr)
return BitwiseOr(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/BitwiseXor)
return BitwiseXor(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Add)
return Add(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Subtract)
return Subtract(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Multiply)
return Multiply(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Divide)
return Divide(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Power)
return Power(Eval(bin.exp), Eval(bin.exp2))
if(/node/expression/operator_node/binary/Modulo)
return Modulo(Eval(bin.exp), Eval(bin.exp2))
else
RaiseError(new/runtimeError/UnknownInstruction())
return
switch(exp.type)
if(/node/expression/operator_node/unary/Minus)
return Minus(Eval(exp.exp))
if(/node/expression/operator_node/unary/LogicalNot)
return LogicalNot(Eval(exp.exp))
if(/node/expression/operator_node/unary/BitwiseNot)
return BitwiseNot(Eval(exp.exp))
if(/node/expression/operator_node/unary/group)
return Eval(exp.exp)
else
RaiseError(new/runtimeError/UnknownInstruction())
//Binary//
//Comparison operators
/n_Interpreter/proc/Equal(a, b) return a==b
/n_Interpreter/proc/NotEqual(a, b) return a!=b //LogicalNot(Equal(a, b))
/n_Interpreter/proc/Greater(a, b) return a>b
/n_Interpreter/proc/Less(a, b) return a<b
/n_Interpreter/proc/GreaterOrEqual(a, b) return a>=b
/n_Interpreter/proc/LessOrEqual(a, b) return a<=b
//Logical Operators
/n_Interpreter/proc/LogicalAnd(a, b) return a&&b
/n_Interpreter/proc/LogicalOr(a, b) return a||b
/n_Interpreter/proc/LogicalXor(a, b) return (a||b) && !(a&&b)
//Bitwise Operators
/n_Interpreter/proc/BitwiseAnd(a, b) return a&b
/n_Interpreter/proc/BitwiseOr(a, b) return a|b
/n_Interpreter/proc/BitwiseXor(a, b) return a^b
//Arithmetic Operators
/n_Interpreter/proc/Add(a, b)
if(istext(a)&&!istext(b)) b="[b]"
else if(istext(b)&&!istext(a)) a="[a]"
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("+", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("+", a, b))
return null
return a+b
/n_Interpreter/proc/Subtract(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("-", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("-", a, b))
return null
return a-b
/n_Interpreter/proc/Divide(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("/", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("/", a, b))
return null
if(b==0)
RaiseError(new/runtimeError/DivisionByZero())
return null
return a/b
/n_Interpreter/proc/Multiply(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("*", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("*", a, b))
return null
return a*b
/n_Interpreter/proc/Modulo(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("%", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("%", a, b))
return null
return a%b
/n_Interpreter/proc/Power(a, b)
if(isobject(a) && !isobject(b))
RaiseError(new/runtimeError/TypeMismatch("**", a, b))
return null
else if(isobject(b) && !isobject(a))
RaiseError(new/runtimeError/TypeMismatch("**", a, b))
return null
return a**b
//Unary//
/n_Interpreter/proc/Minus(a) return -a
/n_Interpreter/proc/LogicalNot(a) return !a
/n_Interpreter/proc/BitwiseNot(a) return ~a

View File

@@ -1,140 +0,0 @@
/*
File: Interpreter (Public)
Contains methods for interacting with the interpreter.
*/
/*
Class: n_Interpreter
Procedures allowing for interaction with the script that is being run by the interpreter object.
*/
/n_Interpreter
/*
Proc: Load
Loads a 'compiled' script into memory.
Parameters:
program - A <GlobalBlock> object which represents the script's global scope.
*/
/n_Interpreter/proc/Load(node/BlockDefinition/GlobalBlock/program)
ASSERT(program)
src.program = program
CreateGlobalScope()
/*
Proc: Run
Runs the script.
*/
/n_Interpreter/proc/Run()
cur_recursion = 0 // reset recursion
cur_statements = 0 // reset CPU tracking
alertadmins = 0
ASSERT(src.program)
RunBlock(src.program)
/*
Proc: SetVar
Defines a global variable for the duration of the next execution of a script.
Notes:
This differs from <Block.SetVar()> in that variables set using this procedure only last for the session,
while those defined from the block object persist if it is ran multiple times.
See Also:
- <Block.SetVar()>
*/
/n_Interpreter/proc/SetVar(name, value)
if(!istext(name))
//CRASH("Invalid variable name")
return
AssignVariable(name, value)
/*
Proc: SetProc
Defines a procedure to be available to the script.
Parameters:
name - The name of the procedure as exposed to the script.
path - The typepath of a proc to be called when the function call is read by the interpreter, or, if object is specified, a string representing the procedure's name.
object - (Optional) An object which will the be target of a function call.
params - Only required if object is not null, a list of the names of parameters the proc takes.
*/
/n_Interpreter/proc/SetProc(name, path, object=null, list/params=null)
if(!istext(name))
//CRASH("Invalid function name")
return
if(!object)
globalScope.functions[name] = path
return
var/node/statement/FunctionDefinition/S = new()
S.func_name = name
S.parameters = params
S.block = new()
S.block.SetVar("src", object)
var/node/expression/FunctionCall/C = new()
C.func_name = path
C.object = new("src")
for(var/p in params)
C.parameters += new/node/expression/value/variable(p)
var/node/statement/ReturnStatement/R=new()
R.value=C
S.block.statements += R
globalScope.functions[name] = S
/*
Proc: VarExists
Checks whether a global variable with the specified name exists.
*/
/n_Interpreter/proc/VarExists(name)
return globalScope.variables.Find(name) //convert to 1/0 first?
/*
Proc: ProcExists
Checks whether a global function with the specified name exists.
*/
/n_Interpreter/proc/ProcExists(name)
return globalScope.functions.Find(name)
/*
Proc: GetVar
Returns the value of a global variable in the script. Remember to ensure that the variable exists before calling this procedure.
See Also:
- <VarExists()>
*/
/n_Interpreter/proc/GetVar(name)
if(!VarExists(name))
//CRASH("No variable named '[name]'.")
return
var/x = globalScope.variables[name]
return Eval(x)
/*
Proc: CallProc
Calls a global function defined in the script and, amazingly enough, returns its return value. Remember to ensure that the function
exists before calling this procedure.
See Also:
- <ProcExists()>
*/
/n_Interpreter/proc/CallProc(name, params[]=null)
if(!ProcExists(name))
//CRASH("No function named '[name]'.")
return
var/node/statement/FunctionDefinition/func = globalScope.functions[name]
if(istype(func))
var/node/statement/FunctionCall/stmt = new
stmt.func_name = func.func_name
stmt.parameters = params
return RunFunction(stmt)
else
return call(func)(arglist(params))
//CRASH("Unknown function type '[name]'.")
/*
Event: HandleError
Called when the interpreter throws a runtime error.
See Also:
- <runtimeError>
*/
/n_Interpreter/proc/HandleError(runtimeError/e)

View File

@@ -1,309 +0,0 @@
/*
File: Interpreter (Internal)
*/
/*
Class: n_Interpreter
*/
/*
Macros: Status Macros
RETURNING - Indicates that the current function is returning a value.
BREAKING - Indicates that the current loop is being terminated.
CONTINUING - Indicates that the rest of the current iteration of a loop is being skipped.
*/
#define RETURNING 1
#define BREAKING 2
#define CONTINUING 4
/n_Interpreter
var/scope/curScope
var/scope/globalScope
var/node/BlockDefinition/program
var/node/statement/FunctionDefinition/curFunction
var/stack/scopes = new()
var/stack/functions = new()
var/datum/container // associated container for interpeter
/*
Var: status
A variable indicating that the rest of the current block should be skipped. This may be set to any combination of <Status Macros>.
*/
var/status=0
var/returnVal
var/max_statements=1000 // maximum amount of statements that can be called in one execution. this is to prevent massive crashes and exploitation
var/cur_statements=0 // current amount of statements called
var/alertadmins=0 // set to 1 if the admins shouldn't be notified of anymore issues
var/max_iterations=100 // max number of uninterrupted loops possible
var/max_recursion=50 // max recursions without returning anything (or completing the code block)
var/cur_recursion=0 // current amount of recursion
/*
Var: persist
If 0, global variables will be reset after Run() finishes.
*/
var/persist=1
var/paused=0
/*
Constructor: New
Calls <Load()> with the given parameters.
*/
/n_Interpreter/New(node/BlockDefinition/GlobalBlock/program=null)
.=..()
if(program)Load(program)
/*
Proc: RaiseError
Raises a runtime error.
*/
/n_Interpreter/proc/RaiseError(runtimeError/e)
e.stack=functions.Copy()
e.stack.Push(curFunction)
src.HandleError(e)
/n_Interpreter/proc/CreateScope(node/BlockDefinition/B)
var/scope/S = new(B, curScope)
scopes.Push(curScope)
curScope = S
return S
/n_Interpreter/proc/CreateGlobalScope()
scopes.Clear()
var/scope/S = new(program, null)
globalScope = S
return S
/*
Proc: RunBlock
Runs each statement in a block of code.
*/
/n_Interpreter/proc/RunBlock(node/BlockDefinition/Block, scope/scope = null)
var/is_global = istype(Block, /node/BlockDefinition/GlobalBlock)
if(!is_global)
if(scope)
curScope = scope
else
CreateScope(Block)
else
if(!persist)
CreateGlobalScope()
curScope = globalScope
if(cur_statements < max_statements)
for(var/node/statement/S in Block.statements)
while(paused) sleep(10)
cur_statements++
if(cur_statements >= max_statements)
RaiseError(new/runtimeError/MaxCPU())
if(container && !alertadmins)
if(istype(container, /datum/TCS_Compiler))
var/datum/TCS_Compiler/Compiler = container
var/obj/machinery/telecomms/server/Holder = Compiler.Holder
var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Compiler.Holder] ([Holder.x], [Holder.y], [Holder.z])."
alertadmins = 1
message_admins(message, 1)
break
if(istype(S, /node/statement/VariableAssignment))
var/node/statement/VariableAssignment/stmt = S
var/name = stmt.var_name.id_name
if(!stmt.object)
// Below we assign the variable first to null if it doesn't already exist.
// This is necessary for assignments like +=, and when the variable is used in a function
// If the variable already exists in a different block, then AssignVariable will automatically use that one.
if(!IsVariableAccessible(name))
AssignVariable(name, null)
AssignVariable(name, Eval(stmt.value))
else
var/datum/D = Eval(GetVariable(stmt.object.id_name))
if(!D) return
D.vars[stmt.var_name.id_name] = Eval(stmt.value)
else if(istype(S, /node/statement/VariableDeclaration))
//VariableDeclaration nodes are used to forcibly declare a local variable so that one in a higher scope isn't used by default.
var/node/statement/VariableDeclaration/dec=S
if(!dec.object)
AssignVariable(dec.var_name.id_name, null, curScope)
else
var/datum/D = Eval(GetVariable(dec.object.id_name))
if(!D) return
D.vars[dec.var_name.id_name] = null
else if(istype(S, /node/statement/FunctionCall))
RunFunction(S)
else if(istype(S, /node/statement/FunctionDefinition))
//do nothing
else if(istype(S, /node/statement/WhileLoop))
RunWhile(S)
else if(istype(S, /node/statement/IfStatement))
RunIf(S)
else if(istype(S, /node/statement/ReturnStatement))
if(!curFunction)
RaiseError(new/runtimeError/UnexpectedReturn())
continue
status |= RETURNING
returnVal=Eval(S:value)
break
else if(istype(S, /node/statement/BreakStatement))
status |= BREAKING
break
else if(istype(S, /node/statement/ContinueStatement))
status |= CONTINUING
break
else
RaiseError(new/runtimeError/UnknownInstruction())
if(status)
break
curScope = scopes.Pop()
/*
Proc: RunFunction
Runs a function block or a proc with the arguments specified in the script.
*/
/n_Interpreter/proc/RunFunction(node/statement/FunctionCall/stmt)
//Note that anywhere /node/statement/FunctionCall/stmt is used so may /node/expression/FunctionCall
// If recursion gets too high (max 50 nested functions) throw an error
if(cur_recursion >= max_recursion)
RaiseError(new/runtimeError/RecursionLimitReached())
return 0
var/node/statement/FunctionDefinition/def
if(!stmt.object) //A scope's function is being called, stmt.object is null
def = GetFunction(stmt.func_name)
else if(istype(stmt.object)) //A method of an object exposed as a variable is being called, stmt.object is a /node/identifier
var/O = GetVariable(stmt.object.id_name) //Gets a reference to the object which is the target of the function call.
if(!O) return //Error already thrown in GetVariable()
def = Eval(O)
if(!def) return
cur_recursion++ // add recursion
if(istype(def))
if(curFunction) functions.Push(curFunction)
var/scope/S = CreateScope(def.block)
for(var/i=1 to def.parameters.len)
var/val
if(stmt.parameters.len>=i)
val = stmt.parameters[i]
//else
// unspecified param
AssignVariable(def.parameters[i], new/node/expression/value/literal(Eval(val)), S)
curFunction=stmt
RunBlock(def.block, S)
//Handle return value
. = returnVal
status &= ~RETURNING
returnVal=null
curFunction=functions.Pop()
cur_recursion--
else
cur_recursion--
var/list/params=new
for(var/node/expression/P in stmt.parameters)
params+=list(Eval(P))
if(isobject(def)) //def is an object which is the target of a function call
if( !hascall(def, stmt.func_name) )
RaiseError(new/runtimeError/UndefinedFunction("[stmt.object.id_name].[stmt.func_name]"))
return
return call(def, stmt.func_name)(arglist(params))
else //def is a path to a global proc
return call(def)(arglist(params))
//else
// RaiseError(new/runtimeError/UnknownInstruction())
/*
Proc: RunIf
Checks a condition and runs either the if block or else block.
*/
/n_Interpreter/proc/RunIf(node/statement/IfStatement/stmt)
if(Eval(stmt.cond))
RunBlock(stmt.block)
else if(stmt.else_block)
RunBlock(stmt.else_block)
/*
Proc: RunWhile
Runs a while loop.
*/
/n_Interpreter/proc/RunWhile(node/statement/WhileLoop/stmt)
var/i=1
while(Eval(stmt.cond) && Iterate(stmt.block, i++))
continue
status &= ~BREAKING
/*
Proc:Iterate
Runs a single iteration of a loop. Returns a value indicating whether or not to continue looping.
*/
/n_Interpreter/proc/Iterate(node/BlockDefinition/block, count)
RunBlock(block)
if(max_iterations > 0 && count >= max_iterations)
RaiseError(new/runtimeError/IterationLimitReached())
return 0
if(status & (BREAKING|RETURNING))
return 0
status &= ~CONTINUING
return 1
/*
Proc: GetFunction
Finds a function in an accessible scope with the given name. Returns a <FunctionDefinition>.
*/
/n_Interpreter/proc/GetFunction(name)
var/scope/S = curScope
while(S)
if(S.functions.Find(name))
return S.functions[name]
S = S.parent
RaiseError(new/runtimeError/UndefinedFunction(name))
/*
Proc: GetVariable
Finds a variable in an accessible scope and returns its value.
*/
/n_Interpreter/proc/GetVariable(name)
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return S.variables[name]
S = S.parent
RaiseError(new/runtimeError/UndefinedVariable(name))
/n_Interpreter/proc/GetVariableScope(name) //needed for when you reassign a variable in a higher scope
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return S
S = S.parent
/n_Interpreter/proc/IsVariableAccessible(name)
var/scope/S = curScope
while(S)
if(S.variables.Find(name))
return TRUE
S = S.parent
return FALSE
/*
Proc: AssignVariable
Assigns a value to a variable in a specific block.
Parameters:
name - The name of the variable to assign.
value - The value to assign to it.
S - The scope the variable resides in. If it is null, a scope with the variable already existing is found. If no scopes have a variable of the given name, the current scope is used.
*/
/n_Interpreter/proc/AssignVariable(name, node/expression/value, scope/S=null)
if(!S) S = GetVariableScope(name)
if(!S) S = curScope
if(!S) S = globalScope
ASSERT(istype(S))
if(istext(value) || isnum(value) || isnull(value)) value = new/node/expression/value/literal(value)
else if(!istype(value) && isobject(value)) value = new/node/expression/value/reference(value)
//TODO: check for invalid name
S.variables["[name]"] = value

View File

@@ -1,16 +0,0 @@
/*
Class: scope
A runtime instance of a block. Used internally by the interpreter.
*/
/scope/
var/scope/parent = null
var/node/BlockDefinition/block
var/list/functions
var/list/variables
/scope/New(node/BlockDefinition/B, scope/parent)
src.block = B
src.parent = parent
src.variables = B.initial_variables.Copy()
src.functions = B.functions.Copy()
.=..()

View File

@@ -1,99 +0,0 @@
/*
File: Options
*/
var/global/const/ascii_A =65
var/global/const/ascii_Z =90
var/global/const/ascii_a =97
var/global/const/ascii_z =122
var/global/const/ascii_DOLLAR = 36 // $
var/global/const/ascii_ZERO=48
var/global/const/ascii_NINE=57
var/global/const/ascii_UNDERSCORE=95 // _
/*
Class: n_scriptOptions
*/
/n_scriptOptions/proc/CanStartID(char) //returns true if the character can start a variable, function, or keyword name (by default letters or an underscore)
if(!isnum(char))char=text2ascii(char)
return (char in ascii_A to ascii_Z) || (char in ascii_a to ascii_z) || char==ascii_UNDERSCORE || char==ascii_DOLLAR
/n_scriptOptions/proc/IsValidIDChar(char) //returns true if the character can be in the body of a variable, function, or keyword name (by default letters, numbers, and underscore)
if(!isnum(char))char=text2ascii(char)
return CanStartID(char) || IsDigit(char)
/n_scriptOptions/proc/IsDigit(char)
if(!isnum(char))char=text2ascii(char)
return char in ascii_ZERO to ascii_NINE
/n_scriptOptions/proc/IsValidID(id) //returns true if all the characters in the string are okay to be in an identifier name
if(!CanStartID(id)) //don't need to grab first char in id, since text2ascii does it automatically
return 0
if(length(id)==1) return 1
for(var/i=2 to length(id))
if(!IsValidIDChar(copytext(id, i, i+1)))
return 0
return 1
/*
Class: nS_Options
An implementation of <n_scriptOptions> for the n_Script language.
*/
/n_scriptOptions/nS_Options
var/list/symbols = list("(", ")", "\[", "]", ";", ",", "{", "}") //scanner - Characters that can be in symbols
/*
Var: keywords
An associative list used by the parser to parse keywords. Indices are strings which will trigger the keyword when parsed and the
associated values are <nS_Keyword> types of which the <n_Keyword.Parse()> proc will be called.
*/
var/list/keywords = list(
"if" = /n_Keyword/nS_Keyword/kwIf,
"else" = /n_Keyword/nS_Keyword/kwElse,
"while" = /n_Keyword/nS_Keyword/kwWhile,
"break" = /n_Keyword/nS_Keyword/kwBreak,
"continue" = /n_Keyword/nS_Keyword/kwContinue,
"return" = /n_Keyword/nS_Keyword/kwReturn,
"def" = /n_Keyword/nS_Keyword/kwDef
)
var/list/assign_operators = list(
"=" = null,
"&=" = "&",
"|=" = "|",
"`=" = "`",
"+=" = "+",
"-=" = "-",
"*=" = "*",
"/=" = "/",
"^=" = "^",
"%=" = "%"
)
var/list/unary_operators =list(
"!" = /node/expression/operator_node/unary/LogicalNot,
"~" = /node/expression/operator_node/unary/BitwiseNot,
"-" = /node/expression/operator_node/unary/Minus
)
var/list/binary_operators=list(
"==" = /node/expression/operator_node/binary/Equal,
"!=" = /node/expression/operator_node/binary/NotEqual,
">" = /node/expression/operator_node/binary/Greater,
"<" = /node/expression/operator_node/binary/Less,
">=" = /node/expression/operator_node/binary/GreaterOrEqual,
"<=" = /node/expression/operator_node/binary/LessOrEqual,
"&&" = /node/expression/operator_node/binary/LogicalAnd,
"||" = /node/expression/operator_node/binary/LogicalOr,
"&" = /node/expression/operator_node/binary/BitwiseAnd,
"|" = /node/expression/operator_node/binary/BitwiseOr,
"`" = /node/expression/operator_node/binary/BitwiseXor,
"+" = /node/expression/operator_node/binary/Add,
"-" = /node/expression/operator_node/binary/Subtract,
"*" = /node/expression/operator_node/binary/Multiply,
"/" = /node/expression/operator_node/binary/Divide,
"^" = /node/expression/operator_node/binary/Power,
"%" = /node/expression/operator_node/binary/Modulo)
/n_scriptOptions/nS_Options/New()
.=..()
for(var/O in assign_operators+binary_operators+unary_operators)
if(!symbols.Find(O)) symbols+=O

View File

@@ -1,310 +0,0 @@
/*
File: Expressions
Procedures for parsing expressions.
*/
/*
Macros: Expression Macros
OPERATOR - A value indicating the parser currently expects a binary operator.
VALUE - A value indicating the parser currently expects a value.
SHIFT - Tells the parser to push the current operator onto the stack.
REDUCE - Tells the parser to reduce the stack.
*/
#define OPERATOR 1
#define VALUE 2
#define SHIFT 0
#define REDUCE 1
/*
Class: nS_Parser
*/
/n_Parser/nS_Parser
/*
Var: expecting
A variable which keeps track of whether an operator or value is expected. It should be either <OPERATOR> or <VALUE>. See <ParseExpression()>
for more information.
*/
var/expecting=VALUE
/*
Proc: Precedence
Compares two operators, decides which is higher in the order of operations, and returns <SHIFT> or <REDUCE>.
*/
/n_Parser/nS_Parser/proc/Precedence(node/expression/operator_node/top, node/expression/operator_node/input)
if(istype(top))
top=top.precedence
if(istype(input))
input=input:precedence
if(top>=input)
return REDUCE
return SHIFT
/*
Proc: GetExpression
Takes a token expected to represent a value and returns an <expression> node.
*/
/n_Parser/nS_Parser/proc/GetExpression(token/T)
if(!T) return
if(istype(T, /node/expression))
return T
switch(T.type)
if(/token/word)
return new/node/expression/value/variable(T.value)
if(/token/accessor)
var/token/accessor/A=T
var/node/expression/value/variable/E//=new(A.member)
var/stack/S=new()
while(istype(A.object, /token/accessor))
S.Push(A)
A=A.object
ASSERT(istext(A.object))
while(A)
var/node/expression/value/variable/V=new()
V.id=new(A.member)
if(E)
V.object=E
else
V.object=new/node/identifier(A.object)
E=V
A=S.Pop()
return E
if(/token/number, /token/string)
return new/node/expression/value/literal(T.value)
/*
Proc: GetOperator
Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary
operator from a token.
Parameters:
O - The input value. If this is a token, O is reset to the token's value.
When O is a string and is in L, its associated value is used as the path to instantiate.
type - The desired type of the returned object.
L - The list in which to search for O.
See Also:
- <GetBinaryOperator()>
- <GetUnaryOperator()>
*/
/n_Parser/nS_Parser/proc/GetOperator(O, type=/node/expression/operator_node, L[])
if(istype(O, type)) return O //O is already the desired type
if(istype(O, /token)) O=O:value //sets O to text
if(istext(O)) //sets O to path
if(L.Find(O)) O=L[O]
else return null
if(ispath(O))O=new O //catches path from last check
else return null //Unknown type
return O
/*
Proc: GetBinaryOperator
Uses <GetOperator()> to search for an instance of a binary operator type with which the given string is associated. For example, if
O is set to "+", an <Add> node is returned.
See Also:
- <GetOperator()>
- <GetUnaryOperator()>
*/
/n_Parser/nS_Parser/proc/GetBinaryOperator(O)
return GetOperator(O, /node/expression/operator_node/binary, options.binary_operators)
/*
Proc: GetUnaryOperator
Uses <GetOperator()> to search for an instance of a unary operator type with which the given string is associated. For example, if
O is set to "!", a <LogicalNot> node is returned.
See Also:
- <GetOperator()>
- <GetBinaryOperator()>
*/
/n_Parser/nS_Parser/proc/GetUnaryOperator(O)
return GetOperator(O, /node/expression/operator_node/unary, options.unary_operators)
/*
Proc: Reduce
Takes the operator on top of the opr stack and assigns its operand(s). Then this proc pushes the value of that operation to the top
of the val stack.
*/
/n_Parser/nS_Parser/proc/Reduce(stack/opr, stack/val)
var/node/expression/operator_node/O=opr.Pop()
if(!O) return
if(!istype(O))
errors+=new/scriptError("Error reducing expression - invalid operator.")
return
//Take O and assign its operands, popping one or two values from the val stack
//depending on whether O is a binary or unary operator.
if(istype(O, /node/expression/operator_node/binary))
var/node/expression/operator_node/binary/B=O
B.exp2=val.Pop()
B.exp =val.Pop()
val.Push(B)
else
O.exp=val.Pop()
val.Push(O)
/*
Proc: EndOfExpression
Returns true if the current token represents the end of an expression.
Parameters:
end - A list of values to compare the current token to.
*/
/n_Parser/nS_Parser/proc/EndOfExpression(end[])
if(!curToken)
return 1
if(istype(curToken, /token/symbol) && end.Find(curToken.value))
return 1
if(istype(curToken, /token/end) && end.Find(/token/end))
return 1
return 0
/*
Proc: ParseExpression
Uses the Shunting-yard algorithm to parse expressions.
Notes:
- When an opening parenthesis is found, then <ParseParenExpression()> is called to handle it.
- The <expecting> variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either).
Articles:
- <http://epaperpress.com/oper/>
- <http://en.wikipedia.org/wiki/Shunting-yard_algorithm>
See Also:
- <ParseFunctionExpression()>
- <ParseParenExpression()>
- <ParseParamExpression()>
*/
/n_Parser/nS_Parser/proc/ParseExpression(list/end=list(/token/end), list/ErrChars=list("{", "}"))
var/stack/opr=new
var/stack/val=new
src.expecting=VALUE
while(TRUE)
if(EndOfExpression(end))
break
if(istype(curToken, /token/symbol) && ErrChars.Find(curToken.value))
errors+=new/scriptError/BadToken(curToken)
break
if(index>tokens.len) //End of File
errors+=new/scriptError/EndOfFile()
break
var/token/ntok
if(index+1<=tokens.len)
ntok=tokens[index+1]
if(istype(curToken, /token/symbol) && curToken.value=="(") //Parse parentheses expression
if(expecting!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(ParseParenExpression())
else if(istype(curToken, /token/symbol)) //Operator found.
var/node/expression/operator_node/curOperator //Figure out whether it is unary or binary and get a new instance.
if(src.expecting==OPERATOR)
curOperator=GetBinaryOperator(curToken)
if(!curOperator)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
else
curOperator=GetUnaryOperator(curToken)
if(!curOperator) //given symbol isn't a unary operator
errors+=new/scriptError/ExpectedToken("expression", curToken)
NextToken()
continue
if(opr.Top() && Precedence(opr.Top(), curOperator)==REDUCE) //Check order of operations and reduce if necessary
Reduce(opr, val)
continue
opr.Push(curOperator)
src.expecting=VALUE
else if(ntok && ntok.value=="(" && istype(ntok, /token/symbol)\
&& istype(curToken, /token/word)) //Parse function call
var/token/preToken=curToken
var/old_expect=src.expecting
var/fex=ParseFunctionExpression()
if(old_expect!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", preToken)
NextToken()
continue
val.Push(fex)
else if(istype(curToken, /token/keyword)) //inline keywords
var/n_Keyword/kw=options.keywords[curToken.value]
kw=new kw(inline=1)
if(kw)
if(!kw.Parse(src))
return
else
errors+=new/scriptError/BadToken(curToken)
else if(istype(curToken, /token/end)) //semicolon found where it wasn't expected
errors+=new/scriptError/BadToken(curToken)
NextToken()
continue
else
if(expecting!=VALUE)
errors+=new/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(GetExpression(curToken))
src.expecting=OPERATOR
NextToken()
while(opr.Top()) Reduce(opr, val) //Reduce the value stack completely
.=val.Pop() //Return what should be the last value on the stack
if(val.Top()) //
var/node/N=val.Pop()
errors+=new/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].")
return null
/*
Proc: ParseFunctionExpression
Parses a function call inside of an expression.
See Also:
- <ParseExpression()>
*/
/n_Parser/nS_Parser/proc/ParseFunctionExpression()
var/node/expression/FunctionCall/exp=new
exp.func_name=curToken.value
NextToken() //skip function name
NextToken() //skip open parenthesis, already found
var/loops = 0
while(TRUE)
loops++
if(loops>=1000)
CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;")
if(istype(curToken, /token/symbol) && curToken.value==")")
return exp
exp.parameters+=ParseParamExpression()
if(curToken.value==","&&istype(curToken, /token/symbol))NextToken() //skip comma
if(istype(curToken, /token/end)) //Prevents infinite loop...
errors+=new/scriptError/ExpectedToken(")")
return exp
/*
Proc: ParseParenExpression
Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses.
See Also:
- <ParseExpression()>
*/
/n_Parser/nS_Parser/proc/ParseParenExpression()
if(!CheckToken("(", /token/symbol))
return
return new/node/expression/operator_node/unary/group(ParseExpression(list(")")))
/*
Proc: ParseParamExpression
Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call.
See Also:
- <ParseExpression()>
*/
/n_Parser/nS_Parser/proc/ParseParamExpression()
return ParseExpression(list(",", ")"))

View File

@@ -1,158 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Keywords
*/
var/global/const/KW_FAIL = 0 //Fatal error; stop parsing entire script.
var/global/const/KW_PASS = 1 //OK
var/global/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on.
var/global/const/KW_WARN = 3 //Warning
/*
var/global/const/Class: n_Keyword
var/global/const/Represents a special statement in the code triggered by a keyword.
*/
/*
Var: inline
1 if the keyword is in an expression (e.g. the new keyword in many languages), 0 otherwise (such as the if and else keywords).
*/
/n_Keyword
var/inline
/n_Keyword/New(inline=FALSE)
src.inline=inline
return ..()
/*
Proc: Parse
Called when the parser finds a keyword in the code.
Parameters:
parser - The parser that created this object. You can use the parameter to manipulate the parser in order to add statements and blocks
to its AST.
*/
/n_Keyword/proc/Parse(n_Parser/parser)
/*
Class: nS_Keyword
A keyword in n_Script. By default these include return, if, else, while, and def. To enable or disable a keyword, change the
<nS_Options.keywords> list.
Behavior:
When a parser is expecting a new statement, and a keyword listed in <nS_Options.keywords> is found, it will call the keyword's
<n_Keyword.Parse()> proc.
*/
//
/n_Keyword/nS_Keyword/New(inline=0)
if(inline)
qdel(src)
/n_Keyword/nS_Keyword/kwReturn/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadReturn(parser.curToken)
. = KW_WARN
var/node/statement/ReturnStatement/stmt=new
parser.NextToken() //skip 'return' token
stmt.value=parser.ParseExpression()
parser.curBlock.statements+=stmt
/n_Keyword/nS_Keyword/kwIf/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/IfStatement/stmt=new
parser.NextToken() //skip 'if' token
stmt.cond=parser.ParseParenExpression()
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(!parser.CheckToken("{", /token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0
return KW_ERR
parser.curBlock.statements+=stmt
stmt.block=new
parser.AddBlock(stmt.block)
/n_Keyword/nS_Keyword/kwElse/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/list/L=parser.curBlock.statements
var/node/statement/IfStatement/stmt
if(L&&L.len) stmt=L[L.len] //Get the last statement in the current block
if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement
parser.errors+=new/scriptError/ExpectedToken("if statement",parser.curToken)
return KW_FAIL
parser.NextToken() //skip 'else' token
if(!parser.CheckToken("{", /token/symbol, skip=0))
return KW_ERR
stmt.else_block=new()
parser.AddBlock(stmt.else_block)
/n_Keyword/nS_Keyword/kwWhile/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/WhileLoop/stmt=new
parser.NextToken() //skip 'while' token
stmt.cond=parser.ParseParenExpression()
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(!parser.CheckToken("{", /token/symbol, skip=0))
return KW_ERR
parser.curBlock.statements+=stmt
stmt.block=new
parser.AddBlock(stmt.block)
/n_Keyword/nS_Keyword/kwBreak/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadToken(parser.curToken)
. = KW_WARN
var/node/statement/BreakStatement/stmt=new
parser.NextToken() //skip 'break' token
parser.curBlock.statements+=stmt
/n_Keyword/nS_Keyword/kwContinue/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
parser.errors+=new/scriptError/BadToken(parser.curToken)
. = KW_WARN
var/node/statement/ContinueStatement/stmt=new
parser.NextToken() //skip 'break' token
parser.curBlock.statements+=stmt
/n_Keyword/nS_Keyword/kwDef/Parse(n_Parser/nS_Parser/parser)
.=KW_PASS
var/node/statement/FunctionDefinition/def=new
parser.NextToken() //skip 'def' token
if(!parser.options.IsValidID(parser.curToken.value))
parser.errors+=new/scriptError/InvalidID(parser.curToken)
return KW_FAIL
def.func_name=parser.curToken.value
parser.NextToken()
if(!parser.CheckToken("(", /token/symbol))
return KW_FAIL
while(TRUE) //for now parameters can be separated by whitespace - they don't need a comma in between
if(istype(parser.curToken, /token/symbol))
switch(parser.curToken.value)
if(",")
parser.NextToken()
if(")")
break
else
parser.errors+=new/scriptError/BadToken(parser.curToken)
return KW_ERR
else if(istype(parser.curToken, /token/word))
def.parameters+=parser.curToken.value
parser.NextToken()
else
parser.errors+=new/scriptError/InvalidID(parser.curToken)
return KW_ERR
if(!parser.CheckToken(")", /token/symbol))
return KW_FAIL
if(istype(parser.curToken, /token/end)) //Function prototype
parser.curBlock.statements+=def
else if(parser.curToken.value=="{" && istype(parser.curToken, /token/symbol))
def.block = new
parser.curBlock.statements+=def
parser.curBlock.functions[def.func_name]=def
parser.AddBlock(def.block)
else
parser.errors+=new/scriptError/BadToken(parser.curToken)
return KW_FAIL

View File

@@ -1,182 +0,0 @@
/*
File: Parser
*/
/*
Class: n_Parser
An object that reads tokens and produces an AST (abstract syntax tree).
*/
/n_Parser
var/index = 1
/*
Var: index
The parser's current position in the token's list.
*/
/*
Var: tokens
A list of tokens in the source code generated by a scanner.
*/
var/list/tokens = new
/*
Var: errors
A list of fatal errors found by the parser. If there are any items in this list, then it is not safe to run the returned AST.
See Also:
- <scriptError>
*/
var/list/errors = new
/*
Var: warnings
A list of non-fatal problems in the script.
*/
var/list/warnings = new
/*
Var: curToken
The token at <index> in <tokens>.
*/
var/token/curToken
var/stack/blocks=new
var/node/BlockDefinition/GlobalBlock/global_block=new
var/node/BlockDefinition/curBlock
/*
Proc: Parse
Reads the tokens and returns the AST's <GlobalBlock> node. Be sure to populate the tokens list before calling this procedure.
*/
/n_Parser/proc/Parse()
/*
Proc: NextToken
Sets <curToken> to the next token in the <tokens> list, or null if there are no more tokens.
*/
/n_Parser/proc/NextToken()
if(index>=tokens.len)
curToken=null
else
curToken=tokens[++index]
return curToken
/*
Class: nS_Parser
An implmentation of a parser for n_Script.
*/
/n_Parser/nS_Parser
var/n_scriptOptions/nS_Options/options
/*
Constructor: New
Parameters:
tokens - A list of tokens to parse.
options - An object used for configuration.
*/
/n_Parser/nS_Parser/New(tokens[], n_scriptOptions/options)
src.tokens=tokens
src.options=options
curBlock=global_block
return ..()
/n_Parser/nS_Parser/Parse()
ASSERT(tokens)
for(,src.index<=src.tokens.len, src.index++)
curToken=tokens[index]
switch(curToken.type)
if(/token/keyword)
var/n_Keyword/kw=options.keywords[curToken.value]
kw=new kw()
if(kw)
if(!kw.Parse(src))
return
if(/token/word)
var/token/ntok
if(index+1>tokens.len)
errors+=new/scriptError/BadToken(curToken)
continue
ntok=tokens[index+1]
if(!istype(ntok, /token/symbol))
errors+=new/scriptError/BadToken(ntok)
continue
if(ntok.value=="(")
ParseFunctionStatement()
else if(options.assign_operators.Find(ntok.value))
ParseAssignment()
else
errors+=new/scriptError/BadToken(ntok)
continue
if(!istype(curToken, /token/end))
errors+=new/scriptError/ExpectedToken(";", curToken)
continue
if(/token/symbol)
if(curToken.value=="}")
if(!EndBlock())
errors+=new/scriptError/BadToken(curToken)
continue
else
errors+=new/scriptError/BadToken(curToken)
continue
if(/token/end)
warnings+=new/scriptError/BadToken(curToken)
continue
else
errors+=new/scriptError/BadToken(curToken)
return
return global_block
/n_Parser/nS_Parser/proc/CheckToken(val, type, err=1, skip=1)
if(curToken.value!=val || !istype(curToken,type))
if(err)
errors+=new/scriptError/ExpectedToken(val, curToken)
return 0
if(skip)NextToken()
return 1
/n_Parser/nS_Parser/proc/AddBlock(node/BlockDefinition/B)
blocks.Push(curBlock)
curBlock=B
/n_Parser/nS_Parser/proc/EndBlock()
if(curBlock==global_block) return 0
curBlock=blocks.Pop()
return 1
/n_Parser/nS_Parser/proc/ParseAssignment()
var/name=curToken.value
if(!options.IsValidID(name))
errors+=new/scriptError/InvalidID(curToken)
return
NextToken()
var/t=options.binary_operators[options.assign_operators[curToken.value]]
var/node/statement/VariableAssignment/stmt=new()
stmt.var_name=new(name)
NextToken()
if(t)
stmt.value=new t()
stmt.value:exp=new/node/expression/value/variable(stmt.var_name)
stmt.value:exp2=ParseExpression()
else
stmt.value=ParseExpression()
curBlock.statements+=stmt
/n_Parser/nS_Parser/proc/ParseFunctionStatement()
if(!istype(curToken, /token/word))
errors+=new/scriptError("Bad identifier in function call.")
return
var/node/statement/FunctionCall/stmt=new
stmt.func_name=curToken.value
NextToken() //skip function name
if(!CheckToken("(", /token/symbol)) //Check for and skip open parenthesis
return
var/loops = 0
while(TRUE)
loops++
if(loops>=6000)
CRASH("Something TERRIBLE has gone wrong in ParseFunctionStatement ;__;")
if(!curToken)
errors+=new/scriptError/EndOfFile()
return
if(istype(curToken, /token/symbol) && curToken.value==")")
curBlock.statements+=stmt
NextToken() //Skip close parenthesis
return
var/node/expression/P=ParseParamExpression()
stmt.parameters+=P
if(istype(curToken, /token/symbol) && curToken.value==",") NextToken()

View File

@@ -1,273 +0,0 @@
/*
File: Scanner
*/
/*
Class: n_Scanner
An object responsible for breaking up source code into tokens for use by the parser.
*/
/n_Scanner
var/code
/*
Var: errors
A list of fatal errors found by the scanner. If there are any items in this list, then it is not safe to parse the returned tokens.
See Also:
- <scriptError>
*/
var/list/errors = new
/*
Var: warnings
A list of non-fatal problems in the source code found by the scanner.
*/
var/list/warnings = new
/*
Proc: LoadCode
Loads source code.
*/
/n_Scanner/proc/LoadCode(c)
code=c
/*
Proc: LoadCodeFromFile
Gets the code from a file and calls <LoadCode()>.
*/
/n_Scanner/proc/LoadCodeFromFile(f)
LoadCode(file2text(f))
/*
Proc: Scan
Runs the scanner and returns the resulting list of tokens. Ensure that <LoadCode()> has been called first.
*/
/n_Scanner/proc/Scan()
/*
Class: nS_Scanner
A scanner implementation for n_Script.
*/
/n_Scanner/nS_Scanner
/*
Variable: codepos
The scanner's position in the source code.
*/
var/codepos = 1
var/line = 1
var/linepos = 0 //column=codepos-linepos
var/n_scriptOptions/nS_Options/options
var/commenting = 0 /// 1 is a single-line comment, 2 is a multi-line comment
/*
Variable: ignore
A list of characters that are ignored by the scanner.
Default Value:
Whitespace
*/
var/list/ignore = list(" ", "\t", "\n") //Don't add tokens for whitespace
/*
Variable: end_stmt
A list of characters that end a statement. Each item may only be one character long.
Default Value:
Semicolon
*/
var/list/end_stmt = list(";")
/*
Variable: string_delim
A list of characters that can start and end strings.
Default Value:
Double and single quotes.
*/
var/list/string_delim = list("\"", "'")
/*
Variable: delim
A list of characters that denote the start of a new token. This list is automatically populated.
*/
var/list/delim = new
/*
Macro: COL
The current column number.
*/
#define COL codepos-linepos
/*
Constructor: New
Parameters:
code - The source code to tokenize.
options - An <nS_Options> object used to configure the scanner.
*/
/n_Scanner/nS_Scanner/New(code, n_scriptOptions/nS_Options/options)
.=..()
ignore+= ascii2text(13) //Carriage return
delim += ignore + options.symbols + end_stmt + string_delim
src.options=options
LoadCode(code)
/n_Scanner/nS_Scanner/Scan() //Creates a list of tokens from source code
var/list/tokens=new
for(, src.codepos<=length(code), src.codepos++)
var/char=copytext(code, codepos, codepos+1)
if(char=="\n")
line++
linepos=codepos
if(ignore.Find(char))
continue
else if(char == "/")
ReadComment()
else if(end_stmt.Find(char))
tokens+=new /token/end(char, line, COL)
else if(string_delim.Find(char))
codepos++ //skip string delimiter
tokens+=ReadString(char)
else if(options.CanStartID(char))
tokens+=ReadWord()
else if(options.IsDigit(char))
tokens+=ReadNumber()
else if(options.symbols.Find(char))
tokens+=ReadSymbol()
codepos=initial(codepos)
line=initial(line)
linepos=initial(linepos)
return tokens
/*
Proc: ReadString
Reads a string in the source code into a token.
Parameters:
start - The character used to start the string.
*/
/n_Scanner/nS_Scanner/proc/ReadString(start)
var/buf
for(, codepos <= length(code), codepos++)//codepos to length(code))
var/char=copytext(code, codepos, codepos+1)
switch(char)
if("\\") //Backslash (\) encountered in string
codepos++ //Skip next character in string, since it was escaped by a backslash
char=copytext(code, codepos, codepos+1)
switch(char)
if("\\") //Double backslash
buf+="\\"
if("n") //\n Newline
buf+="\n"
else
if(char==start) //\" Doublequote
buf+=start
else //Unknown escaped text
buf+=char
if("\n")
. = new/token/string(buf, line, COL)
errors+=new/scriptError("Unterminated string. Newline reached.", .)
line++
linepos=codepos
break
else
if(char==start) //string delimiter found, end string
break
else
buf+=char //Just a normal character in a string
if(!.) return new/token/string(buf, line, COL)
/*
Proc: ReadWord
Reads characters separated by an item in <delim> into a token.
*/
/n_Scanner/nS_Scanner/proc/ReadWord()
var/char=copytext(code, codepos, codepos+1)
var/buf
while(!delim.Find(char) && codepos<=length(code))
buf+=char
char=copytext(code, ++codepos, codepos+1)
codepos-- //allow main Scan() proc to read the delimiter
if(options.keywords.Find(buf))
return new /token/keyword(buf, line, COL)
else
return new /token/word(buf, line, COL)
/*
Proc: ReadSymbol
Reads a symbol into a token.
*/
/n_Scanner/nS_Scanner/proc/ReadSymbol()
var/char=copytext(code, codepos, codepos+1)
var/buf
while(options.symbols.Find(buf+char))
buf+=char
if(++codepos>length(code)) break
char=copytext(code, codepos, codepos+1)
codepos-- //allow main Scan() proc to read the next character
return new /token/symbol(buf, line, COL)
/*
Proc: ReadNumber
Reads a number into a token.
*/
/n_Scanner/nS_Scanner/proc/ReadNumber()
var/char=copytext(code, codepos, codepos+1)
var/buf
var/dec=0
while(options.IsDigit(char) || (char=="." && !dec))
if(char==".") dec=1
buf+=char
codepos++
char=copytext(code, codepos, codepos+1)
var/token/number/T=new(buf, line, COL)
if(isnull(text2num(buf)))
errors+=new/scriptError("Bad number: ", T)
T.value=0
codepos-- //allow main Scan() proc to read the next character
return T
/*
Proc: ReadComment
Reads a comment and outputs the type of comment
*/
/n_Scanner/nS_Scanner/proc/ReadComment()
var/char=copytext(code, codepos, codepos+1)
var/nextchar=copytext(code, codepos+1, codepos+2)
var/charstring = char+nextchar
var/comm = 1
// 1: single-line comment
// 2: multi-line comment
var/expectedend = 0
if(charstring == "//" || charstring == "/*")
if(charstring == "/*")
comm = 2 // starts a multi-line comment
while(comm)
if(++codepos>length(code)) break
if(expectedend) // ending statement expected...
char = copytext(code, codepos, codepos+1)
if(char == "/") // ending statement found - beak the comment
comm = 0
break
if(comm == 2)
// multi-line comments are broken by ending statements
char = copytext(code, codepos, codepos+1)
if(char == "*")
expectedend = 1
continue
else
char = copytext(code, codepos, codepos+1)
if(char == "\n")
comm = 0
break
if(expectedend) expectedend = 0
if(comm == 2)
errors+=new/scriptError/UnterminatedComment()

View File

@@ -1,37 +0,0 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
Class: Token
Represents an entity and position in the source code.
*/
/token
var/value
var/line
var/column
/token/New(v, l=0, c=0)
value=v
line=l
column=c
/token/string
/token/symbol
/token/word
/token/keyword
/token/number/New()
.=..()
if(!isnum(value))
value=text2num(value)
ASSERT(!isnull(value))
/token/accessor
var/object
var/member
/token/accessor/New(object, member, l=0, c=0)
src.object=object
src.member=member
src.value="[object].[member]" //for debugging only
src.line=l
src.column=c
/token/end

View File

@@ -1,21 +0,0 @@
/stack
var/list/contents=new
/stack/proc/Push(value)
contents+=value
/stack/proc/Pop()
if(!contents.len) return null
. = contents[contents.len]
contents.len--
/stack/proc/Top() //returns the item on the top of the stack without removing it
if(!contents.len) return null
return contents[contents.len]
/stack/proc/Copy()
var/stack/S=new()
S.contents=src.contents.Copy()
return S
/stack/proc/Clear()
contents.Cut()

View File

@@ -8,7 +8,7 @@
var/list/shuttle_area // Initial value can be either a single area type or a list of area types
var/obj/effect/shuttle_landmark/current_location //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/tmp/arrive_time = 0 //the time at which the shuttle arrives when long jumping
var/arrive_time = 0 //the time at which the shuttle arrives when long jumping
var/flags = SHUTTLE_FLAGS_NONE
var/process_state = IDLE_STATE // Used with SHUTTLE_FLAGS_PROCESS, as well as to store current state.
var/category = /datum/shuttle
@@ -28,7 +28,7 @@
var/mothershuttle //tag of mothershuttle
var/motherdock //tag of mothershuttle landmark, defaults to starting location
var/tmp/depart_time = 0 //Similar to above, set when the shuttle leaves when long jumping. Used for progress bars.
var/depart_time = 0 //Similar to above, set when the shuttle leaves when long jumping. Used for progress bars.
var/debug_logging = FALSE // If set to true, the shuttle will start broadcasting its debug messages to admins

View File

@@ -10,7 +10,7 @@
var/datum/embedded_program/docking/shuttle_docking_controller // Controller on the shuttle (the one in use)
var/docking_codes
var/tmp/obj/effect/shuttle_landmark/next_location //This is only used internally.
var/obj/effect/shuttle_landmark/next_location //This is only used internally.
var/datum/embedded_program/docking/active_docking_controller // Controller we are docked with (or trying to)
var/obj/effect/shuttle_landmark/landmark_transition //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.

View File

@@ -10,9 +10,9 @@
var/obj/structure/lift/panel/control_panel_interior // Lift control panel.
var/doors_closing = 0 // Whether doors are in the process of closing
var/tmp/moving_upwards
var/tmp/busy_state // Used for controller processing.
var/tmp/next_process // world.time process() should next do something
var/moving_upwards
var/busy_state // Used for controller processing.
var/next_process // world.time process() should next do something
/datum/turbolift/proc/emergency_stop()
queued_floors.Cut()

View File

@@ -456,7 +456,6 @@
#include "code\defines\procs\announce.dm"
#include "code\defines\procs\AStar.dm"
#include "code\defines\procs\dbcore.dm"
#include "code\defines\procs\radio.dm"
#include "code\defines\procs\statistics.dm"
#include "code\game\atoms.dm"
#include "code\game\atoms_movable.dm"
@@ -804,13 +803,19 @@
#include "code\game\machinery\pipe\pipe_dispenser.dm"
#include "code\game\machinery\pipe\pipe_recipes.dm"
#include "code\game\machinery\pipe\pipelayer.dm"
#include "code\game\machinery\telecomms\allinone.dm"
#include "code\game\machinery\telecomms\broadcaster.dm"
#include "code\game\machinery\telecomms\bus.dm"
#include "code\game\machinery\telecomms\hub.dm"
#include "code\game\machinery\telecomms\logbrowser.dm"
#include "code\game\machinery\telecomms\machine_interactions.dm"
#include "code\game\machinery\telecomms\misc.dm"
#include "code\game\machinery\telecomms\presets.dm"
#include "code\game\machinery\telecomms\telecommunications.dm"
#include "code\game\machinery\telecomms\processor.dm"
#include "code\game\machinery\telecomms\receiver.dm"
#include "code\game\machinery\telecomms\relay.dm"
#include "code\game\machinery\telecomms\server.dm"
#include "code\game\machinery\telecomms\telecomms.dm"
#include "code\game\machinery\telecomms\telemonitor.dm"
#include "code\game\machinery\telecomms\traffic_control.dm"
#include "code\game\machinery\virtual_reality\ar_console.dm"
#include "code\game\machinery\virtual_reality\vr_console.dm"
#include "code\game\magic\Uristrunes.dm"
@@ -3058,26 +3063,6 @@
#include "code\modules\research\designs\circuits\ai_modules.dm"
#include "code\modules\research\designs\circuits\circuits.dm"
#include "code\modules\research\designs\circuits\disks.dm"
#include "code\modules\scripting\Errors.dm"
#include "code\modules\scripting\IDE.dm"
#include "code\modules\scripting\Options.dm"
#include "code\modules\scripting\stack.dm"
#include "code\modules\scripting\AST\AST Nodes.dm"
#include "code\modules\scripting\AST\Blocks.dm"
#include "code\modules\scripting\AST\Statements.dm"
#include "code\modules\scripting\AST\Operators\Binary Operators.dm"
#include "code\modules\scripting\AST\Operators\Unary Operators.dm"
#include "code\modules\scripting\Implementations\_Logic.dm"
#include "code\modules\scripting\Implementations\Telecomms.dm"
#include "code\modules\scripting\Interpreter\Evaluation.dm"
#include "code\modules\scripting\Interpreter\Interaction.dm"
#include "code\modules\scripting\Interpreter\Interpreter.dm"
#include "code\modules\scripting\Interpreter\Scope.dm"
#include "code\modules\scripting\Parser\Expressions.dm"
#include "code\modules\scripting\Parser\Keywords.dm"
#include "code\modules\scripting\Parser\Parser.dm"
#include "code\modules\scripting\Scanner\Scanner.dm"
#include "code\modules\scripting\Scanner\Tokens.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security levels\security levels.dm"
#include "code\modules\shieldgen\directional_shield.dm"

View File

@@ -142,10 +142,8 @@ const TelecommsMultitoolMenuPolymorphicOptions = (props, context) => {
const {
// Relay
use_listening_level,
use_broadcasting,
use_receiving,
listening_level,
broadcasting,
receiving,
// Bus
@@ -160,22 +158,13 @@ const TelecommsMultitoolMenuPolymorphicOptions = (props, context) => {
} = props.options;
// If absolutely nothing is active, we tell the user there ain't no shit here.
if (!use_listening_level && !use_broadcasting && !use_receiving
&& !use_change_freq && !use_broadcast_range && !use_receive_range) {
if (!use_broadcasting && !use_receiving && !use_change_freq && !use_broadcast_range && !use_receive_range) {
return <Section title="No Options Found" />;
}
return (
<Section title="Options">
<LabeledList>
{use_listening_level ? (
<LabeledList.Item label="Signal Locked to Station">
<Button
icon={listening_level ? "lock-closed" : "lock-open"}
content={listening_level ? "Yes" : "No"}
onClick={() => act("change_listening")} />
</LabeledList.Item>
) : null}
{use_broadcasting ? (
<LabeledList.Item label="Broadcasting">
<Button
@@ -219,4 +208,4 @@ const TelecommsMultitoolMenuPolymorphicOptions = (props, context) => {
</LabeledList>
</Section>
);
};
};

File diff suppressed because one or more lines are too long