mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-11 10:42:40 +00:00
Merge pull request #9300 from Spookerton/spkrtn/del/remove-tcomms-scripting
remove tcomms scripting
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
122
code/game/machinery/telecomms/allinone.dm
Normal file
122
code/game/machinery/telecomms/allinone.dm
Normal 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
|
||||
)
|
||||
@@ -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))
|
||||
|
||||
71
code/game/machinery/telecomms/bus.dm
Normal file
71
code/game/machinery/telecomms/bus.dm
Normal 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")
|
||||
32
code/game/machinery/telecomms/hub.dm
Normal file
32
code/game/machinery/telecomms/hub.dm
Normal 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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
567
code/game/machinery/telecomms/misc.dm
Normal file
567
code/game/machinery/telecomms/misc.dm
Normal 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
|
||||
@@ -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")
|
||||
|
||||
27
code/game/machinery/telecomms/processor.dm
Normal file
27
code/game/machinery/telecomms/processor.dm
Normal 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)
|
||||
89
code/game/machinery/telecomms/receiver.dm
Normal file
89
code/game/machinery/telecomms/receiver.dm
Normal 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))
|
||||
79
code/game/machinery/telecomms/relay.dm
Normal file
79
code/game/machinery/telecomms/relay.dm
Normal 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
|
||||
109
code/game/machinery/telecomms/server.dm
Normal file
109
code/game/machinery/telecomms/server.dm
Normal 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
|
||||
380
code/game/machinery/telecomms/telecomms.dm
Normal file
380
code/game/machinery/telecomms/telecomms.dm
Normal 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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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]")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ..()
|
||||
@@ -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
|
||||
@@ -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)."
|
||||
@@ -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")
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
.=..()
|
||||
@@ -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
|
||||
@@ -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(",", ")"))
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
33
polaris.dme
33
polaris.dme
@@ -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"
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user