mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-25 01:22:13 +00:00
Ports /tg/ spatial grid system, refactors telecomms, destroys lag (#15140)
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
#include "code\__defines\ghostspawner.dm"
|
||||
#include "code\__defines\guns.dm"
|
||||
#include "code\__defines\hydroponics.dm"
|
||||
#include "code\__defines\important_recursive_contents.dm"
|
||||
#include "code\__defines\items_clothing.dm"
|
||||
#include "code\__defines\jobs.dm"
|
||||
#include "code\__defines\lighting.dm"
|
||||
@@ -68,6 +69,7 @@
|
||||
#include "code\__defines\shuttle.dm"
|
||||
#include "code\__defines\space_sectors.dm"
|
||||
#include "code\__defines\spaceman_dmm.dm"
|
||||
#include "code\__defines\spatial_gridmap.dm"
|
||||
#include "code\__defines\species.dm"
|
||||
#include "code\__defines\species_languages.dm"
|
||||
#include "code\__defines\subsystem-defines.dm"
|
||||
@@ -75,6 +77,7 @@
|
||||
#include "code\__defines\targeting.dm"
|
||||
#include "code\__defines\tgs.dm"
|
||||
#include "code\__defines\time.dm"
|
||||
#include "code\__defines\traits.dm"
|
||||
#include "code\__defines\turfs.dm"
|
||||
#include "code\__defines\vueui.dm"
|
||||
#include "code\__defines\webhook.dm"
|
||||
@@ -106,6 +109,7 @@
|
||||
#include "code\_helpers\names.dm"
|
||||
#include "code\_helpers\overlay.dm"
|
||||
#include "code\_helpers\sanitize_values.dm"
|
||||
#include "code\_helpers\spatial_info.dm"
|
||||
#include "code\_helpers\spawn_sync.dm"
|
||||
#include "code\_helpers\text.dm"
|
||||
#include "code\_helpers\time.dm"
|
||||
@@ -207,6 +211,7 @@
|
||||
#include "code\controllers\subsystems\records.dm"
|
||||
#include "code\controllers\subsystems\responseteam.dm"
|
||||
#include "code\controllers\subsystems\skybox.dm"
|
||||
#include "code\controllers\subsystems\spatial_gridmap.dm"
|
||||
#include "code\controllers\subsystems\statistics.dm"
|
||||
#include "code\controllers\subsystems\stickyban.dm"
|
||||
#include "code\controllers\subsystems\sun.dm"
|
||||
@@ -765,7 +770,6 @@
|
||||
#include "code\game\machinery\computer\computer.dm"
|
||||
#include "code\game\machinery\computer\guestpass.dm"
|
||||
#include "code\game\machinery\computer\law.dm"
|
||||
#include "code\game\machinery\computer\message.dm"
|
||||
#include "code\game\machinery\computer\Operating.dm"
|
||||
#include "code\game\machinery\computer\pod.dm"
|
||||
#include "code\game\machinery\computer\RCON_Console.dm"
|
||||
@@ -798,13 +802,22 @@
|
||||
#include "code\game\machinery\embedded_controller\simple_docking_controller.dm"
|
||||
#include "code\game\machinery\pipe\construction.dm"
|
||||
#include "code\game\machinery\pipe\pipe_dispenser.dm"
|
||||
#include "code\game\machinery\telecomms\broadcaster.dm"
|
||||
#include "code\game\machinery\telecomms\logbrowser.dm"
|
||||
#include "code\game\machinery\telecomms\broadcasting.dm"
|
||||
#include "code\game\machinery\telecomms\machine_interactions.dm"
|
||||
#include "code\game\machinery\telecomms\presets.dm"
|
||||
#include "code\game\machinery\telecomms\telecomunications.dm"
|
||||
#include "code\game\machinery\telecomms\telemonitor.dm"
|
||||
#include "code\game\machinery\telecomms\traffic_control.dm"
|
||||
#include "code\game\machinery\telecomms\telecommunications.dm"
|
||||
#include "code\game\machinery\telecomms\computers\logbrowser.dm"
|
||||
#include "code\game\machinery\telecomms\computers\message.dm"
|
||||
#include "code\game\machinery\telecomms\computers\telemonitor.dm"
|
||||
#include "code\game\machinery\telecomms\computers\traffic_control.dm"
|
||||
#include "code\game\machinery\telecomms\machines\allinone.dm"
|
||||
#include "code\game\machinery\telecomms\machines\broadcaster.dm"
|
||||
#include "code\game\machinery\telecomms\machines\bus.dm"
|
||||
#include "code\game\machinery\telecomms\machines\hub.dm"
|
||||
#include "code\game\machinery\telecomms\machines\message_server.dm"
|
||||
#include "code\game\machinery\telecomms\machines\processor.dm"
|
||||
#include "code\game\machinery\telecomms\machines\receiver.dm"
|
||||
#include "code\game\machinery\telecomms\machines\server.dm"
|
||||
#include "code\game\modifiers\modifiers.dm"
|
||||
#include "code\game\objects\buckling.dm"
|
||||
#include "code\game\objects\empulse.dm"
|
||||
@@ -2876,7 +2889,6 @@
|
||||
#include "code\modules\recycling\sortingmachinery.dm"
|
||||
#include "code\modules\research\circuitprinter.dm"
|
||||
#include "code\modules\research\destructive_analyzer.dm"
|
||||
#include "code\modules\research\message_server.dm"
|
||||
#include "code\modules\research\protolathe.dm"
|
||||
#include "code\modules\research\rd-readme.dm"
|
||||
#include "code\modules\research\rdconsole.dm"
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
|
||||
|
||||
/// Signifies that this proc is used to handle signals.
|
||||
/// Every proc you pass to RegisterSignal must have this.
|
||||
#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
|
||||
#define AddElement(arguments...) _AddElement(list(##arguments))
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
// global signals
|
||||
// These are signals which can be listened to by any component on any parent
|
||||
|
||||
// when we expand maxz
|
||||
#define COMSIG_GLOB_NEW_Z "!new_z"
|
||||
// when we expand maxx and maxy (do we ever do this)
|
||||
#define COMSIG_GLOB_EXPANDED_WORLD_BOUNDS "!expanded_world_bounds"
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// /datum signals
|
||||
@@ -29,6 +34,20 @@
|
||||
// /turf signals
|
||||
|
||||
// /atom/movable signals
|
||||
#define COMSIG_MOVABLE_MOVED "movable_moved"
|
||||
|
||||
#define COMSIG_MOVABLE_HEAR "movable_hear"
|
||||
#define HEARING_MESSAGE 1
|
||||
#define HEARING_SPEAKER 2
|
||||
#define HEARING_LANGUAGE 3
|
||||
#define HEARING_RAW_MESSAGE 4
|
||||
|
||||
//spatial grid signals
|
||||
|
||||
///Called from base of /datum/controller/subsystem/spatial_grid/proc/enter_cell: (/atom/movable)
|
||||
#define SPATIAL_GRID_CELL_ENTERED(contents_type) "spatial_grid_cell_entered_[contents_type]"
|
||||
///Called from base of /datum/controller/subsystem/spatial_grid/proc/exit_cell: (/atom/movable)
|
||||
#define SPATIAL_GRID_CELL_EXITED(contents_type) "spatial_grid_cell_exited_[contents_type]"
|
||||
|
||||
// /mob signals
|
||||
|
||||
|
||||
7
code/__defines/important_recursive_contents.dm
Normal file
7
code/__defines/important_recursive_contents.dm
Normal file
@@ -0,0 +1,7 @@
|
||||
// the area channel of the important_recursive_contents list, everything in here will be sent a signal when their last holding object changes areas
|
||||
#define RECURSIVE_CONTENTS_AREA_SENSITIVE "recursive_contents_area_sensitive"
|
||||
// the hearing channel of the important_recursive_contents list, everything in here will count as a hearing atom
|
||||
#define RECURSIVE_CONTENTS_HEARING_SENSITIVE "recursive_contents_hearing_sensitive"
|
||||
// the client mobs channel of the important_recursive_contents list, everything in here will be a mob with an attached client
|
||||
// this is given to both a clients mob, and a clients eye, both point to the clients mob
|
||||
#define RECURSIVE_CONTENTS_CLIENT_MOBS "recursive_contents_client_mobs"
|
||||
@@ -10,6 +10,15 @@
|
||||
#define LAZYPICK(L,DEFAULT) (LAZYLEN(L) ? pick(L) : DEFAULT)
|
||||
#define LAZYISIN(L, I) (L ? (I in L) : FALSE)
|
||||
#define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I;
|
||||
#define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V);
|
||||
#define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; }
|
||||
#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null
|
||||
|
||||
/// Performs an insertion on the given lazy list with the given key and value. If the value already exists, a new one will not be made.
|
||||
#define LAZYORASSOCLIST(lazy_list, key, value) \
|
||||
LAZYINITLIST(lazy_list); \
|
||||
LAZYINITLIST(lazy_list[key]); \
|
||||
lazy_list[key] |= value;
|
||||
|
||||
// Shims for some list procs in lists.dm.
|
||||
#define isemptylist(L) (!LAZYLEN(L))
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define TCMB 2.7 // -270.3 degrees celcius
|
||||
|
||||
#define QUANTIZE(variable) (round(variable,0.0001))
|
||||
#define ROUND_UP(x) ( -round(-(x)))
|
||||
#define CEILING(x, y) ( -round(-(x) / (y)) * (y) )
|
||||
|
||||
#define INFINITY 1.#INF
|
||||
|
||||
@@ -2,36 +2,42 @@
|
||||
#define PUBLIC_LOW_FREQ 1441
|
||||
#define PUBLIC_HIGH_FREQ 1489
|
||||
#define RADIO_HIGH_FREQ 1600
|
||||
// Reminder: frequencies should only be odd numbers
|
||||
|
||||
// Public frequencies (no encryption key required), see range above
|
||||
#define BOT_FREQ 1447
|
||||
#define COMM_FREQ 1353
|
||||
#define ERT_FREQ 1345
|
||||
#define AI_FREQ 1343
|
||||
#define DTH_FREQ 1341
|
||||
#define PEN_FREQ 1451
|
||||
#define PUB_FREQ 1459
|
||||
#define ENT_FREQ 1461
|
||||
#define HAIL_FREQ 1463
|
||||
#define SEC_I_FREQ 1475
|
||||
#define MED_I_FREQ 1485
|
||||
|
||||
// Department / private frequencies
|
||||
|
||||
#define SYND_FREQ 1213
|
||||
#define BLSP_FREQ 1253
|
||||
#define NINJ_FREQ 1255
|
||||
#define BURG_FREQ 1257
|
||||
#define RAID_FREQ 1277
|
||||
#define SHIP_FREQ 1280
|
||||
#define ENT_FREQ 1461 //entertainment frequency. This is not a diona exclusive frequency.
|
||||
#define DTH_FREQ 1341
|
||||
#define AI_FREQ 1343
|
||||
#define ERT_FREQ 1345
|
||||
#define COMM_FREQ 1353
|
||||
|
||||
// department channels
|
||||
var/const/PUB_FREQ = 1459
|
||||
var/const/PEN_FREQ = 1451
|
||||
var/const/SEC_FREQ = 1359
|
||||
var/const/ENG_FREQ = 1357
|
||||
var/const/MED_FREQ = 1355
|
||||
var/const/SCI_FREQ = 1351
|
||||
var/const/SRV_FREQ = 1349
|
||||
var/const/SUP_FREQ = 1347
|
||||
#define SUP_FREQ 1347
|
||||
#define SRV_FREQ 1349
|
||||
#define SCI_FREQ 1351
|
||||
#define MED_FREQ 1355
|
||||
#define ENG_FREQ 1357
|
||||
#define SEC_FREQ 1359
|
||||
|
||||
// internal department channels
|
||||
#define MED_I_FREQ 1485
|
||||
#define SEC_I_FREQ 1475
|
||||
var/list/AWAY_FREQS_UNASSIGNED = list(1491, 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509)
|
||||
var/list/AWAY_FREQS_ASSIGNED = list("Hailing" = HAIL_FREQ)
|
||||
|
||||
var/list/radiochannels = list(
|
||||
"Common" = PUB_FREQ,
|
||||
"Hailing" = HAIL_FREQ,
|
||||
"Science" = SCI_FREQ,
|
||||
"Command" = COMM_FREQ,
|
||||
"Medical" = MED_FREQ,
|
||||
@@ -50,8 +56,31 @@ var/list/radiochannels = list(
|
||||
"AI Private" = AI_FREQ,
|
||||
"Entertainment" = ENT_FREQ,
|
||||
"Medical (I)" = MED_I_FREQ,
|
||||
"Security (I)" = SEC_I_FREQ,
|
||||
"Ship" = SHIP_FREQ
|
||||
"Security (I)" = SEC_I_FREQ
|
||||
)
|
||||
|
||||
var/list/reverseradiochannels = list(
|
||||
"[PUB_FREQ]" = "Common",
|
||||
"[HAIL_FREQ]" = "Hailing",
|
||||
"[SCI_FREQ]" = "Science",
|
||||
"[COMM_FREQ]" = "Command",
|
||||
"[MED_FREQ]" = "Medical",
|
||||
"[ENG_FREQ]" = "Engineering",
|
||||
"[SEC_FREQ]" = "Security",
|
||||
"[PEN_FREQ]" = "Penal",
|
||||
"[ERT_FREQ]" = "Response Team",
|
||||
"[DTH_FREQ]" = "Special Ops",
|
||||
"[SYND_FREQ]" = "Mercenary",
|
||||
"[NINJ_FREQ]" = "Ninja",
|
||||
"[BLSP_FREQ]" = "Bluespace",
|
||||
"[BURG_FREQ]" = "Burglar",
|
||||
"[RAID_FREQ]" = "Raider",
|
||||
"[SUP_FREQ]" = "Operations",
|
||||
"[SRV_FREQ]" = "Service",
|
||||
"[AI_FREQ]" = "AI Private",
|
||||
"[ENT_FREQ]" = "Entertainment",
|
||||
"[MED_I_FREQ]" = "Medical (I)",
|
||||
"[SEC_I_FREQ]" = "Security (I)"
|
||||
)
|
||||
|
||||
// The assoc variants are separate lists because they need the keys to be strings, but some code expects numbers.
|
||||
@@ -80,7 +109,8 @@ var/list/ANTAG_FREQS_ASSOC = list(
|
||||
"[SYND_FREQ]" = TRUE,
|
||||
"[RAID_FREQ]" = TRUE,
|
||||
"[NINJ_FREQ]" = TRUE,
|
||||
"[BURG_FREQ]" = TRUE
|
||||
"[BURG_FREQ]" = TRUE,
|
||||
"[BLSP_FREQ]" = TRUE
|
||||
)
|
||||
|
||||
//Department channels, arranged lexically
|
||||
@@ -93,8 +123,7 @@ var/list/DEPT_FREQS = list(
|
||||
SCI_FREQ,
|
||||
SRV_FREQ,
|
||||
SUP_FREQ,
|
||||
ENT_FREQ,
|
||||
SHIP_FREQ
|
||||
ENT_FREQ
|
||||
)
|
||||
|
||||
var/list/DEPT_FREQS_ASSOC = list(
|
||||
@@ -110,8 +139,11 @@ var/list/DEPT_FREQS_ASSOC = list(
|
||||
)
|
||||
|
||||
#define TRANSMISSION_WIRE 0 // Wired transmission, unused at the moment
|
||||
#define TRANSMISSION_RADIO 1
|
||||
#define TRANSMISSION_SUBSPACE 2
|
||||
#define TRANSMISSION_RADIO 1 // Default radiowave transmission
|
||||
#define TRANSMISSION_SUBSPACE 2 // Subspace transmission (headsets)
|
||||
#define TRANSMISSION_SUPERSPACE 3 // Independent / CentCom radios only
|
||||
|
||||
#define RADIO_NO_Z_LEVEL_RESTRICTION 0
|
||||
|
||||
/* filters */
|
||||
//When devices register with the radio controller, they might register under a certain filter.
|
||||
|
||||
16
code/__defines/spatial_gridmap.dm
Normal file
16
code/__defines/spatial_gridmap.dm
Normal file
@@ -0,0 +1,16 @@
|
||||
// Each cell in a spatial_grid is this many turfs in length and width
|
||||
#define SPATIAL_GRID_CELLSIZE 17
|
||||
|
||||
#define SPATIAL_GRID_CELLS_PER_SIDE(world_bounds) ROUND_UP((world_bounds) / SPATIAL_GRID_CELLSIZE)
|
||||
|
||||
#define SPATIAL_GRID_CHANNELS 2
|
||||
|
||||
// grid contents channels
|
||||
|
||||
// Everything that is hearing sensitive is stored in this channel
|
||||
#define SPATIAL_GRID_CONTENTS_TYPE_HEARING RECURSIVE_CONTENTS_HEARING_SENSITIVE
|
||||
// Every movable that has a client in it is stored in this channel
|
||||
#define SPATIAL_GRID_CONTENTS_TYPE_CLIENTS RECURSIVE_CONTENTS_CLIENT_MOBS
|
||||
|
||||
// Whether movable is itself or containing something which should be in one of the spatial grid channels
|
||||
#define HAS_SPATIAL_GRID_CONTENTS(movable) (movable.important_recursive_contents && (movable.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE] || movable.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]))
|
||||
144
code/__defines/traits.dm
Normal file
144
code/__defines/traits.dm
Normal file
@@ -0,0 +1,144 @@
|
||||
#define SIGNAL_ADDTRAIT(trait_ref) "addtrait [trait_ref]"
|
||||
#define SIGNAL_REMOVETRAIT(trait_ref) "removetrait [trait_ref]"
|
||||
// trait accessor defines
|
||||
#define ADD_TRAIT(target, trait, source) \
|
||||
do { \
|
||||
var/list/_L; \
|
||||
if (!target.status_traits) { \
|
||||
target.status_traits = list(); \
|
||||
_L = target.status_traits; \
|
||||
_L[trait] = list(source); \
|
||||
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
|
||||
} else { \
|
||||
_L = target.status_traits; \
|
||||
if (_L[trait]) { \
|
||||
_L[trait] |= list(source); \
|
||||
} else { \
|
||||
_L[trait] = list(source); \
|
||||
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#define REMOVE_TRAIT(target, trait, sources) \
|
||||
do { \
|
||||
var/list/_L = target.status_traits; \
|
||||
var/list/_S; \
|
||||
if (sources && !islist(sources)) { \
|
||||
_S = list(sources); \
|
||||
} else { \
|
||||
_S = sources\
|
||||
}; \
|
||||
if (_L && _L[trait]) { \
|
||||
for (var/_T in _L[trait]) { \
|
||||
if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \
|
||||
_L[trait] -= _T \
|
||||
} \
|
||||
};\
|
||||
if (!length(_L[trait])) { \
|
||||
_L -= trait; \
|
||||
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
|
||||
}; \
|
||||
if (!length(_L)) { \
|
||||
target.status_traits = null \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
#define REMOVE_TRAIT_NOT_FROM(target, trait, sources) \
|
||||
do { \
|
||||
var/list/_traits_list = target.status_traits; \
|
||||
var/list/_sources_list; \
|
||||
if (sources && !islist(sources)) { \
|
||||
_sources_list = list(sources); \
|
||||
} else { \
|
||||
_sources_list = sources\
|
||||
}; \
|
||||
if (_traits_list && _traits_list[trait]) { \
|
||||
for (var/_trait_source in _traits_list[trait]) { \
|
||||
if (!(_trait_source in _sources_list)) { \
|
||||
_traits_list[trait] -= _trait_source \
|
||||
} \
|
||||
};\
|
||||
if (!length(_traits_list[trait])) { \
|
||||
_traits_list -= trait; \
|
||||
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
|
||||
}; \
|
||||
if (!length(_traits_list)) { \
|
||||
target.status_traits = null \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
#define REMOVE_TRAITS_NOT_IN(target, sources) \
|
||||
do { \
|
||||
var/list/_L = target.status_traits; \
|
||||
var/list/_S = sources; \
|
||||
if (_L) { \
|
||||
for (var/_T in _L) { \
|
||||
_L[_T] &= _S;\
|
||||
if (!length(_L[_T])) { \
|
||||
_L -= _T; \
|
||||
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \
|
||||
}; \
|
||||
};\
|
||||
if (!length(_L)) { \
|
||||
target.status_traits = null\
|
||||
};\
|
||||
}\
|
||||
} while (0)
|
||||
#define REMOVE_TRAITS_IN(target, sources) \
|
||||
do { \
|
||||
var/list/_L = target.status_traits; \
|
||||
var/list/_S = sources; \
|
||||
if (sources && !islist(sources)) { \
|
||||
_S = list(sources); \
|
||||
} else { \
|
||||
_S = sources\
|
||||
}; \
|
||||
if (_L) { \
|
||||
for (var/_T in _L) { \
|
||||
_L[_T] -= _S;\
|
||||
if (!length(_L[_T])) { \
|
||||
_L -= _T; \
|
||||
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T)); \
|
||||
}; \
|
||||
};\
|
||||
if (!length(_L)) { \
|
||||
target.status_traits = null\
|
||||
};\
|
||||
}\
|
||||
} while (0)
|
||||
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
|
||||
target.status_traits ?\
|
||||
(target.status_traits[trait] ?\
|
||||
((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\
|
||||
: FALSE)\
|
||||
: FALSE)
|
||||
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
|
||||
|
||||
// common trait sources
|
||||
#define TRAIT_GENERIC "generic"
|
||||
#define GENERIC_ITEM_TRAIT "generic_item"
|
||||
#define UNCONSCIOUS_TRAIT "unconscious"
|
||||
#define EYE_DAMAGE "eye_damage"
|
||||
#define EAR_DAMAGE "ear_damage"
|
||||
#define GENETIC_MUTATION "genetic"
|
||||
#define OBESITY "obesity"
|
||||
#define MAGIC_TRAIT "magic"
|
||||
#define TRAUMA_TRAIT "trauma"
|
||||
|
||||
/// cannot be removed without admin intervention
|
||||
#define ROUNDSTART_TRAIT "roundstart"
|
||||
#define JOB_TRAIT "job"
|
||||
|
||||
#define INNATE_TRAIT "innate"
|
||||
|
||||
//important_recursive_contents traits
|
||||
/*
|
||||
* Used for movables that need to be updated, via COMSIG_ENTER_AREA and COMSIG_EXIT_AREA, when transitioning areas.
|
||||
* Use [/atom/movable/proc/become_area_sensitive(trait_source)] to properly enable it. How you remove it isn't as important.
|
||||
*/
|
||||
#define TRAIT_AREA_SENSITIVE "area-sensitive"
|
||||
|
||||
// every hearing sensitive atom has this trait
|
||||
#define TRAIT_HEARING_SENSITIVE "hearing_sensitive"
|
||||
@@ -39,83 +39,6 @@
|
||||
|
||||
return 0 //not in range and not telekinetic
|
||||
|
||||
// Like view but bypasses luminosity check
|
||||
|
||||
/proc/hear(var/range, var/atom/source)
|
||||
|
||||
var/lum = source.luminosity
|
||||
source.luminosity = 6
|
||||
|
||||
var/list/heard = view(range, source)
|
||||
source.luminosity = lum
|
||||
|
||||
return heard
|
||||
|
||||
/proc/circlerange(center=usr,radius=3)
|
||||
|
||||
var/turf/centerturf = get_turf(center)
|
||||
var/list/turfs = new/list()
|
||||
var/rsq = radius * (radius+0.5)
|
||||
|
||||
for(var/atom/T in range(radius, centerturf))
|
||||
var/dx = T.x - centerturf.x
|
||||
var/dy = T.y - centerturf.y
|
||||
if(dx*dx + dy*dy <= rsq)
|
||||
turfs += T
|
||||
|
||||
//turfs += centerturf
|
||||
return turfs
|
||||
|
||||
/proc/circleview(center=usr,radius=3)
|
||||
|
||||
var/turf/centerturf = get_turf(center)
|
||||
var/list/atoms = new/list()
|
||||
var/rsq = radius * (radius+0.5)
|
||||
|
||||
for(var/atom/A in view(radius, centerturf))
|
||||
var/dx = A.x - centerturf.x
|
||||
var/dy = A.y - centerturf.y
|
||||
if(dx*dx + dy*dy <= rsq)
|
||||
atoms += A
|
||||
|
||||
//turfs += centerturf
|
||||
return atoms
|
||||
|
||||
/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj)
|
||||
var/dx = Loc1.x - Loc2.x
|
||||
var/dy = Loc1.y - Loc2.y
|
||||
|
||||
var/dist = sqrt(dx**2 + dy**2)
|
||||
|
||||
return dist
|
||||
|
||||
/proc/circlerangeturfs(center=usr,radius=3)
|
||||
var/turf/centerturf = get_turf(center)
|
||||
if(radius == 1)
|
||||
return list(centerturf)
|
||||
var/list/turfs = new/list()
|
||||
var/rsq = radius * (radius+0.5)
|
||||
|
||||
for(var/turf/T in range(radius, centerturf))
|
||||
var/dx = T.x - centerturf.x
|
||||
var/dy = T.y - centerturf.y
|
||||
if(dx*dx + dy*dy <= rsq)
|
||||
turfs += T
|
||||
return turfs
|
||||
|
||||
/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()?
|
||||
|
||||
var/turf/centerturf = get_turf(center)
|
||||
var/list/turfs = new/list()
|
||||
var/rsq = radius * (radius+0.5)
|
||||
|
||||
for(var/turf/T in view(radius, centerturf))
|
||||
var/dx = T.x - centerturf.x
|
||||
var/dy = T.y - centerturf.y
|
||||
if(dx*dx + dy*dy <= rsq)
|
||||
turfs += T
|
||||
return turfs
|
||||
|
||||
// Will recursively loop through an atom's locs until it finds the atom loc above a turf or its target_atom
|
||||
/proc/recursive_loc_turf_check(var/atom/O, var/recursion_limit = 3, var/atom/target_atom)
|
||||
if(recursion_limit <= 0 || isturf(O.loc) || O == target_atom)
|
||||
@@ -125,147 +48,6 @@
|
||||
recursion_limit--
|
||||
return recursive_loc_turf_check(O, recursion_limit)
|
||||
|
||||
// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents.
|
||||
// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects,
|
||||
// being unable to hear people due to being in a box within a bag.
|
||||
// Does not return list, as list is passed as reference.
|
||||
|
||||
/proc/recursive_content_check(var/atom/O, var/list/L = list(), var/recursion_limit = 3, var/client_check = 1, var/sight_check = 1, var/include_mobs = 1, var/include_objects = 1)
|
||||
|
||||
if(!recursion_limit)
|
||||
return
|
||||
|
||||
for(var/I in O.contents)
|
||||
|
||||
if(ismob(I))
|
||||
if(!sight_check || isInSight(I, O))
|
||||
recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
|
||||
if(include_mobs)
|
||||
if(client_check)
|
||||
var/mob/M = I
|
||||
if(M.client)
|
||||
L += M
|
||||
else
|
||||
L += I
|
||||
|
||||
else if(isobj(I))
|
||||
if(!sight_check || isInSight(I, O))
|
||||
recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
|
||||
if(include_objects)
|
||||
L += I
|
||||
|
||||
// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code.
|
||||
|
||||
/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios)
|
||||
|
||||
set background = 1
|
||||
|
||||
. = list()
|
||||
// Returns a list of mobs who can hear any of the radios given in @radios
|
||||
var/list/speaker_coverage = list()
|
||||
for(var/obj/item/device/radio/R in radios)
|
||||
if(R)
|
||||
//Cyborg checks. Receiving message uses a bit of cyborg's charge.
|
||||
var/obj/item/device/radio/borg/BR = R
|
||||
if(istype(BR) && BR.myborg)
|
||||
var/mob/living/silicon/robot/borg = BR.myborg
|
||||
var/datum/robot_component/CO = borg.get_component("radio")
|
||||
if(!CO)
|
||||
continue //No radio component (Shouldn't happen)
|
||||
if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage))
|
||||
continue //No power.
|
||||
|
||||
var/turf/speaker = get_turf(R)
|
||||
if(speaker)
|
||||
for(var/turf/T in hear(R.canhear_range,speaker))
|
||||
speaker_coverage[T] = T
|
||||
|
||||
var/list/listeners = player_list.Copy()
|
||||
for(var/mob/M as anything in player_list)
|
||||
if(M.old_mob)
|
||||
listeners += M.old_mob
|
||||
|
||||
// Try to find all the players who can hear the message
|
||||
for(var/mob/M as anything in listeners)
|
||||
if(M.can_hear_radio(speaker_coverage))
|
||||
. += M
|
||||
|
||||
/proc/get_mobs_or_objs_in_view(turf/T, range, list/mobs, list/objs, checkghosts = GHOSTS_ALL_HEAR)
|
||||
var/list/hear = list()
|
||||
DVIEW(hear, range, T, INVISIBILITY_MAXIMUM)
|
||||
var/list/hearturfs = list()
|
||||
|
||||
if(islist(mobs))
|
||||
for(var/mob/M in hear)
|
||||
mobs[M] = TRUE
|
||||
hearturfs[get_turf(M)] = TRUE
|
||||
|
||||
for(var/mob/M in player_list)
|
||||
#ifdef UNIT_TEST
|
||||
if(istype(M, /mob/living/test))
|
||||
mobs[M] = TRUE
|
||||
continue
|
||||
#endif
|
||||
if(checkghosts == GHOSTS_ALL_HEAR && M.stat == DEAD && !isnewplayer(M) && (M.client && M.client.prefs.toggles & CHAT_GHOSTEARS))
|
||||
mobs[M] = TRUE
|
||||
continue
|
||||
|
||||
if(M.loc && hearturfs[get_turf(M)])
|
||||
mobs[M] = TRUE
|
||||
|
||||
if(islist(objs))
|
||||
for(var/obj/O in hear)
|
||||
objs[O] = TRUE
|
||||
hearturfs[get_turf(O)] = TRUE
|
||||
|
||||
for(var/obj/O in listening_objects)
|
||||
if(O.loc && hearturfs[get_turf(O)])
|
||||
objs[O] = TRUE
|
||||
|
||||
proc
|
||||
inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
|
||||
var/turf/T
|
||||
if(X1==X2)
|
||||
if(Y1==Y2)
|
||||
return 1 //Light cannot be blocked on same tile
|
||||
else
|
||||
var/s = SIGN(Y2-Y1)
|
||||
Y1+=s
|
||||
while(Y1!=Y2)
|
||||
T=locate(X1,Y1,Z)
|
||||
if(T.opacity)
|
||||
return 0
|
||||
Y1+=s
|
||||
else
|
||||
var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
|
||||
var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
|
||||
var/signX = SIGN(X2-X1)
|
||||
var/signY = SIGN(Y2-Y1)
|
||||
if(X1<X2)
|
||||
b+=m
|
||||
while(X1!=X2 || Y1!=Y2)
|
||||
if(round(m*X1+b-Y1))
|
||||
Y1+=signY //Line exits tile vertically
|
||||
else
|
||||
X1+=signX //Line exits tile horizontally
|
||||
T=locate(X1,Y1,Z)
|
||||
if(T.opacity)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/isInSight(var/atom/A, var/atom/B)
|
||||
var/turf/Aturf = get_turf(A)
|
||||
var/turf/Bturf = get_turf(B)
|
||||
|
||||
if(!Aturf || !Bturf)
|
||||
return 0
|
||||
|
||||
if(inLineOfSight(Aturf.x,Aturf.y, Bturf.x,Bturf.y,Aturf.z))
|
||||
return 1
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
/proc/get_cardinal_step_away(atom/start, atom/finish) //returns the position of a step from start away from finish, in one of the cardinal directions
|
||||
//returns only NORTH, SOUTH, EAST, or WEST
|
||||
var/dx = finish.x - start.x
|
||||
|
||||
@@ -28,6 +28,7 @@ var/global/list/the_station_areas = list()
|
||||
var/global/list/implants = list()
|
||||
|
||||
var/global/list/turfs = list() //list of all turfs
|
||||
var/global/list/station_turfs = list()
|
||||
var/global/list/areas_by_type = list()
|
||||
var/global/list/all_areas = list()
|
||||
|
||||
|
||||
@@ -171,3 +171,50 @@
|
||||
|
||||
/// Value or the next multiple of divisor in a positive direction. Ceilm(-1.5, 0.3) = -1.5 , Ceilm(-1.5, 0.4) = -1.2
|
||||
#define Ceilm(value, divisor) ( -round(-(value) / (divisor)) * (divisor) )
|
||||
|
||||
/**
|
||||
* Get a list of turfs in a line from `starting_atom` to `ending_atom`.
|
||||
*
|
||||
* Uses the ultra-fast [Bresenham Line-Drawing Algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
|
||||
*/
|
||||
/proc/get_line(atom/starting_atom, atom/ending_atom)
|
||||
var/current_x_step = starting_atom.x // start at X and Y, then add 1 or -1 to these to get every turf from start to end
|
||||
var/current_y_step = starting_atom.y
|
||||
var/starting_z = starting_atom.z
|
||||
|
||||
var/list/line = list(get_turf(starting_atom))
|
||||
|
||||
var/x_distance = ending_atom.x - current_x_step
|
||||
var/y_distance = ending_atom.y - current_y_step
|
||||
|
||||
var/abs_x_distance = abs(x_distance)
|
||||
var/abs_y_distance = abs(y_distance)
|
||||
|
||||
var/x_distance_sign = SIGN(x_distance)
|
||||
var/y_distance_sign = SIGN(y_distance)
|
||||
|
||||
var/x = abs_x_distance >> 1
|
||||
var/y = abs_y_distance >> 1
|
||||
|
||||
if (abs_x_distance >= abs_y_distance)
|
||||
for (var/distance_counter in 0 to (abs_x_distance - 1))
|
||||
y += abs_y_distance
|
||||
|
||||
if(y >= abs_x_distance) // Every abs_y_distance steps, step once in y direction
|
||||
y -= abs_x_distance
|
||||
current_y_step += y_distance_sign
|
||||
|
||||
current_x_step += x_distance_sign // Step in x direction
|
||||
line += locate(current_x_step, current_y_step, starting_z)
|
||||
else
|
||||
for (var/distance_counter in 0 to (abs_y_distance - 1))
|
||||
x += abs_x_distance
|
||||
|
||||
if(x >= abs_y_distance)
|
||||
x -= abs_y_distance
|
||||
current_x_step += x_distance_sign
|
||||
|
||||
current_y_step += y_distance_sign
|
||||
line += locate(current_x_step, current_y_step, starting_z)
|
||||
|
||||
return line
|
||||
|
||||
@@ -232,7 +232,7 @@ Proc for attack log creation, because really why not
|
||||
break
|
||||
|
||||
//update our pda and id if we have them on our person
|
||||
var/list/searching = GetAllContents(searchDepth = 3)
|
||||
var/list/searching = GetAllContents()
|
||||
var/search_id = 1
|
||||
var/search_pda = 1
|
||||
|
||||
|
||||
374
code/_helpers/spatial_info.dm
Normal file
374
code/_helpers/spatial_info.dm
Normal file
@@ -0,0 +1,374 @@
|
||||
/turf
|
||||
///what /mob/abstract/oranges_ear instance is already assigned to us as there should only ever be one.
|
||||
///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration
|
||||
var/mob/abstract/oranges_ear/assigned_oranges_ear
|
||||
|
||||
/** # Oranges Ear
|
||||
*
|
||||
* turns out view() spends a significant portion of its processing time generating lists of contents of viewable turfs which includes EVERYTHING on it visible
|
||||
* and the turf itself. there is an optimization to view() which makes it only generate lists of a certain atom type - this system takes advantage of that.
|
||||
* a fuckton of these are generated as part of its SS's init and stored in a list, when requested for a list of movables returned by the spatial grid or by some
|
||||
* superset of the final output that must be narrowed down by view() one of these gets put on every turf that contains the movables that need filtering
|
||||
* and each is given references to the movables they represent. that way you can do for(var/mob/abstract/oranges_ear/ear in view(...)) and check what they reference
|
||||
* as opposed to for(var/atom/movable/target in view(...)) and checking if they have the properties you want which leads to much larger lists generated by view()
|
||||
* and also leads to iterating through more movables to filter them.
|
||||
*
|
||||
* TLDR: iterating through just mobs is much faster than all movables when iterating through view(), this system leverages that to boost speed
|
||||
* enough to offset the cost of allocating the mobs
|
||||
*
|
||||
* named because the idea was first made by oranges and i didnt know what else to call it (note that this system was originally made for get_hearers_in_view())
|
||||
*/
|
||||
/mob/abstract/oranges_ear
|
||||
icon_state = null
|
||||
invisibility = 0
|
||||
mouse_opacity = 0
|
||||
faction = null
|
||||
screens = null
|
||||
|
||||
/// references to everything "on" the turf we are assigned to, that we care about. populated in assign() and cleared in unassign().
|
||||
/// movables iside of other movables count as being "on" if they have get_turf(them) == our turf. intentionally not a lazylist
|
||||
var/list/references = list()
|
||||
|
||||
/mob/abstract/oranges_ear/Initialize(mapload)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
|
||||
/mob/abstract/oranges_ear/Destroy(force)
|
||||
var/old_length = length(SSspatial_grid.pregenerated_oranges_ears)
|
||||
SSspatial_grid.pregenerated_oranges_ears -= src
|
||||
if(length(SSspatial_grid.pregenerated_oranges_ears) < old_length)
|
||||
SSspatial_grid.number_of_oranges_ears -= 1
|
||||
|
||||
var/turf/our_loc = get_turf(src)
|
||||
if(our_loc && our_loc.assigned_oranges_ear == src)
|
||||
our_loc.assigned_oranges_ear = null
|
||||
|
||||
. = ..()
|
||||
|
||||
/mob/abstract/oranges_ear/Move()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
crash_with("SOMEHOW A /mob/abstract/oranges_ear MOVED")
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/oranges_ear/forceMove(atom/destination)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
crash_with("SOMEHOW A /mob/abstract/oranges_ear MOVED")
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/oranges_ear/Bump()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
return FALSE
|
||||
|
||||
///clean this oranges_ear up for future use
|
||||
/mob/abstract/oranges_ear/proc/unassign()
|
||||
var/turf/turf_loc = loc
|
||||
turf_loc.assigned_oranges_ear = null//trollface. our loc should ALWAYS be a turf, no exceptions. if it isnt then this doubles as an error message ;)
|
||||
loc = null
|
||||
references.Cut()
|
||||
|
||||
/**
|
||||
* returns every hearaing movable in view to the turf of source not taking into account lighting
|
||||
* useful when you need to maintain always being able to hear something if a sound is emitted from it and you can see it (and youre in range).
|
||||
* otherwise this is just a more expensive version of get_hearers_in_LOS()
|
||||
*
|
||||
* * view_radius - what radius search circle we are using, worse performance as this increases
|
||||
* * source - object at the center of our search area. everything in get_turf(source) is guaranteed to be part of the search area
|
||||
*/
|
||||
/proc/get_hearers_in_view(view_radius, atom/source)
|
||||
var/turf/center_turf = get_turf(source)
|
||||
if(!center_turf)
|
||||
return
|
||||
|
||||
. = list()
|
||||
|
||||
if(view_radius <= 0)//special case for if only source cares
|
||||
for(var/atom/movable/target as anything in center_turf)
|
||||
var/list/recursive_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE]
|
||||
if(recursive_contents)
|
||||
. += recursive_contents
|
||||
return .
|
||||
|
||||
var/list/hearables_from_grid = SSspatial_grid.orthogonal_range_search(source, RECURSIVE_CONTENTS_HEARING_SENSITIVE, view_radius)
|
||||
|
||||
if(!length(hearables_from_grid))//we know that something is returned by the grid, but we dont know if we need to actually filter down the output
|
||||
return .
|
||||
|
||||
var/list/assigned_oranges_ears = SSspatial_grid.assign_oranges_ears(hearables_from_grid)
|
||||
|
||||
var/old_luminosity = center_turf.luminosity
|
||||
center_turf.luminosity = 6 //man if only we had an inbuilt dview()
|
||||
|
||||
//this is the ENTIRE reason all this shit is worth it due to how view() works and can be optimized
|
||||
//view() constructs lists of viewed atoms by default and specifying a specific type of atom to look for limits the lists it constructs to those of that
|
||||
//primitive type and then when the view operation is completed the output is then typechecked to only iterate through objects in view with the same
|
||||
//typepath. by assigning one /mob/abstract/oranges_ear to every turf with hearable atoms on it and giving them references to each one means that:
|
||||
//1. view() only constructs lists of atoms with the mob primitive type and
|
||||
//2. the mobs returned by view are fast typechecked to only iterate through /mob/abstract/oranges_ear mobs, which guarantees at most one per turf
|
||||
//on a whole this can outperform iterating through all movables in view() by ~2x especially when hearables are a tiny percentage of movables in view
|
||||
for(var/mob/abstract/oranges_ear/ear in view(view_radius, center_turf))
|
||||
. += ear.references
|
||||
|
||||
for(var/mob/abstract/oranges_ear/remaining_ear as anything in assigned_oranges_ears)//we need to clean up our mess
|
||||
remaining_ear.unassign()
|
||||
|
||||
center_turf.luminosity = old_luminosity
|
||||
return .
|
||||
|
||||
/**
|
||||
* Returns a list of movable atoms that are hearing sensitive in view_radius and line of sight to source
|
||||
* the majority of the work is passed off to the spatial grid if view_radius > 0
|
||||
* because view() isnt a raycasting algorithm, this does not hold symmetry to it. something in view might not be hearable with this.
|
||||
* if you want that use get_hearers_in_view() - however thats significantly more expensive
|
||||
*
|
||||
* * view_radius - what radius search circle we are using, worse performance as this increases but not as much as it used to
|
||||
* * source - object at the center of our search area. everything in get_turf(source) is guaranteed to be part of the search area
|
||||
*/
|
||||
/proc/get_hearers_in_LOS(view_radius, atom/source)
|
||||
var/turf/center_turf = get_turf(source)
|
||||
if(!center_turf)
|
||||
return
|
||||
|
||||
if(view_radius <= 0)//special case for if only source cares
|
||||
. = list()
|
||||
for(var/atom/movable/target as anything in center_turf)
|
||||
var/list/hearing_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE]
|
||||
if(hearing_contents)
|
||||
. += hearing_contents
|
||||
return
|
||||
|
||||
. = SSspatial_grid.orthogonal_range_search(source, SPATIAL_GRID_CONTENTS_TYPE_HEARING, view_radius)
|
||||
|
||||
for(var/atom/movable/target as anything in .)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
|
||||
var/distance = get_dist(center_turf, target_turf)
|
||||
|
||||
if(distance > view_radius)
|
||||
. -= target
|
||||
continue
|
||||
|
||||
else if(distance < 2) //we should always be able to see something 0 or 1 tiles away
|
||||
continue
|
||||
|
||||
//this turf search algorithm is the worst scaling part of this proc, scaling worse than view() for small-moderate ranges and > 50 length contents_to_return
|
||||
//luckily its significantly faster than view for large ranges in large spaces and/or relatively few contents_to_return
|
||||
//i can do things that would scale better, but they would be slower for low volume searches which is the vast majority of the current workload
|
||||
//maybe in the future a high volume algorithm would be worth it
|
||||
var/turf/inbetween_turf = center_turf
|
||||
|
||||
//this is the lowest overhead way of doing a loop in dm other than a goto. distance is guaranteed to be >= steps taken to target by this algorithm
|
||||
for(var/step_counter in 1 to distance)
|
||||
inbetween_turf = get_step_towards(inbetween_turf, target_turf)
|
||||
|
||||
if(inbetween_turf == target_turf)//we've gotten to target's turf without returning due to turf opacity, so we must be able to see target
|
||||
break
|
||||
|
||||
if(inbetween_turf.opacity)//this turf or something on it is opaque so we cant see through it
|
||||
. -= target
|
||||
break
|
||||
|
||||
/proc/get_hearers_in_radio_ranges(list/obj/item/device/radio/radios)
|
||||
. = list()
|
||||
// Returns a list of mobs who can hear any of the radios given in @radios
|
||||
for(var/obj/item/device/radio/radio in radios)
|
||||
. |= get_hearers_in_LOS(radio.canhear_range, radio, FALSE)
|
||||
|
||||
///Calculate if two atoms are in sight, returns TRUE or FALSE
|
||||
/proc/inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
|
||||
var/turf/T
|
||||
if(X1==X2)
|
||||
if(Y1==Y2)
|
||||
return TRUE //Light cannot be blocked on same tile
|
||||
else
|
||||
var/s = SIGN(Y2-Y1)
|
||||
Y1+=s
|
||||
while(Y1!=Y2)
|
||||
T=locate(X1,Y1,Z)
|
||||
if(T.opacity)
|
||||
return FALSE
|
||||
Y1+=s
|
||||
else
|
||||
var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
|
||||
var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
|
||||
var/signX = SIGN(X2-X1)
|
||||
var/signY = SIGN(Y2-Y1)
|
||||
if(X1<X2)
|
||||
b+=m
|
||||
while(X1!=X2 || Y1!=Y2)
|
||||
if(round(m*X1+b-Y1))
|
||||
Y1+=signY //Line exits tile vertically
|
||||
else
|
||||
X1+=signX //Line exits tile horizontally
|
||||
T=locate(X1,Y1,Z)
|
||||
if(T.opacity)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/proc/isInSight(atom/first_atom, atom/second_atom)
|
||||
var/turf/first_turf = get_turf(first_atom)
|
||||
var/turf/second_turf = get_turf(second_atom)
|
||||
|
||||
if(!first_turf || !second_turf)
|
||||
return FALSE
|
||||
|
||||
return inLineOfSight(first_turf.x, first_turf.y, second_turf.x, second_turf.y, first_turf.z)
|
||||
|
||||
///Returns all atoms present in a circle around the center
|
||||
/proc/circle_range(center = usr,radius = 3)
|
||||
|
||||
var/turf/center_turf = get_turf(center)
|
||||
var/list/atoms = new/list()
|
||||
var/rsq = radius * (radius + 0.5)
|
||||
|
||||
for(var/atom/checked_atom as anything in range(radius, center_turf))
|
||||
var/dx = checked_atom.x - center_turf.x
|
||||
var/dy = checked_atom.y - center_turf.y
|
||||
if(dx * dx + dy * dy <= rsq)
|
||||
atoms += checked_atom
|
||||
|
||||
return atoms
|
||||
|
||||
///Returns all atoms present in a circle around the center but uses view() instead of range() (Currently not used)
|
||||
/proc/circle_view(center=usr,radius=3)
|
||||
|
||||
var/turf/center_turf = get_turf(center)
|
||||
var/list/atoms = new/list()
|
||||
var/rsq = radius * (radius + 0.5)
|
||||
|
||||
for(var/atom/checked_atom as anything in view(radius, center_turf))
|
||||
var/dx = checked_atom.x - center_turf.x
|
||||
var/dy = checked_atom.y - center_turf.y
|
||||
if(dx * dx + dy * dy <= rsq)
|
||||
atoms += checked_atom
|
||||
|
||||
return atoms
|
||||
|
||||
///Returns the distance between two atoms
|
||||
/proc/get_dist_euclidian(atom/first_location as turf|mob|obj, atom/second_location as turf|mob|obj)
|
||||
var/dx = first_location.x - second_location.x
|
||||
var/dy = first_location.y - second_location.y
|
||||
|
||||
var/dist = sqrt(dx ** 2 + dy ** 2)
|
||||
|
||||
return dist
|
||||
|
||||
///Returns a list of turfs around a center based on RANGE_TURFS()
|
||||
/proc/circle_range_turfs(center = usr, radius = 3)
|
||||
|
||||
var/turf/center_turf = get_turf(center)
|
||||
var/list/turfs = new/list()
|
||||
var/rsq = radius * (radius + 0.5)
|
||||
|
||||
for(var/turf/checked_turf as anything in RANGE_TURFS(radius, center_turf))
|
||||
var/dx = checked_turf.x - center_turf.x
|
||||
var/dy = checked_turf.y - center_turf.y
|
||||
if(dx * dx + dy * dy <= rsq)
|
||||
turfs += checked_turf
|
||||
return turfs
|
||||
|
||||
///Returns a list of turfs around a center based on view()
|
||||
/proc/circle_view_turfs(center=usr,radius=3) //Is there even a diffrence between this proc and circle_range_turfs()?
|
||||
|
||||
var/turf/center_turf = get_turf(center)
|
||||
var/list/turfs = new/list()
|
||||
var/rsq = radius * (radius + 0.5)
|
||||
|
||||
for(var/turf/checked_turf in view(radius, center_turf))
|
||||
var/dx = checked_turf.x - center_turf.x
|
||||
var/dy = checked_turf.y - center_turf.y
|
||||
if(dx * dx + dy * dy <= rsq)
|
||||
turfs += checked_turf
|
||||
return turfs
|
||||
|
||||
/**
|
||||
* Get a bounding box of a list of atoms.
|
||||
*
|
||||
* Arguments:
|
||||
* - atoms - List of atoms. Can accept output of view() and range() procs.
|
||||
*
|
||||
* Returns: list(x1, y1, x2, y2)
|
||||
*/
|
||||
/proc/get_bbox_of_atoms(list/atoms)
|
||||
var/list/list_x = list()
|
||||
var/list/list_y = list()
|
||||
for(var/_a in atoms)
|
||||
var/atom/a = _a
|
||||
list_x += a.x
|
||||
list_y += a.y
|
||||
return list(
|
||||
min(list_x),
|
||||
min(list_y),
|
||||
max(list_x),
|
||||
max(list_y))
|
||||
|
||||
/// Like view but bypasses luminosity check
|
||||
/proc/get_hear(range, atom/source)
|
||||
var/lum = source.luminosity
|
||||
source.luminosity = 6
|
||||
|
||||
. = view(range, source)
|
||||
source.luminosity = lum
|
||||
|
||||
///Returns the open turf next to the center in a specific direction
|
||||
/proc/get_open_turf_in_dir(atom/center, dir)
|
||||
var/turf/T = get_ranged_target_turf(center, dir, 1)
|
||||
if(istype(T) && !T.density)
|
||||
return T
|
||||
|
||||
///Returns a list with all the adjacent open turfs. Clears the list of nulls in the end.
|
||||
/proc/get_adjacent_open_turfs(atom/center)
|
||||
. = list(
|
||||
get_open_turf_in_dir(center, NORTH),
|
||||
get_open_turf_in_dir(center, SOUTH),
|
||||
get_open_turf_in_dir(center, EAST),
|
||||
get_open_turf_in_dir(center, WEST)
|
||||
)
|
||||
listclearnulls(.)
|
||||
|
||||
///Returns a list with all the adjacent areas by getting the adjacent open turfs
|
||||
/proc/get_adjacent_open_areas(atom/center)
|
||||
. = list()
|
||||
var/list/adjacent_turfs = get_adjacent_open_turfs(center)
|
||||
for(var/near_turf in adjacent_turfs)
|
||||
. |= get_area(near_turf)
|
||||
|
||||
/**
|
||||
* Returns a list with the names of the areas around a center at a certain distance
|
||||
* Returns the local area if no distance is indicated
|
||||
* Returns an empty list if the center is null
|
||||
**/
|
||||
/proc/get_areas_in_range(distance = 0, atom/center = usr)
|
||||
if(!distance)
|
||||
var/turf/center_turf = get_turf(center)
|
||||
return center_turf ? list(center_turf.loc) : list()
|
||||
if(!center)
|
||||
return list()
|
||||
|
||||
var/list/turfs = RANGE_TURFS(distance, center)
|
||||
var/list/areas = list()
|
||||
for(var/turf/checked_turf as anything in turfs)
|
||||
areas |= checked_turf.loc
|
||||
return areas
|
||||
|
||||
///Returns a list of all areas that are adjacent to the center atom's area, clear the list of nulls at the end.
|
||||
/proc/get_adjacent_areas(atom/center)
|
||||
. = list(
|
||||
get_area(get_ranged_target_turf(center, NORTH, 1)),
|
||||
get_area(get_ranged_target_turf(center, SOUTH, 1)),
|
||||
get_area(get_ranged_target_turf(center, EAST, 1)),
|
||||
get_area(get_ranged_target_turf(center, WEST, 1))
|
||||
)
|
||||
listclearnulls(.)
|
||||
|
||||
///Checks if the mob provided (must_be_alone) is alone in an area
|
||||
/proc/alone_in_area(area/the_area, mob/must_be_alone, check_type = /mob/living/carbon)
|
||||
var/area/our_area = get_area(the_area)
|
||||
for(var/carbon in living_mob_list)
|
||||
if(!istype(carbon, check_type))
|
||||
continue
|
||||
if(carbon == must_be_alone)
|
||||
continue
|
||||
if(our_area == get_area(carbon))
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -286,6 +286,7 @@
|
||||
SearchVar(ghostteleportlocs)
|
||||
SearchVar(centcom_areas)
|
||||
SearchVar(the_station_areas)
|
||||
SearchVar(station_turfs)
|
||||
SearchVar(implants)
|
||||
SearchVar(turfs)
|
||||
SearchVar(all_species)
|
||||
@@ -618,7 +619,6 @@
|
||||
SearchVar(syndicate_elite_shuttle_timeleft)
|
||||
SearchVar(recentmessages)
|
||||
SearchVar(message_delay)
|
||||
SearchVar(telecomms_list)
|
||||
SearchVar(word_to_uristrune_table)
|
||||
SearchVar(slot_flags_enumeration)
|
||||
SearchVar(BUMP_TELEPORTERS)
|
||||
|
||||
@@ -57,6 +57,8 @@ if(Datum.isprocessing) {\
|
||||
var/list/obj/machinery/hologram/holopad/all_holopads = list()
|
||||
var/list/all_status_displays = list() // Note: This contains both ai_status_display and status_display.
|
||||
var/list/gravity_generators = list()
|
||||
var/list/obj/machinery/telecomms/all_telecomms = list()
|
||||
var/list/obj/machinery/telecomms/all_receivers = list()
|
||||
|
||||
var/list/rcon_smes_units = list()
|
||||
var/list/rcon_smes_units_by_tag = list()
|
||||
@@ -76,8 +78,10 @@ if(Datum.isprocessing) {\
|
||||
all_cameras = SSmachinery.all_cameras
|
||||
all_holopads = SSmachinery.all_holopads
|
||||
recipe_datums = SSmachinery.recipe_datums
|
||||
breaker_boxes = breaker_boxes
|
||||
all_sensors = all_sensors
|
||||
breaker_boxes = SSmachinery.breaker_boxes
|
||||
all_sensors = SSmachinery.all_sensors
|
||||
all_telecomms = SSmachinery.all_telecomms
|
||||
all_receivers = SSmachinery.all_receivers
|
||||
current_step = SSMACHINERY_PIPENETS
|
||||
|
||||
/datum/controller/subsystem/machinery/New()
|
||||
|
||||
@@ -136,6 +136,17 @@ var/datum/controller/subsystem/radio/SSradio
|
||||
|
||||
return 1
|
||||
|
||||
/datum/controller/subsystem/radio/proc/remove_object_all(obj/device)
|
||||
for(var/freq in frequencies)
|
||||
SSradio.remove_object(device, text2num(freq))
|
||||
|
||||
/datum/controller/subsystem/radio/proc/get_devices(freq, filter = RADIO_DEFAULT)
|
||||
var/datum/radio_frequency/frequency = frequencies[num2text(freq)]
|
||||
if(!frequency)
|
||||
return
|
||||
|
||||
return frequency.devices["[filter]"]
|
||||
|
||||
/datum/controller/subsystem/radio/proc/return_frequency(new_frequency)
|
||||
var/f_text = num2text(new_frequency)
|
||||
var/datum/radio_frequency/frequency = frequencies[f_text]
|
||||
@@ -147,6 +158,12 @@ var/datum/controller/subsystem/radio/SSradio
|
||||
|
||||
return frequency
|
||||
|
||||
// Used to test connectivity to the telecomms network.
|
||||
/datum/controller/subsystem/radio/proc/telecomms_ping(obj/O, test_freq = PUB_FREQ)
|
||||
var/datum/signal/subspace/testsig = new(O, test_freq)
|
||||
for (var/obj/machinery/telecomms/R in SSmachinery.all_receivers)
|
||||
if(R.receive_range(testsig) >= 0)
|
||||
return TRUE
|
||||
|
||||
// Some misc procs not technically part of the subsystem, but are related.
|
||||
|
||||
@@ -155,7 +172,6 @@ var/datum/controller/subsystem/radio/SSradio
|
||||
return null
|
||||
|
||||
/proc/frequency_span_class(var/frequency)
|
||||
. = "radio"
|
||||
var/fstr = "[frequency]"
|
||||
// Antags!
|
||||
if (ANTAG_FREQS_ASSOC[fstr])
|
||||
@@ -168,29 +184,50 @@ var/datum/controller/subsystem/radio/SSradio
|
||||
// department radio formatting
|
||||
switch (frequency)
|
||||
if (COMM_FREQ) // command
|
||||
. = "comradio"
|
||||
return "comradio"
|
||||
if (AI_FREQ) // AI Private
|
||||
. = "airadio"
|
||||
return "airadio"
|
||||
if (SEC_FREQ,SEC_I_FREQ)
|
||||
. = "secradio"
|
||||
return "secradio"
|
||||
if (PEN_FREQ)
|
||||
. = "penradio"
|
||||
return "penradio"
|
||||
if (ENG_FREQ)
|
||||
. = "engradio"
|
||||
return "engradio"
|
||||
if (SCI_FREQ)
|
||||
. = "sciradio"
|
||||
return "sciradio"
|
||||
if (MED_FREQ,MED_I_FREQ)
|
||||
. = "medradio"
|
||||
return"medradio"
|
||||
if (SUP_FREQ) // cargo
|
||||
. = "supradio"
|
||||
return "supradio"
|
||||
if (SRV_FREQ) // service
|
||||
. = "srvradio"
|
||||
return "srvradio"
|
||||
if (ENT_FREQ) //entertainment
|
||||
. = "entradio"
|
||||
return "entradio"
|
||||
if (BLSP_FREQ)
|
||||
. = "bluespaceradio"
|
||||
if (SHIP_FREQ)
|
||||
. = "shipradio"
|
||||
else
|
||||
return "bluespaceradio"
|
||||
if (HAIL_FREQ)
|
||||
return "hailradio"
|
||||
|
||||
if(DEPT_FREQS_ASSOC[fstr])
|
||||
. = "deptradio"
|
||||
return "deptradio"
|
||||
|
||||
for(var/channel in AWAY_FREQS_ASSIGNED)
|
||||
if(AWAY_FREQS_ASSIGNED[channel] == frequency)
|
||||
return "shipradio"
|
||||
|
||||
return "radio"
|
||||
|
||||
/proc/assign_away_freq(channel)
|
||||
if (!AWAY_FREQS_UNASSIGNED.len)
|
||||
return FALSE
|
||||
|
||||
if (channel in AWAY_FREQS_ASSIGNED)
|
||||
return AWAY_FREQS_ASSIGNED[channel]
|
||||
|
||||
var/freq = pick_n_take(AWAY_FREQS_UNASSIGNED)
|
||||
AWAY_FREQS_ASSIGNED[channel] = freq
|
||||
radiochannels[channel] = freq
|
||||
reverseradiochannels["[freq]"] = channel
|
||||
ALL_RADIO_CHANNELS[channel] = TRUE
|
||||
|
||||
return freq
|
||||
|
||||
611
code/controllers/subsystems/spatial_gridmap.dm
Normal file
611
code/controllers/subsystems/spatial_gridmap.dm
Normal file
@@ -0,0 +1,611 @@
|
||||
///the subsystem creates this many [/mob/abstract/oranges_ear] mob instances during init. allocations that require more than this create more.
|
||||
#define NUMBER_OF_PREGENERATED_ORANGES_EARS 2500
|
||||
|
||||
// macros meant specifically to add/remove movables from the hearing_contents and client_contents lists of
|
||||
// /datum/spatial_grid_cell, when empty they become references to a single list in SSspatial_grid and when filled they become their own list
|
||||
// this is to save memory without making them lazylists as that slows down iteration through them
|
||||
#define GRID_CELL_ADD(cell_contents_list, movable_or_list) \
|
||||
if(!length(cell_contents_list)) { \
|
||||
cell_contents_list = list(); \
|
||||
cell_contents_list += movable_or_list; \
|
||||
} else { \
|
||||
cell_contents_list += movable_or_list; \
|
||||
};
|
||||
|
||||
#define GRID_CELL_SET(cell_contents_list, movable_or_list) \
|
||||
if(!length(cell_contents_list)) { \
|
||||
cell_contents_list = list(); \
|
||||
cell_contents_list += movable_or_list; \
|
||||
} else { \
|
||||
cell_contents_list |= movable_or_list; \
|
||||
};
|
||||
|
||||
//dont use these outside of SSspatial_grid's scope use the procs it has for this purpose
|
||||
#define GRID_CELL_REMOVE(cell_contents_list, movable_or_list) \
|
||||
cell_contents_list -= movable_or_list; \
|
||||
if(!length(cell_contents_list)) {\
|
||||
cell_contents_list = dummy_list; \
|
||||
};
|
||||
|
||||
/**
|
||||
* # Spatial Grid Cell
|
||||
*
|
||||
* used by [/datum/controller/subsystem/spatial_grid] to cover every z level so that the coordinates of every turf in the world corresponds to one of these in
|
||||
* the subsystems list of grid cells by z level. each one of these contains content lists holding all atoms meeting a certain criteria that is in our borders.
|
||||
* these datums shouldnt have significant behavior, they should just hold data. the lists are filled and emptied by the subsystem.
|
||||
*/
|
||||
/datum/spatial_grid_cell
|
||||
///our x index in the list of cells. this is our index inside of our row list
|
||||
var/cell_x
|
||||
///our y index in the list of cells. this is the index of our row list inside of our z level grid
|
||||
var/cell_y
|
||||
///which z level we belong to, corresponding to the index of our gridmap in SSspatial_grid.grids_by_z_level
|
||||
var/cell_z
|
||||
//every data point in a grid cell is separated by usecase
|
||||
|
||||
//when empty, the contents lists of these grid cell datums are just references to a dummy list from SSspatial_grid
|
||||
//this is meant to allow a great compromise between memory usage and speed.
|
||||
//now orthogonal_range_search() doesnt need to check if the list is null and each empty list is taking 12 bytes instead of 24
|
||||
//the only downside is that it needs to be switched over to a new list when it goes from 0 contents to > 0 contents and switched back on the opposite case
|
||||
|
||||
///every hearing sensitive movable inside this cell
|
||||
var/list/hearing_contents
|
||||
///every client possessed mob inside this cell
|
||||
var/list/client_contents
|
||||
|
||||
/datum/spatial_grid_cell/New(cell_x, cell_y, cell_z)
|
||||
. = ..()
|
||||
src.cell_x = cell_x
|
||||
src.cell_y = cell_y
|
||||
src.cell_z = cell_z
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/dummy_list = SSspatial_grid.dummy_list
|
||||
|
||||
if(length(dummy_list))
|
||||
dummy_list.Cut()
|
||||
crash_with("SSspatial_grid.dummy_list had something inserted into it at some point! this is a problem as it is supposed to stay empty")
|
||||
|
||||
hearing_contents = dummy_list
|
||||
client_contents = dummy_list
|
||||
|
||||
/datum/spatial_grid_cell/Destroy(force, ...)
|
||||
if(force)//the response to someone trying to qdel this is a right proper fuck you
|
||||
crash_with("dont try to destroy spatial grid cells without a good reason. if you need to do it use force")
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
/**
|
||||
* # Spatial Grid
|
||||
*
|
||||
* a gamewide grid of spatial_grid_cell datums, each "covering" [SPATIAL_GRID_CELLSIZE] ^ 2 turfs.
|
||||
* each spatial_grid_cell datum stores information about what is inside its covered area, so that searches through that area dont have to literally search
|
||||
* through all turfs themselves to know what is within it since view() calls are expensive, and so is iterating through stuff you dont want.
|
||||
* this allows you to only go through lists of what you want very cheaply.
|
||||
*
|
||||
* you can also register to objects entering and leaving a spatial cell, this allows you to do things like stay idle until a player enters, so you wont
|
||||
* have to use expensive view() calls or iteratite over the global list of players and call get_dist() on every one. which is fineish for a few things, but is
|
||||
* k * n operations for k objects iterating through n players.
|
||||
*
|
||||
* currently this system is only designed for searching for relatively uncommon things, small subsets of /atom/movable.
|
||||
* dont add stupid shit to the cells please, keep the information that the cells store to things that need to be searched for often
|
||||
*
|
||||
* as of right now this system operates on a subset of the important_recursive_contents list for atom/movable, specifically
|
||||
* [RECURSIVE_CONTENTS_HEARING_SENSITIVE] and [RECURSIVE_CONTENTS_CLIENT_MOBS] because both are those are both 1. important and 2. commonly searched for
|
||||
*/
|
||||
/var/datum/controller/subsystem/spatial_grid/SSspatial_grid
|
||||
|
||||
/datum/controller/subsystem/spatial_grid
|
||||
name = "Spatial Grid"
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
///list of the spatial_grid_cell datums per z level, arranged in the order of y index then x index
|
||||
var/list/grids_by_z_level = list()
|
||||
///everything that spawns before us is added to this list until we initialize
|
||||
var/list/waiting_to_add_by_type = list(RECURSIVE_CONTENTS_HEARING_SENSITIVE = list(), RECURSIVE_CONTENTS_CLIENT_MOBS = list())
|
||||
|
||||
var/cells_on_x_axis = 0
|
||||
var/cells_on_y_axis = 0
|
||||
|
||||
///empty spatial grid cell content lists are just a reference to this instead of a standalone list to save memory without needed to check if its null when iterating
|
||||
var/list/dummy_list = list()
|
||||
|
||||
///list of all of /mob/abstract/oranges_ear instances we have pregenerated for view() iteration speedup
|
||||
var/list/mob/abstract/oranges_ear/pregenerated_oranges_ears = list()
|
||||
///how many pregenerated /mob/abstract/oranges_ear instances currently exist. this should hopefully never exceed its starting value
|
||||
var/number_of_oranges_ears = NUMBER_OF_PREGENERATED_ORANGES_EARS
|
||||
|
||||
/datum/controller/subsystem/spatial_grid/New()
|
||||
NEW_SS_GLOBAL(SSspatial_grid)
|
||||
|
||||
/datum/controller/subsystem/spatial_grid/Initialize(start_timeofday)
|
||||
. = ..()
|
||||
|
||||
cells_on_x_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxx)
|
||||
cells_on_y_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxy)
|
||||
|
||||
for(var/z_level in 1 to world.maxz)
|
||||
propogate_spatial_grid_to_new_z(null, z_level)
|
||||
CHECK_TICK
|
||||
|
||||
//go through the pre init queue for anything waiting to be let in the grid
|
||||
for(var/channel_type in waiting_to_add_by_type)
|
||||
for(var/atom/movable/movable as anything in waiting_to_add_by_type[channel_type])
|
||||
var/turf/movable_turf = get_turf(movable)
|
||||
if(movable_turf)
|
||||
enter_cell(movable, movable_turf)
|
||||
|
||||
UnregisterSignal(movable, COMSIG_PARENT_PREQDELETED)
|
||||
waiting_to_add_by_type[channel_type] -= movable
|
||||
|
||||
pregenerate_more_oranges_ears(NUMBER_OF_PREGENERATED_ORANGES_EARS)
|
||||
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_NEW_Z, .proc/propogate_spatial_grid_to_new_z)
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_EXPANDED_WORLD_BOUNDS, .proc/after_world_bounds_expanded)
|
||||
|
||||
///add a movable to the pre init queue for whichever type is specified so that when the subsystem initializes they get added to the grid
|
||||
/datum/controller/subsystem/spatial_grid/proc/enter_pre_init_queue(atom/movable/waiting_movable, type)
|
||||
RegisterSignal(waiting_movable, COMSIG_PARENT_PREQDELETED, .proc/queued_item_deleted, override = TRUE)
|
||||
//override because something can enter the queue for two different types but that is done through unrelated procs that shouldnt know about eachother
|
||||
waiting_to_add_by_type[type] += waiting_movable
|
||||
|
||||
///removes an initialized and probably deleted movable from our pre init queue before we're initialized
|
||||
/datum/controller/subsystem/spatial_grid/proc/remove_from_pre_init_queue(atom/movable/movable_to_remove, exclusive_type)
|
||||
if(exclusive_type)
|
||||
waiting_to_add_by_type[exclusive_type] -= movable_to_remove
|
||||
|
||||
var/waiting_movable_is_in_other_queues = FALSE//we need to check if this movable is inside the other queues
|
||||
for(var/type in waiting_to_add_by_type)
|
||||
if(movable_to_remove in waiting_to_add_by_type[type])
|
||||
waiting_movable_is_in_other_queues = TRUE
|
||||
|
||||
if(!waiting_movable_is_in_other_queues)
|
||||
UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED)
|
||||
|
||||
return
|
||||
|
||||
UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED)
|
||||
for(var/type in waiting_to_add_by_type)
|
||||
waiting_to_add_by_type[type] -= movable_to_remove
|
||||
|
||||
///if a movable is inside our pre init queue before we're initialized and it gets deleted we need to remove that reference with this proc
|
||||
/datum/controller/subsystem/spatial_grid/proc/queued_item_deleted(atom/movable/movable_being_deleted)
|
||||
SIGNAL_HANDLER
|
||||
remove_from_pre_init_queue(movable_being_deleted, null)
|
||||
|
||||
///creates the spatial grid for a new z level
|
||||
/datum/controller/subsystem/spatial_grid/proc/propogate_spatial_grid_to_new_z(datum/controller/subsystem/processing/dcs/fucking_dcs, var/z_level)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/list/new_cell_grid = list()
|
||||
|
||||
grids_by_z_level += list(new_cell_grid)
|
||||
|
||||
for(var/y in 1 to cells_on_y_axis)
|
||||
new_cell_grid += list(list())
|
||||
for(var/x in 1 to cells_on_x_axis)
|
||||
var/datum/spatial_grid_cell/cell = new(x, y, z_level)
|
||||
new_cell_grid[y] += cell
|
||||
|
||||
///creates number_to_generate new oranges_ear's and adds them to the subsystems list of ears.
|
||||
///i really fucking hope this never gets called after init :clueless:
|
||||
/datum/controller/subsystem/spatial_grid/proc/pregenerate_more_oranges_ears(number_to_generate)
|
||||
for(var/new_ear in 1 to number_to_generate)
|
||||
pregenerated_oranges_ears += new/mob/abstract/oranges_ear(null)
|
||||
|
||||
number_of_oranges_ears = length(pregenerated_oranges_ears)
|
||||
|
||||
///allocate one [/mob/abstract/oranges_ear] mob per turf containing atoms_that_need_ears and give them a reference to every listed atom in their turf.
|
||||
///if an oranges_ear is allocated to a turf that already has an oranges_ear then the second one fails to allocate (and gives the existing one the atom it was assigned to)
|
||||
/datum/controller/subsystem/spatial_grid/proc/assign_oranges_ears(list/atoms_that_need_ears)
|
||||
var/input_length = length(atoms_that_need_ears)
|
||||
|
||||
if(input_length > number_of_oranges_ears)
|
||||
crash_with("somehow, for some reason, more than the preset generated number of oranges ears was requested. thats fucking [number_of_oranges_ears]. this is not good that should literally never happen")
|
||||
pregenerate_more_oranges_ears(input_length - number_of_oranges_ears)//im still gonna DO IT but ill complain about it
|
||||
|
||||
. = list()
|
||||
|
||||
///the next unallocated /mob/abstract/oranges_ear that we try to allocate to assigned_atom's turf
|
||||
var/mob/abstract/oranges_ear/current_ear
|
||||
///the next atom in atoms_that_need_ears an ear assigned to it
|
||||
var/atom/assigned_atom
|
||||
///the turf loc of the current assigned_atom. turfs are used to track oranges_ears already assigned to one location so we dont allocate more than one
|
||||
///because allocating more than one oranges_ear to a given loc wastes view iterations
|
||||
var/turf/turf_loc
|
||||
|
||||
for(var/current_ear_index in 1 to input_length)
|
||||
assigned_atom = atoms_that_need_ears[current_ear_index]
|
||||
|
||||
turf_loc = get_turf(assigned_atom)
|
||||
if(!turf_loc)
|
||||
continue
|
||||
|
||||
current_ear = pregenerated_oranges_ears[current_ear_index]
|
||||
|
||||
if(turf_loc.assigned_oranges_ear)
|
||||
turf_loc.assigned_oranges_ear.references += assigned_atom
|
||||
continue //if theres already an oranges_ear mob at assigned_movable's turf we give assigned_movable to it instead and dont allocate ourselves
|
||||
|
||||
current_ear.references += assigned_atom
|
||||
|
||||
current_ear.loc = turf_loc //normally this is bad, but since this is meant to be as fast as possible we literally just need to exist there for view() to see us
|
||||
turf_loc.assigned_oranges_ear = current_ear
|
||||
|
||||
. += current_ear
|
||||
|
||||
///adds cells to the grid for every z level when world.maxx or world.maxy is expanded after this subsystem is initialized. hopefully this is never needed.
|
||||
///because i never tested this.
|
||||
/datum/controller/subsystem/spatial_grid/proc/after_world_bounds_expanded(datum/controller/subsystem/processing/dcs/fucking_dcs, has_expanded_world_maxx, has_expanded_world_maxy)
|
||||
SIGNAL_HANDLER
|
||||
var/old_x_axis = cells_on_x_axis
|
||||
var/old_y_axis = cells_on_y_axis
|
||||
|
||||
cells_on_x_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxx)
|
||||
cells_on_y_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxy)
|
||||
|
||||
for(var/z_level in 1 to length(grids_by_z_level))
|
||||
var/list/z_level_gridmap = grids_by_z_level[z_level]
|
||||
|
||||
for(var/cell_row_for_expanded_y_axis in 1 to cells_on_y_axis)
|
||||
|
||||
if(cell_row_for_expanded_y_axis > old_y_axis)//we are past the old length of the number of rows, so add to the list
|
||||
z_level_gridmap += list(list())
|
||||
|
||||
//now we know theres a row at this position, so add cells to it that need to be added and update the ones that already exist
|
||||
var/list/cell_row = z_level_gridmap[cell_row_for_expanded_y_axis]
|
||||
|
||||
for(var/grid_cell_for_expanded_x_axis in 1 to cells_on_x_axis)
|
||||
|
||||
if(grid_cell_for_expanded_x_axis > old_x_axis)
|
||||
var/datum/spatial_grid_cell/new_cell_inserted = new(grid_cell_for_expanded_x_axis, cell_row_for_expanded_y_axis, z_level)
|
||||
cell_row += new_cell_inserted
|
||||
continue
|
||||
|
||||
//now we know the cell index we're at contains an already existing cell that needs its x and y values updated
|
||||
var/datum/spatial_grid_cell/old_cell_that_needs_updating = cell_row[grid_cell_for_expanded_x_axis]
|
||||
old_cell_that_needs_updating.cell_x = grid_cell_for_expanded_x_axis
|
||||
old_cell_that_needs_updating.cell_y = cell_row_for_expanded_y_axis
|
||||
|
||||
///the left or bottom side index of a box composed of spatial grid cells with the given actual center x or y coordinate
|
||||
#define BOUNDING_BOX_MIN(center_coord) max(ROUND_UP((center_coord - range) / SPATIAL_GRID_CELLSIZE), 1)
|
||||
///the right or upper side index of a box composed of spatial grid cells with the given center x or y coordinate.
|
||||
///outputted value cant exceed the number of cells on that axis
|
||||
#define BOUNDING_BOX_MAX(center_coord, axis_size) min(ROUND_UP((center_coord + range) / SPATIAL_GRID_CELLSIZE), axis_size)
|
||||
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Range_searching#Orthogonal_range_searching
|
||||
*
|
||||
* searches through the grid cells intersecting a rectangular search space (with sides of length 2 * range) then returns all contents of type inside them.
|
||||
* much faster than iterating through view() to find all of what you want.
|
||||
*
|
||||
* this does NOT return things only in range distance from center! the search space is a square not a circle, if you want only things in a certain distance
|
||||
* then you need to filter that yourself
|
||||
*
|
||||
* * center - the atom that is the center of the searched circle
|
||||
* * type - the type of grid contents you are looking for, see __DEFINES/spatial_grid.dm
|
||||
* * range - the bigger this is, the more spatial grid cells the search space intersects
|
||||
*/
|
||||
/datum/controller/subsystem/spatial_grid/proc/orthogonal_range_search(atom/center, type, range)
|
||||
var/turf/center_turf = get_turf(center)
|
||||
|
||||
var/center_x = center_turf.x//used inside the macros
|
||||
var/center_y = center_turf.y
|
||||
|
||||
. = list()
|
||||
|
||||
//cache for sanic speeds
|
||||
var/cells_on_y_axis = src.cells_on_y_axis
|
||||
var/cells_on_x_axis = src.cells_on_x_axis
|
||||
|
||||
if(grids_by_z_level.len < center_turf.z)
|
||||
return
|
||||
|
||||
//technically THIS list only contains lists, but inside those lists are grid cell datums and we can go without a SINGLE var init if we do this
|
||||
var/list/datum/spatial_grid_cell/grid_level = grids_by_z_level[center_turf.z]
|
||||
switch(type)
|
||||
if(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS)
|
||||
for(var/row in BOUNDING_BOX_MIN(center_y) to BOUNDING_BOX_MAX(center_y, cells_on_y_axis))
|
||||
for(var/x_index in BOUNDING_BOX_MIN(center_x) to BOUNDING_BOX_MAX(center_x, cells_on_x_axis))
|
||||
|
||||
. += grid_level[row][x_index].client_contents
|
||||
|
||||
if(SPATIAL_GRID_CONTENTS_TYPE_HEARING)
|
||||
for(var/row in BOUNDING_BOX_MIN(center_y) to BOUNDING_BOX_MAX(center_y, cells_on_y_axis))
|
||||
for(var/x_index in BOUNDING_BOX_MIN(center_x) to BOUNDING_BOX_MAX(center_x, cells_on_x_axis))
|
||||
|
||||
. += grid_level[row][x_index].hearing_contents
|
||||
|
||||
return .
|
||||
|
||||
///get the grid cell encomapassing targets coordinates
|
||||
/datum/controller/subsystem/spatial_grid/proc/get_cell_of(atom/target)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(!target_turf)
|
||||
return
|
||||
|
||||
return grids_by_z_level[target_turf.z][ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE)][ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE)]
|
||||
|
||||
///get all grid cells intersecting the bounding box around center with sides of length 2 * range
|
||||
/datum/controller/subsystem/spatial_grid/proc/get_cells_in_range(atom/center, range)
|
||||
var/turf/center_turf = get_turf(center)
|
||||
|
||||
var/center_x = center_turf.x
|
||||
var/center_y = center_turf.y
|
||||
|
||||
var/list/intersecting_grid_cells = list()
|
||||
|
||||
//the minimum x and y cell indexes to test
|
||||
var/min_x = max(ROUND_UP((center_x - range) / SPATIAL_GRID_CELLSIZE), 1)
|
||||
var/min_y = max(ROUND_UP((center_y - range) / SPATIAL_GRID_CELLSIZE), 1)//calculating these indices only takes around 2 microseconds
|
||||
|
||||
//the maximum x and y cell indexes to test
|
||||
var/max_x = min(ROUND_UP((center_x + range) / SPATIAL_GRID_CELLSIZE), cells_on_x_axis)
|
||||
var/max_y = min(ROUND_UP((center_y + range) / SPATIAL_GRID_CELLSIZE), cells_on_y_axis)
|
||||
|
||||
var/list/grid_level = grids_by_z_level[center_turf.z]
|
||||
|
||||
for(var/row in min_y to max_y)
|
||||
var/list/grid_row = grid_level[row]
|
||||
|
||||
for(var/x_index in min_x to max_x)
|
||||
intersecting_grid_cells += grid_row[x_index]
|
||||
|
||||
return intersecting_grid_cells
|
||||
|
||||
///find the spatial map cell that target belongs to, then add target's important_recusive_contents to it.
|
||||
///make sure to provide the turf new_target is "in"
|
||||
/datum/controller/subsystem/spatial_grid/proc/enter_cell(atom/movable/new_target, turf/target_turf)
|
||||
if(init_state != SS_INITSTATE_DONE)
|
||||
return
|
||||
|
||||
if(QDELETED(new_target))
|
||||
CRASH("qdeleted or null target trying to enter the spatial grid!")
|
||||
|
||||
if(!target_turf || !new_target?.important_recursive_contents)
|
||||
CRASH("/datum/controller/subsystem/spatial_grid/proc/enter_cell() was given null arguments or a new_target without important_recursive_contents!")
|
||||
|
||||
var/x_index = ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE)
|
||||
var/y_index = ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE)
|
||||
var/z_index = target_turf.z
|
||||
|
||||
var/datum/spatial_grid_cell/intersecting_cell = grids_by_z_level[z_index][y_index][x_index]
|
||||
|
||||
if(new_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])
|
||||
GRID_CELL_SET(intersecting_cell.client_contents, new_target.important_recursive_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS])
|
||||
|
||||
SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_ENTERED(RECURSIVE_CONTENTS_CLIENT_MOBS), new_target)
|
||||
|
||||
if(new_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])
|
||||
GRID_CELL_SET(intersecting_cell.hearing_contents, new_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])
|
||||
|
||||
SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_ENTERED(RECURSIVE_CONTENTS_HEARING_SENSITIVE), new_target)
|
||||
|
||||
/**
|
||||
* find the spatial map cell that target used to belong to, then subtract target's important_recusive_contents from it.
|
||||
* make sure to provide the turf old_target used to be "in"
|
||||
*
|
||||
* * old_target - the thing we want to remove from the spatial grid cell
|
||||
* * target_turf - the turf we use to determine the cell we're removing from
|
||||
* * exclusive_type - either null or a valid contents channel. if you just want to remove a single type from the grid cell then use this
|
||||
*/
|
||||
/datum/controller/subsystem/spatial_grid/proc/exit_cell(atom/movable/old_target, turf/target_turf, exclusive_type)
|
||||
if(init_state != SS_INITSTATE_DONE)
|
||||
return
|
||||
|
||||
if(QDELETED(old_target))
|
||||
CRASH("qdeleted or null target trying to enter the spatial grid")
|
||||
|
||||
if(!target_turf || !old_target?.important_recursive_contents)
|
||||
CRASH("/datum/controller/subsystem/spatial_grid/proc/exit_cell() was given null arguments or a new_target without important_recursive_contents!")
|
||||
|
||||
var/x_index = ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE)
|
||||
var/y_index = ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE)
|
||||
var/z_index = target_turf.z
|
||||
|
||||
var/list/grid = grids_by_z_level[z_index]
|
||||
var/datum/spatial_grid_cell/intersecting_cell = grid[y_index][x_index]
|
||||
|
||||
if(exclusive_type && old_target.important_recursive_contents[exclusive_type])
|
||||
switch(exclusive_type)
|
||||
if(RECURSIVE_CONTENTS_CLIENT_MOBS)
|
||||
GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])
|
||||
|
||||
if(RECURSIVE_CONTENTS_HEARING_SENSITIVE)
|
||||
GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])
|
||||
|
||||
SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target)
|
||||
return
|
||||
|
||||
if(old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])
|
||||
GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])
|
||||
|
||||
SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), old_target)
|
||||
|
||||
if(old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])
|
||||
GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])
|
||||
|
||||
SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(RECURSIVE_CONTENTS_HEARING_SENSITIVE), old_target)
|
||||
|
||||
///find the cell this movable is associated with and removes it from all lists
|
||||
/datum/controller/subsystem/spatial_grid/proc/force_remove_from_cell(atom/movable/to_remove, datum/spatial_grid_cell/input_cell)
|
||||
if(init_state != SS_INITSTATE_DONE)
|
||||
remove_from_pre_init_queue(to_remove)//the spatial grid doesnt exist yet, so just take it out of the queue
|
||||
return
|
||||
|
||||
if(!input_cell)
|
||||
input_cell = get_cell_of(to_remove)
|
||||
if(!input_cell)
|
||||
find_hanging_cell_refs_for_movable(to_remove, TRUE)
|
||||
return
|
||||
|
||||
GRID_CELL_REMOVE(input_cell.client_contents, to_remove)
|
||||
GRID_CELL_REMOVE(input_cell.hearing_contents, to_remove)
|
||||
|
||||
///if shit goes south, this will find hanging references for qdeleting movables inside the spatial grid
|
||||
/datum/controller/subsystem/spatial_grid/proc/find_hanging_cell_refs_for_movable(atom/movable/to_remove, remove_from_cells = TRUE)
|
||||
|
||||
var/list/queues_containing_movable = list()
|
||||
for(var/queue_channel in waiting_to_add_by_type)
|
||||
var/list/queue_list = waiting_to_add_by_type[queue_channel]
|
||||
if(to_remove in queue_list)
|
||||
queues_containing_movable += queue_channel//just add the associative key
|
||||
if(remove_from_cells)
|
||||
queue_list -= to_remove
|
||||
|
||||
if(init_state != SS_INITSTATE_DONE)
|
||||
return queues_containing_movable
|
||||
|
||||
var/list/containing_cells = list()
|
||||
for(var/list/z_level_grid as anything in grids_by_z_level)
|
||||
for(var/list/cell_row as anything in z_level_grid)
|
||||
for(var/datum/spatial_grid_cell/cell as anything in cell_row)
|
||||
if(to_remove in (cell.hearing_contents | cell.client_contents))
|
||||
containing_cells += cell
|
||||
if(remove_from_cells)
|
||||
force_remove_from_cell(to_remove, cell)
|
||||
|
||||
return containing_cells
|
||||
|
||||
///debug proc for checking if a movable is in multiple cells when it shouldnt be (ie always unless multitile entering is implemented)
|
||||
/atom/proc/find_all_cells_containing(remove_from_cells = FALSE)
|
||||
var/datum/spatial_grid_cell/real_cell = SSspatial_grid.get_cell_of(src)
|
||||
var/list/containing_cells = SSspatial_grid.find_hanging_cell_refs_for_movable(src, FALSE, remove_from_cells)
|
||||
|
||||
message_admins("[src] is located in the contents of [length(containing_cells)] spatial grid cells")
|
||||
|
||||
var/cell_coords = "the following cells contain [src]: "
|
||||
for(var/datum/spatial_grid_cell/cell as anything in containing_cells)
|
||||
cell_coords += "([cell.cell_x], [cell.cell_y], [cell.cell_z]), "
|
||||
|
||||
message_admins(cell_coords)
|
||||
message_admins("[src] is supposed to only be contained in the cell at indexes ([real_cell.cell_x], [real_cell.cell_y], [real_cell.cell_z]). but is contained at the cells at [cell_coords]")
|
||||
|
||||
///debug proc for finding how full the cells of src's z level are
|
||||
/atom/proc/find_grid_statistics_for_z_level(insert_clients = 0)
|
||||
var/raw_clients = 0
|
||||
var/raw_hearables = 0
|
||||
|
||||
var/cells_with_clients = 0
|
||||
var/cells_with_hearables = 0
|
||||
|
||||
var/list/client_list = list()
|
||||
var/list/hearable_list = list()
|
||||
|
||||
var/total_cells = (world.maxx / SPATIAL_GRID_CELLSIZE) ** 2
|
||||
|
||||
var/average_clients_per_cell = 0
|
||||
var/average_hearables_per_cell = 0
|
||||
|
||||
var/hearable_min_x = (world.maxx / SPATIAL_GRID_CELLSIZE)
|
||||
var/hearable_max_x = 1
|
||||
|
||||
var/hearable_min_y = (world.maxy / SPATIAL_GRID_CELLSIZE)
|
||||
var/hearable_max_y = 1
|
||||
|
||||
var/client_min_x = (world.maxx / SPATIAL_GRID_CELLSIZE)
|
||||
var/client_max_x = 1
|
||||
|
||||
var/client_min_y = (world.maxy / SPATIAL_GRID_CELLSIZE)
|
||||
var/client_max_y = 1
|
||||
|
||||
var/list/inserted_clients = list()
|
||||
|
||||
if(insert_clients)
|
||||
var/list/turfs
|
||||
if(isStationLevel(z))
|
||||
turfs = station_turfs
|
||||
|
||||
else
|
||||
turfs = block(locate(1,1,z), locate(world.maxx, world.maxy, z))
|
||||
|
||||
for(var/client_to_insert in 0 to insert_clients)
|
||||
var/turf/random_turf = pick(turfs)
|
||||
var/mob/fake_client = new()
|
||||
fake_client.important_recursive_contents = list(SPATIAL_GRID_CONTENTS_TYPE_HEARING = list(fake_client), SPATIAL_GRID_CONTENTS_TYPE_CLIENTS = list(fake_client))
|
||||
fake_client.forceMove(random_turf)
|
||||
inserted_clients += fake_client
|
||||
|
||||
var/list/all_z_level_cells = SSspatial_grid.get_cells_in_range(src, 1000)
|
||||
|
||||
for(var/datum/spatial_grid_cell/cell as anything in all_z_level_cells)
|
||||
var/client_length = length(cell.client_contents)
|
||||
var/hearable_length = length(cell.hearing_contents)
|
||||
|
||||
raw_clients += client_length
|
||||
raw_hearables += hearable_length
|
||||
|
||||
if(client_length)
|
||||
cells_with_clients++
|
||||
|
||||
client_list += cell.client_contents
|
||||
|
||||
if(cell.cell_x < client_min_x)
|
||||
client_min_x = cell.cell_x
|
||||
|
||||
if(cell.cell_x > client_max_x)
|
||||
client_max_x = cell.cell_x
|
||||
|
||||
if(cell.cell_y < client_min_y)
|
||||
client_min_y = cell.cell_y
|
||||
|
||||
if(cell.cell_y > client_max_y)
|
||||
client_max_y = cell.cell_y
|
||||
|
||||
if(hearable_length)
|
||||
cells_with_hearables++
|
||||
|
||||
hearable_list += cell.hearing_contents
|
||||
|
||||
if(cell.cell_x < hearable_min_x)
|
||||
hearable_min_x = cell.cell_x
|
||||
|
||||
if(cell.cell_x > hearable_max_x)
|
||||
hearable_max_x = cell.cell_x
|
||||
|
||||
if(cell.cell_y < hearable_min_y)
|
||||
hearable_min_y = cell.cell_y
|
||||
|
||||
if(cell.cell_y > hearable_max_y)
|
||||
hearable_max_y = cell.cell_y
|
||||
|
||||
var/total_client_distance = 0
|
||||
var/total_hearable_distance = 0
|
||||
|
||||
var/average_client_distance = 0
|
||||
var/average_hearable_distance = 0
|
||||
|
||||
for(var/hearable in hearable_list)//n^2 btw
|
||||
for(var/other_hearable in hearable_list)
|
||||
if(hearable == other_hearable)
|
||||
continue
|
||||
total_hearable_distance += get_dist(hearable, other_hearable)
|
||||
|
||||
for(var/client in client_list)//n^2 btw
|
||||
for(var/other_client in client_list)
|
||||
if(client == other_client)
|
||||
continue
|
||||
total_client_distance += get_dist(client, other_client)
|
||||
|
||||
if(length(hearable_list))
|
||||
average_hearable_distance = total_hearable_distance / length(hearable_list)
|
||||
if(length(client_list))
|
||||
average_client_distance = total_client_distance / length(client_list)
|
||||
|
||||
average_clients_per_cell = raw_clients / total_cells
|
||||
average_hearables_per_cell = raw_hearables / total_cells
|
||||
|
||||
for(var/mob/inserted_client as anything in inserted_clients)
|
||||
qdel(inserted_client)
|
||||
|
||||
message_admins("on z level [z] there are [raw_clients] clients ([insert_clients] of whom are fakes inserted to random station turfs) \
|
||||
and [raw_hearables] hearables. all of whom are inside the bounding box given by \
|
||||
clients: ([client_min_x], [client_min_y]) x ([client_max_x], [client_max_y]) \
|
||||
and hearables: ([hearable_min_x], [hearable_min_y]) x ([hearable_max_x], [hearable_max_y]) \
|
||||
on average there are [average_clients_per_cell] clients per cell and [average_hearables_per_cell] hearables per cell. \
|
||||
[cells_with_clients] cells have clients and [cells_with_hearables] have hearables, \
|
||||
the average client distance is: [average_client_distance] and the average hearable_distance is [average_hearable_distance].")
|
||||
|
||||
#undef GRID_CELL_ADD
|
||||
#undef GRID_CELL_REMOVE
|
||||
#undef GRID_CELL_SET
|
||||
@@ -116,7 +116,7 @@
|
||||
var/pda_msg_amt = 0
|
||||
var/rc_msg_amt = 0
|
||||
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.machinery)
|
||||
for(var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
if(MS.pda_msgs.len > pda_msg_amt)
|
||||
pda_msg_amt = MS.pda_msgs.len
|
||||
if(MS.rc_msgs.len > rc_msg_amt)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
var/tmp/isprocessing = 0
|
||||
var/tmp/gcDestroyed //Time when this object was destroyed.
|
||||
|
||||
/// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
|
||||
var/list/status_traits
|
||||
/// Components attached to this datum
|
||||
/// Lazy associated list in the structure of `type:component/list of components`
|
||||
var/list/datum_components
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
if(T.z != AB.z || get_dist(adestination, AB) > 8 || (AB.stat & (NOPOWER | BROKEN)))
|
||||
continue
|
||||
AB.use_power_oneoff(AB.active_power_usage)
|
||||
bad_turfs += circlerangeturfs(get_turf(AB),8)
|
||||
good_turfs += circlerangeturfs(get_turf(AB),9)
|
||||
bad_turfs += circle_range_turfs(get_turf(AB),8)
|
||||
good_turfs += circle_range_turfs(get_turf(AB),9)
|
||||
if(length(good_turfs) && length(bad_turfs))
|
||||
good_turfs -= bad_turfs
|
||||
if(length(good_turfs))
|
||||
@@ -138,7 +138,7 @@
|
||||
var/turf/curturf = get_turf(teleatom)
|
||||
var/area/destarea = get_area(destination)
|
||||
if(precision)
|
||||
var/list/posturfs = circlerangeturfs(destination,precision)
|
||||
var/list/posturfs = circle_range_turfs(destination,precision)
|
||||
destturf = LAZYPICK(posturfs, null)
|
||||
else
|
||||
destturf = get_turf(destination)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
if (!devices_line)
|
||||
devices_line = new
|
||||
devices[filter] = devices_line
|
||||
devices_line+=device
|
||||
devices_line |= device
|
||||
// var/list/obj/devices_line___ = devices[filter_str]
|
||||
// var/l = devices_line___.len
|
||||
//log_debug("DEBUG: devices_line.len=[devices_line.len]")
|
||||
|
||||
@@ -30,61 +30,3 @@
|
||||
/datum/signal/Destroy()
|
||||
..()
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
/datum/signal/proc/tcombroadcast(var/message, var/freq, var/source, var/job, var/verb, var/language)
|
||||
|
||||
var/datum/signal/newsign = new
|
||||
var/obj/machinery/telecomms/server/S = data["server"]
|
||||
var/obj/item/device/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 = "?"
|
||||
|
||||
if(!language || language == "")
|
||||
language = LANGUAGE_TCB
|
||||
|
||||
var/datum/language/L = all_languages[language]
|
||||
if(!L || !(L.flags & TCOMSSIM))
|
||||
L = all_languages[LANGUAGE_TCB]
|
||||
|
||||
newsign.data["mob"] = null
|
||||
newsign.data["mobtype"] = /mob/living/carbon/human
|
||||
newsign.data["name"] = source
|
||||
newsign.data["realname"] = newsign.data["name"]
|
||||
newsign.data["job"] = job
|
||||
newsign.data["compression"] = 0
|
||||
newsign.data["message"] = message
|
||||
newsign.data["language"] = L
|
||||
newsign.data["type"] = 2 // artificial broadcast
|
||||
if(!isnum(freq))
|
||||
freq = text2num(freq)
|
||||
newsign.frequency = freq
|
||||
|
||||
var/datum/radio_frequency/connection = SSradio.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()
|
||||
newsign.data["verb"] = verb
|
||||
|
||||
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
|
||||
@@ -16,26 +16,26 @@ var/const/WIRE_TRANSMIT = 4
|
||||
var/obj/item/device/radio/R = holder
|
||||
switch(index)
|
||||
if(WIRE_SIGNAL)
|
||||
R.listening = !R.listening && !IsIndexCut(WIRE_RECEIVE)
|
||||
R.broadcasting = R.listening && !IsIndexCut(WIRE_TRANSMIT)
|
||||
R.set_listening(!R.get_listening() && !IsIndexCut(WIRE_RECEIVE))
|
||||
R.set_broadcasting(R.get_listening() && !IsIndexCut(WIRE_TRANSMIT))
|
||||
|
||||
if(WIRE_RECEIVE)
|
||||
R.listening = !R.listening && !IsIndexCut(WIRE_SIGNAL)
|
||||
R.set_listening(!R.get_listening() && !IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
if(WIRE_TRANSMIT)
|
||||
R.broadcasting = !R.broadcasting && !IsIndexCut(WIRE_SIGNAL)
|
||||
R.set_broadcasting(!R.get_broadcasting() && !IsIndexCut(WIRE_SIGNAL))
|
||||
SSnanoui.update_uis(holder)
|
||||
|
||||
/datum/wires/radio/UpdateCut(var/index, var/mended)
|
||||
var/obj/item/device/radio/R = holder
|
||||
switch(index)
|
||||
if(WIRE_SIGNAL)
|
||||
R.listening = mended && !IsIndexCut(WIRE_RECEIVE)
|
||||
R.broadcasting = mended && !IsIndexCut(WIRE_TRANSMIT)
|
||||
R.set_listening(mended && !IsIndexCut(WIRE_RECEIVE))
|
||||
R.set_broadcasting(mended && !IsIndexCut(WIRE_TRANSMIT))
|
||||
|
||||
if(WIRE_RECEIVE)
|
||||
R.listening = mended && !IsIndexCut(WIRE_SIGNAL)
|
||||
R.set_listening(mended && !IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
if(WIRE_TRANSMIT)
|
||||
R.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL)
|
||||
R.set_broadcasting(mended && !IsIndexCut(WIRE_SIGNAL))
|
||||
SSnanoui.update_uis(holder)
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
#define TELECOMMS_RECEPTION_NONE 1
|
||||
#define TELECOMMS_RECEPTION_SENDER 2
|
||||
#define TELECOMMS_RECEPTION_RECEIVER 4
|
||||
#define TELECOMMS_RECEPTION_BOTH 8
|
||||
|
||||
/proc/register_radio(source, old_frequency, new_frequency, radio_filter)
|
||||
if(old_frequency)
|
||||
SSradio.remove_object(source, old_frequency)
|
||||
@@ -34,48 +29,3 @@
|
||||
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 && !within_jamming_range(MS))
|
||||
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)
|
||||
if (check_signal(signal) && !within_jamming_range(sender))
|
||||
return TELECOMMS_RECEPTION_SENDER
|
||||
return TELECOMMS_RECEPTION_NONE
|
||||
|
||||
/proc/get_receiver_reception(var/receiver, var/datum/signal/signal)
|
||||
if(receiver && check_signal(signal) && !within_jamming_range(receiver))
|
||||
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
|
||||
@@ -50,12 +50,36 @@
|
||||
else
|
||||
return null
|
||||
|
||||
// Will return the contents of an atom recursively to a depth of "searchDepth".
|
||||
/atom/proc/GetAllContents(searchDepth = 5, checkClient = 1, checkSight = 1, includeMobs = 1, includeObjects = 1)
|
||||
var/list/L = list()
|
||||
recursive_content_check(src, L, searchDepth, checkClient, checkSight, includeMobs, includeObjects)
|
||||
// Returns src and all recursive contents in a list.
|
||||
/atom/proc/GetAllContents()
|
||||
. = list(src)
|
||||
var/i = 0
|
||||
while(i < length(.))
|
||||
var/atom/A = .[++i]
|
||||
. += A.contents
|
||||
|
||||
return L
|
||||
// identical to GetAllContents but returns a list of atoms of the type passed in the argument
|
||||
/atom/proc/get_all_contents_of_type(type)
|
||||
var/list/processing_list = list(src)
|
||||
. = list()
|
||||
while(length(processing_list))
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list.Cut(1, 2)
|
||||
processing_list += A.contents
|
||||
if(istype(A, type))
|
||||
. += A
|
||||
|
||||
// Returns a list of all locations (except the area) the movable is within
|
||||
/proc/get_nested_locs(atom/movable/atom_on_location, include_turf = FALSE)
|
||||
. = list()
|
||||
var/atom/location = atom_on_location.loc
|
||||
var/turf/our_turf = get_turf(atom_on_location)
|
||||
while (location && location != our_turf)
|
||||
. += location
|
||||
location = location.loc
|
||||
|
||||
if(our_turf && include_turf)
|
||||
. += our_turf
|
||||
|
||||
// Return flags that should be added to the viewer's sight variable.
|
||||
// Otherwise return a negative number to indicate that the view should be cancelled.
|
||||
@@ -554,24 +578,18 @@
|
||||
// "blind_message" (optional) is what blind people will hear e.g. "You hear something!"
|
||||
/atom/proc/visible_message(var/message, var/blind_message, var/range = world.view, var/intent_message = null, var/intent_range = 7)
|
||||
set waitfor = FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/mobs = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(T,range, mobs, objs, ONLY_GHOSTS_IN_VIEW)
|
||||
var/list/hearers = get_hearers_in_view(range, src)
|
||||
|
||||
for(var/o in objs)
|
||||
var/obj/O = o
|
||||
O.show_message(message,1,blind_message,2)
|
||||
|
||||
for(var/m in mobs)
|
||||
var/mob/M = m
|
||||
if(M.see_invisible >= invisibility)
|
||||
M.show_message(message,1,blind_message,2)
|
||||
else if(blind_message)
|
||||
for(var/atom/movable/AM as anything in hearers)
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(M.see_invisible < invisibility)
|
||||
M.show_message(blind_message, 2)
|
||||
continue
|
||||
AM.show_message(message, 1, blind_message, 2)
|
||||
|
||||
if(intent_message)
|
||||
intent_message(intent_message, intent_range, mobs) // pass our mobs list through to intent_message so it doesn't have to call get_mobs_or_objs_in_view again
|
||||
intent_message(intent_message, intent_range, hearers) // pass our hearers list through to intent_message so it doesn't have to call get_hearers again
|
||||
|
||||
// Show a message to all mobs and objects in earshot of this atom.
|
||||
// Use for objects performing audible actions.
|
||||
@@ -580,32 +598,25 @@
|
||||
// "hearing_distance" (optional) is the range, how many tiles away the message can be heard.
|
||||
/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance, var/intent_message = null, var/intent_range = 7)
|
||||
set waitfor = FALSE
|
||||
var/range = world.view
|
||||
if(hearing_distance)
|
||||
range = hearing_distance
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/mobs = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(T,range, mobs, objs, ONLY_GHOSTS_IN_VIEW)
|
||||
|
||||
for(var/m in mobs)
|
||||
var/mob/M = m
|
||||
M.show_message(message,2,deaf_message,1)
|
||||
for(var/o in objs)
|
||||
var/obj/O = o
|
||||
O.show_message(message,2,deaf_message,1)
|
||||
if(!hearing_distance)
|
||||
hearing_distance = world.view
|
||||
|
||||
var/list/hearers = get_hearers_in_view(hearing_distance, src)
|
||||
|
||||
for(var/atom/movable/AM as anything in hearers)
|
||||
AM.show_message(message, 2, deaf_message, 1)
|
||||
|
||||
if(intent_message)
|
||||
intent_message(intent_message, intent_range, mobs) // pass our mobs list through to intent_message so it doesn't have to call get_mobs_or_objs_in_view again
|
||||
intent_message(intent_message, intent_range, hearers) // pass our hearers list through to intent_message so it doesn't have to call get_hearers again
|
||||
|
||||
/atom/proc/intent_message(var/message, var/range = 7, var/list/mobs = list())
|
||||
/atom/proc/intent_message(var/message, var/range = 7, var/list/hearers = list())
|
||||
set waitfor = FALSE
|
||||
if(air_sound(src))
|
||||
var/turf/T = get_turf(src)
|
||||
if(!mobs.len)
|
||||
get_mobs_or_objs_in_view(T, range, mobs, checkghosts = ONLY_GHOSTS_IN_VIEW)
|
||||
if(!hearers.len)
|
||||
hearers = get_hearers_in_view(range, src)
|
||||
for(var/mob/living/carbon/human/H as anything in intent_listener)
|
||||
if(!(H in mobs))
|
||||
if(!(H in hearers))
|
||||
if(src.z == H.z && get_dist(src, H) <= range)
|
||||
H.intent_listen(src, message)
|
||||
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
var/list/contained_mobs
|
||||
appearance_flags = DEFAULT_APPEARANCE_FLAGS | TILE_BOUND
|
||||
|
||||
/**
|
||||
* an associative lazylist of relevant nested contents by "channel", the list is of the form: list(channel = list(important nested contents of that type))
|
||||
* each channel has a specific purpose and is meant to replace potentially expensive nested contents iteration
|
||||
* do NOT add channels to this for little reason as it can add considerable memory usage.
|
||||
*/
|
||||
var/list/important_recursive_contents
|
||||
|
||||
// We don't really need this, and apparently defining it slows down GC.
|
||||
/*/atom/movable/Del()
|
||||
if(!QDELING(src) && loc)
|
||||
@@ -35,7 +42,13 @@
|
||||
..()*/
|
||||
|
||||
/atom/movable/Destroy()
|
||||
if (important_recursive_contents && (important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS] || important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]))
|
||||
SSspatial_grid.force_remove_from_cell(src)
|
||||
|
||||
LAZYCLEARLIST(contained_mobs)
|
||||
LAZYCLEARLIST(important_recursive_contents)
|
||||
. = ..()
|
||||
|
||||
for(var/atom/movable/AM in contents)
|
||||
qdel(AM)
|
||||
loc = null
|
||||
@@ -313,14 +326,15 @@
|
||||
|
||||
// Core movement hooks & procs.
|
||||
/atom/movable/proc/forceMove(atom/destination)
|
||||
if(destination)
|
||||
if(!destination)
|
||||
return FALSE
|
||||
if(loc)
|
||||
loc.Exited(src, destination)
|
||||
var/old_loc = loc
|
||||
loc = destination
|
||||
loc.Entered(src, old_loc)
|
||||
return 1
|
||||
return 0
|
||||
Moved(old_loc, TRUE)
|
||||
return TRUE
|
||||
|
||||
/atom/movable/Move()
|
||||
var/old_loc = loc
|
||||
@@ -345,6 +359,132 @@
|
||||
if (bound_overlay.dir != dir)
|
||||
bound_overlay.set_dir(dir)
|
||||
|
||||
Moved(old_loc, FALSE)
|
||||
|
||||
/atom/movable/proc/Moved(atom/old_loc, forced)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, forced)
|
||||
|
||||
update_grid_location(old_loc, src)
|
||||
|
||||
/atom/movable/proc/update_grid_location(atom/old_loc)
|
||||
if(!HAS_SPATIAL_GRID_CONTENTS(src))
|
||||
return
|
||||
|
||||
var/turf/old_turf = get_turf(old_loc)
|
||||
var/turf/new_turf = get_turf(src)
|
||||
|
||||
if(old_turf && new_turf && (old_turf.z != new_turf.z \
|
||||
|| ROUND_UP(old_turf.x / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.x / SPATIAL_GRID_CELLSIZE) \
|
||||
|| ROUND_UP(old_turf.y / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.y / SPATIAL_GRID_CELLSIZE)))
|
||||
|
||||
SSspatial_grid.exit_cell(src, old_turf)
|
||||
SSspatial_grid.enter_cell(src, new_turf)
|
||||
|
||||
else if(old_turf && !new_turf)
|
||||
SSspatial_grid.exit_cell(src, old_turf)
|
||||
|
||||
else if(new_turf && !old_turf)
|
||||
SSspatial_grid.enter_cell(src, new_turf)
|
||||
|
||||
/atom/movable/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
|
||||
if (LAZYLEN(gone.important_recursive_contents))
|
||||
var/list/nested_locs = get_nested_locs(src) + src
|
||||
for (var/channel in gone.important_recursive_contents)
|
||||
for (var/atom/movable/location as anything in nested_locs)
|
||||
LAZYREMOVEASSOC(location.important_recursive_contents, channel, gone.important_recursive_contents[channel])
|
||||
|
||||
/atom/movable/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
||||
. = ..()
|
||||
|
||||
if (LAZYLEN(arrived.important_recursive_contents))
|
||||
var/list/nested_locs = get_nested_locs(src) + src
|
||||
for (var/channel in arrived.important_recursive_contents)
|
||||
for (var/atom/movable/location as anything in nested_locs)
|
||||
LAZYORASSOCLIST(location.important_recursive_contents, channel, arrived.important_recursive_contents[channel])
|
||||
|
||||
//allows this movable to hear and adds itself to the important_recursive_contents list of itself and every movable loc its in
|
||||
/atom/movable/proc/become_hearing_sensitive(trait_source = TRAIT_GENERIC)
|
||||
if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE))
|
||||
for (var/atom/movable/location as anything in get_nested_locs(src) + src)
|
||||
LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src)
|
||||
|
||||
var/turf/our_turf = get_turf(src)
|
||||
if(our_turf && SSspatial_grid.init_state == SS_INITSTATE_DONE)
|
||||
SSspatial_grid.enter_cell(src, our_turf)
|
||||
|
||||
else if(our_turf && SSspatial_grid.init_state != SS_INITSTATE_DONE)//SSspatial_grid isnt init'd yet, add ourselves to the queue
|
||||
SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE)
|
||||
ADD_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source)
|
||||
|
||||
/**
|
||||
* removes the hearing sensitivity channel from the important_recursive_contents list of this and all nested locs containing us if there are no more sources of the trait left
|
||||
* since RECURSIVE_CONTENTS_HEARING_SENSITIVE is also a spatial grid content type, removes us from the spatial grid if the trait is removed
|
||||
*
|
||||
* * trait_source - trait source define or ALL, if ALL, force removes hearing sensitivity. if a trait source define, removes hearing sensitivity only if the trait is removed
|
||||
*/
|
||||
/atom/movable/proc/lose_hearing_sensitivity(trait_source = TRAIT_GENERIC)
|
||||
if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE))
|
||||
return
|
||||
REMOVE_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source)
|
||||
if(HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE))
|
||||
return
|
||||
|
||||
var/turf/our_turf = get_turf(src)
|
||||
if(our_turf && SSspatial_grid.init_state == SS_INITSTATE_DONE)
|
||||
SSspatial_grid.exit_cell(src, our_turf)
|
||||
else if(our_turf && SSspatial_grid.init_state != SS_INITSTATE_DONE)
|
||||
SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE)
|
||||
|
||||
for(var/atom/movable/location as anything in get_nested_locs(src) + src)
|
||||
LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src)
|
||||
|
||||
///allows this movable to know when it has "entered" another area no matter how many movable atoms its stuffed into, uses important_recursive_contents
|
||||
/atom/movable/proc/become_area_sensitive(trait_source = TRAIT_GENERIC)
|
||||
if(!HAS_TRAIT(src, TRAIT_AREA_SENSITIVE))
|
||||
for (var/atom/movable/location as anything in get_nested_locs(src) + src)
|
||||
LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_AREA_SENSITIVE, src)
|
||||
ADD_TRAIT(src, TRAIT_AREA_SENSITIVE, trait_source)
|
||||
|
||||
///removes the area sensitive channel from the important_recursive_contents list of this and all nested locs containing us if there are no more source of the trait left
|
||||
/atom/movable/proc/lose_area_sensitivity(trait_source = TRAIT_GENERIC)
|
||||
if(!HAS_TRAIT(src, TRAIT_AREA_SENSITIVE))
|
||||
return
|
||||
REMOVE_TRAIT(src, TRAIT_AREA_SENSITIVE, trait_source)
|
||||
if(HAS_TRAIT(src, TRAIT_AREA_SENSITIVE))
|
||||
return
|
||||
|
||||
for (var/atom/movable/location as anything in get_nested_locs(src) + src)
|
||||
LAZYREMOVE(location.important_recursive_contents[RECURSIVE_CONTENTS_AREA_SENSITIVE], src)
|
||||
|
||||
///propogates new_client's mob through our nested contents, similar to other important_recursive_contents procs
|
||||
///main difference is that client contents need to possibly duplicate recursive contents for the clients mob AND its eye
|
||||
/atom/movable/proc/enable_client_mobs_in_contents(client/new_client)
|
||||
var/turf/our_turf = get_turf(src)
|
||||
|
||||
if(our_turf && SSspatial_grid.init_state == SS_INITSTATE_DONE)
|
||||
SSspatial_grid.enter_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS)
|
||||
else if(our_turf && SSspatial_grid.init_state != SS_INITSTATE_DONE)
|
||||
SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS)
|
||||
|
||||
for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src)
|
||||
LAZYORASSOCLIST(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, new_client.mob)
|
||||
|
||||
///Clears the clients channel of this movables important_recursive_contents list and all nested locs
|
||||
/atom/movable/proc/clear_important_client_contents(client/former_client)
|
||||
|
||||
var/turf/our_turf = get_turf(src)
|
||||
|
||||
if(our_turf && SSspatial_grid.init_state == SS_INITSTATE_DONE)
|
||||
SSspatial_grid.exit_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS)
|
||||
else if(our_turf && SSspatial_grid.init_state != SS_INITSTATE_DONE)
|
||||
SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS)
|
||||
|
||||
for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src)
|
||||
LAZYREMOVEASSOC(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, former_client.mob)
|
||||
|
||||
/atom/movable/proc/do_simple_ranged_interaction(var/mob/user)
|
||||
return FALSE
|
||||
|
||||
@@ -431,3 +571,6 @@
|
||||
|
||||
/atom/movable/proc/begin_falling(var/lastloc, var/below)
|
||||
return
|
||||
|
||||
/atom/movable/proc/show_message(msg, type, alt, alt_type) //Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
return
|
||||
|
||||
@@ -63,8 +63,7 @@
|
||||
|
||||
/obj/item/spell/energy_siphon/proc/populate_siphon_list(atom/movable/target)
|
||||
things_to_siphon.Cut()
|
||||
things_to_siphon |= target // The recursive check below does not add the object being checked to its list.
|
||||
things_to_siphon |= recursive_content_check(target, things_to_siphon, recursion_limit = 3, client_check = 0, sight_check = 0, include_mobs = 1, include_objects = 1)
|
||||
things_to_siphon |= target.GetAllContents()
|
||||
for(var/atom/movable/AM in things_to_siphon)
|
||||
if(ishuman(AM)) // We can drain FBPs, so we can skip the test below.
|
||||
var/mob/living/carbon/human/H = AM
|
||||
|
||||
@@ -122,7 +122,7 @@ var/global/list/bluespace_inhibitors
|
||||
if(temp_apc)
|
||||
temp_apc.drain_power(0,TRUE,100000)
|
||||
|
||||
for(var/atom/movable/AM in circlerange(get_turf(src),20))
|
||||
for(var/atom/movable/AM in circle_range(get_turf(src),20))
|
||||
if(AM.anchored)
|
||||
continue
|
||||
var/area/A = random_station_area()
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
if(isXRay())
|
||||
see = range(view_range, pos)
|
||||
else
|
||||
see = hear(view_range, pos)
|
||||
see = get_hear(view_range, pos)
|
||||
return see
|
||||
|
||||
/atom/proc/auto_turn()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
/obj/machinery/button/distress
|
||||
name = "distress beacon launcher"
|
||||
desc = "Press this button to launch a distress beacon."
|
||||
var/listening = FALSE
|
||||
var/recorded_message
|
||||
|
||||
/obj/machinery/button/distress/Initialize(mapload, d, populate_components, is_internal)
|
||||
@@ -16,7 +15,6 @@
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
/obj/machinery/button/distress/hear_talk(mob/M, text, verb, datum/language/speaking)
|
||||
if(listening)
|
||||
recorded_message = text
|
||||
|
||||
/obj/machinery/button/distress/attack_hand(var/mob/user)
|
||||
@@ -35,9 +33,9 @@
|
||||
return
|
||||
var/distress_message = input(user, "Enter a distress message that other vessels will receive.", "Distress Beacon")
|
||||
if(distress_message)
|
||||
listening = TRUE
|
||||
become_hearing_sensitive()
|
||||
user.say(distress_message)
|
||||
listening = FALSE
|
||||
lose_hearing_sensitivity()
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("The beacon refuses to launch without a message!"))
|
||||
active = FALSE
|
||||
|
||||
@@ -23,6 +23,10 @@ Possible to do for anyone motivated enough:
|
||||
* Holopad
|
||||
*/
|
||||
|
||||
#define CAN_HEAR_MASTERS (1<<0)
|
||||
#define CAN_HEAR_ACTIVE_HOLOCALLS (1<<1)
|
||||
#define CAN_HEAR_ALL_FLAGS (CAN_HEAR_MASTERS|CAN_HEAR_ACTIVE_HOLOCALLS)
|
||||
|
||||
#define HOLOPAD_PASSIVE_POWER_USAGE 1
|
||||
#define HOLOGRAM_POWER_USAGE 2
|
||||
|
||||
@@ -58,6 +62,8 @@ Possible to do for anyone motivated enough:
|
||||
|
||||
var/list/linked_pdas = list()
|
||||
|
||||
var/can_hear_flags = NONE
|
||||
|
||||
/obj/machinery/hologram/holopad/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -68,7 +74,6 @@ Possible to do for anyone motivated enough:
|
||||
desc += " Its ID is '[holopad_id]'"
|
||||
|
||||
SSmachinery.all_holopads += src
|
||||
listening_objects += src
|
||||
|
||||
light_color = long_range ? rgb(225, 173, 125) : rgb(125, 180, 225)
|
||||
|
||||
@@ -173,6 +178,33 @@ Possible to do for anyone motivated enough:
|
||||
|
||||
SSvueui.close_user_uis(usr, src)
|
||||
|
||||
//setters
|
||||
/**
|
||||
* setter for can_hear_flags. handles adding or removing the given flag on can_hear_flags and then adding hearing sensitivity or removing it depending on the final state
|
||||
* this is necessary because holopads are a significant fraction of the hearable atoms on station which increases the cost of procs that iterate through hearables
|
||||
* so we need holopads to not be hearable until it is needed
|
||||
*
|
||||
* * flag - one of the can_hear_flags flag defines
|
||||
* * set_flag - boolean, if TRUE sets can_hear_flags to that flag and might add hearing sensitivity if can_hear_flags was NONE before,
|
||||
* if FALSE unsets the flag and possibly removes hearing sensitivity
|
||||
*/
|
||||
/obj/machinery/hologram/holopad/proc/set_can_hear_flags(flag, set_flag = TRUE)
|
||||
if(!(flag & CAN_HEAR_ALL_FLAGS))
|
||||
return FALSE //the given flag doesnt exist
|
||||
|
||||
if(set_flag)
|
||||
if(can_hear_flags == NONE)//we couldnt hear before, so become hearing sensitive
|
||||
become_hearing_sensitive()
|
||||
|
||||
can_hear_flags |= flag
|
||||
return TRUE
|
||||
|
||||
else
|
||||
can_hear_flags &= ~flag
|
||||
if(can_hear_flags == NONE)
|
||||
lose_hearing_sensitivity()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/make_call(var/obj/machinery/hologram/holopad/connected_pad, var/mob/user, forced_call)
|
||||
connected_pad.last_request = world.time
|
||||
@@ -216,6 +248,7 @@ Possible to do for anyone motivated enough:
|
||||
connected_pad.clear_holos(FALSE)
|
||||
connected_pad.connected_pad = null
|
||||
clear_holos(FALSE)
|
||||
set_can_hear_flags(CAN_HEAR_ACTIVE_HOLOCALLS, FALSE)
|
||||
established_connection = FALSE
|
||||
connected_pad.established_connection = FALSE
|
||||
connected_pad.update_icon()
|
||||
@@ -330,9 +363,12 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/create_holo(mob/M)
|
||||
var/obj/effect/overlay/hologram/H = new(get_turf(src))
|
||||
if(isAI(M))
|
||||
set_can_hear_flags(CAN_HEAR_MASTERS)
|
||||
if(!isAI(M) && connected_pad)
|
||||
H.x = src.x - (connected_pad.x - M.x)
|
||||
H.y = src.y - (connected_pad.y - M.y)
|
||||
set_can_hear_flags(CAN_HEAR_ACTIVE_HOLOCALLS)
|
||||
if(!isInSight(H, src))
|
||||
qdel(H)
|
||||
return
|
||||
@@ -359,6 +395,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
for(var/M in active_holograms)
|
||||
if(!clear_ai && isAI(M))
|
||||
continue
|
||||
else if(isAI(M))
|
||||
set_can_hear_flags(CAN_HEAR_MASTERS, FALSE)
|
||||
clear_holo(M)
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/clear_holo(var/mob/M)
|
||||
@@ -481,7 +519,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
if(connected_pad)
|
||||
end_call()
|
||||
clear_holos(TRUE)
|
||||
listening_objects -= src
|
||||
SSmachinery.all_holopads -= src
|
||||
linked_pdas.Cut()
|
||||
return ..()
|
||||
@@ -506,3 +543,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
|
||||
#undef HOLOPAD_PASSIVE_POWER_USAGE
|
||||
#undef HOLOGRAM_POWER_USAGE
|
||||
#undef CAN_HEAR_MASTERS
|
||||
#undef CAN_HEAR_ACTIVE_HOLOCALLS
|
||||
#undef CAN_HEAR_ALL_FLAGS
|
||||
|
||||
@@ -219,6 +219,16 @@ Class Procs:
|
||||
/obj/machinery/proc/inoperable(var/additional_flags = 0)
|
||||
return (stat & (NOPOWER|BROKEN|additional_flags))
|
||||
|
||||
/obj/machinery/proc/toggle_power(power_set = -1, additional_flags = 0)
|
||||
if(power_set >= 0)
|
||||
update_use_power(power_set)
|
||||
else if (use_power || inoperable(additional_flags))
|
||||
update_use_power(POWER_USE_OFF)
|
||||
else
|
||||
update_use_power(initial(use_power))
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/CanUseTopic(var/mob/user)
|
||||
if(stat & BROKEN)
|
||||
return STATUS_CLOSE
|
||||
|
||||
@@ -24,7 +24,7 @@ var/req_console_information = list()
|
||||
var/list/obj/machinery/requests_console/allConsoles = list()
|
||||
|
||||
/obj/machinery/requests_console
|
||||
name = "Requests Console"
|
||||
name = "requests console"
|
||||
desc = "A console intended to send requests to different departments on the station."
|
||||
icon = 'icons/obj/terminals.dmi'
|
||||
icon_state = "req_comp"
|
||||
@@ -118,7 +118,7 @@ var/list/obj/machinery/requests_console/allConsoles = list()
|
||||
announcement.title = "[department] announcement"
|
||||
announcement.newscast = 1
|
||||
|
||||
name = "[department] Requests Console"
|
||||
name = "[department] requests console"
|
||||
allConsoles += src
|
||||
if (departmentType & RC_ASSIST)
|
||||
req_console_assistance |= department
|
||||
@@ -240,12 +240,12 @@ var/list/obj/machinery/requests_console/allConsoles = list()
|
||||
|
||||
if( href_list["department"] && message )
|
||||
var/log_msg = message
|
||||
var/pass = FALSE
|
||||
screen = RCS_SENTFAIL
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
|
||||
if(!MS.active)
|
||||
continue
|
||||
MS.send_rc_message(ckey(href_list["department"]), department, log_msg, msgStamped, msgVerified, priority)
|
||||
var/pass = FALSE
|
||||
var/datum/data_rc_msg/log = new(href_list["department"], department, log_msg, msgStamped, msgVerified, priority)
|
||||
for (var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
if (MS.use_power)
|
||||
MS.rc_msgs += log
|
||||
pass = TRUE
|
||||
if(pass)
|
||||
screen = RCS_SENTPASS
|
||||
@@ -414,8 +414,8 @@ var/list/obj/machinery/requests_console/allConsoles = list()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/requests_console/proc/can_send()
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
|
||||
if(!MS.active)
|
||||
for(var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
if(!MS.use_power)
|
||||
continue
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -1,725 +0,0 @@
|
||||
//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.
|
||||
*/
|
||||
|
||||
var/list/recentmessages = list() // global list of recent messages broadcasted : used to circumvent massive radio spam
|
||||
var/message_delay = 0 // To make sure restarting the recentmessages list is kept in sync
|
||||
|
||||
/obj/machinery/telecomms/broadcaster
|
||||
name = "Subspace Broadcaster"
|
||||
icon_state = "broadcaster"
|
||||
desc = "A dish-shaped machine used to broadcast processed subspace signals."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 25
|
||||
machinetype = 5
|
||||
produces_heat = 0
|
||||
delay = 7
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/broadcaster"
|
||||
|
||||
/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"] |= listening_level
|
||||
|
||||
/** #### - Normal Broadcast - #### **/
|
||||
|
||||
if(signal.data["type"] == 0)
|
||||
|
||||
/* ###### 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"],,
|
||||
signal.data["compression"], signal.data["level"], signal.frequency,
|
||||
signal.data["verb"], signal.data["language"] )
|
||||
|
||||
|
||||
/** #### - Simple Broadcast - #### **/
|
||||
|
||||
if(signal.data["type"] == 1)
|
||||
|
||||
/* ###### Broadcast a message using signal.data ###### */
|
||||
Broadcast_SimpleMessage(signal.data["name"], signal.frequency,
|
||||
signal.data["message"],null, null,
|
||||
signal.data["compression"], listening_level)
|
||||
|
||||
|
||||
/** #### - Artificial Broadcast - #### **/
|
||||
// (Imitates a mob)
|
||||
|
||||
if(signal.data["type"] == 2)
|
||||
|
||||
/* ###### Broadcast a message using signal.data ###### */
|
||||
// Parameter "data" as 4: 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"], 4, signal.data["compression"], signal.data["level"], signal.frequency,
|
||||
signal.data["verb"], signal.data["language"])
|
||||
|
||||
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)
|
||||
message_delay = 0
|
||||
return ..()
|
||||
|
||||
|
||||
/*
|
||||
Basically just an empty shell for receiving and broadcasting radio messages. Not
|
||||
very flexible, but it gets the job done.
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms/allinone
|
||||
name = "Telecommunications Mainframe"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "comm_server"
|
||||
desc = "A compact machine used for portable subspace telecommuniations processing."
|
||||
density = 1
|
||||
anchored = 1
|
||||
use_power = POWER_USE_OFF
|
||||
idle_power_usage = 0
|
||||
machinetype = 6
|
||||
produces_heat = 0
|
||||
var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel
|
||||
var/list/listening_freqs = list()
|
||||
|
||||
|
||||
/obj/machinery/telecomms/allinone/Initialize()
|
||||
. = ..()
|
||||
|
||||
if(!listening_freqs)
|
||||
listening_freqs = ANTAG_FREQS //Covers any updates to ANTAG_FREQS
|
||||
|
||||
desc += " It has an effective broadcast range of [overmap_range] grids on the overmap."
|
||||
|
||||
/obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal)
|
||||
if(!on) // has to be on to receive messages
|
||||
return
|
||||
|
||||
if(!check_receive_sector(signal) && !intercept) //Too far on the overmap to receive. Antag (intercept) don't care about sector checks.
|
||||
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
|
||||
|
||||
if(signal.data["slow"] > 0)
|
||||
sleep(signal.data["slow"]) // simulate the network lag if necessary
|
||||
|
||||
var/list/broadcast_levels = list()
|
||||
if(!intercept)
|
||||
broadcast_levels = list(z)
|
||||
broadcast_levels += GetConnectedZlevels(z) //For multi-z away sites
|
||||
else
|
||||
broadcast_levels = list(0) //This lets antag headsets work everywhere
|
||||
|
||||
/* ###### Broadcast a message using signal.data ###### */
|
||||
|
||||
var/datum/radio_frequency/connection = signal.data["connection"]
|
||||
|
||||
if(connection.frequency in listening_freqs) //Regular broadcasts
|
||||
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"],, signal.data["compression"], broadcast_levels, connection.frequency,
|
||||
signal.data["verb"], signal.data["language"])
|
||||
else
|
||||
if(intercept) //Antag Broadcast intercepting station messages
|
||||
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"], 3, signal.data["compression"], list(0), connection.frequency,
|
||||
signal.data["verb"], signal.data["language"])
|
||||
|
||||
|
||||
/obj/machinery/telecomms/allinone/ship
|
||||
listening_freqs = list(SHIP_FREQ)
|
||||
|
||||
//This goes on the station map so away ships can maintain radio contact.
|
||||
//Regular telecomms machines cannot listen to broadcasts coming from non-station z-levels. If we did this, comms would be receiving a substantial amount of duplicated messages.
|
||||
/obj/machinery/telecomms/allinone/ship/station_relay
|
||||
name = "External Signal Receiver"
|
||||
icon = 'icons/obj/machines/telecomms.dmi'
|
||||
icon_state = "ntnet"
|
||||
desc = "This device allows nearby third-party ships to maintain radio contact with their crew that are aboard the %STATIONNAME."
|
||||
desc_info = "This device does not need to be linked to other telecommunications equipment; it will receive and broadcast on its own. It only needs to be powered."
|
||||
use_power = POWER_USE_IDLE
|
||||
idle_power_usage = 25
|
||||
|
||||
/obj/machinery/telecomms/allinone/ship/station_relay/Initialize()
|
||||
. = ..()
|
||||
desc = replacetext(desc, "%STATIONNAME", current_map.station_name)
|
||||
|
||||
/**
|
||||
|
||||
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/vmessage, var/obj/item/device/radio/radio,
|
||||
var/message, var/name, var/job, var/realname, var/vname,
|
||||
var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/datum/language/speaking = null)
|
||||
|
||||
|
||||
/* ###### Prepare the radio connection ###### */
|
||||
|
||||
var/display_freq = freq
|
||||
|
||||
var/list/obj/item/device/radio/radios = list()
|
||||
|
||||
// --- Broadcast only to intercom devices ---
|
||||
|
||||
if(data == 1)
|
||||
|
||||
for (var/obj/item/device/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 == 2)
|
||||
|
||||
for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"])
|
||||
|
||||
if(istype(R, /obj/item/device/radio/headset))
|
||||
continue
|
||||
|
||||
if(R.receive_range(display_freq, level) > -1)
|
||||
radios += R
|
||||
|
||||
// --- Broadcast to antag radios! ---
|
||||
|
||||
else if(data == 3)
|
||||
for(var/antag_freq in ANTAG_FREQS)
|
||||
var/datum/radio_frequency/antag_connection = SSradio.return_frequency(antag_freq)
|
||||
for (var/obj/item/device/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/device/radio/R in connection.devices["[RADIO_CHAT]"])
|
||||
if(R.receive_range(display_freq, level) > -1)
|
||||
radios += R
|
||||
|
||||
// --- Radio sounds. ---
|
||||
|
||||
for(var/obj/item/device/radio/R in radios)
|
||||
if((R.last_radio_sound + 1 SECOND) < world.time && R != radio)
|
||||
playsound(R.loc, 'sound/effects/radio_chatter.ogg', 2.5, 0, -6, required_asfx_toggles = ASFX_RADIO)
|
||||
R.last_radio_sound = world.time
|
||||
|
||||
|
||||
// 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.client)
|
||||
if(R.client.prefs)
|
||||
if(!(R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios.
|
||||
continue
|
||||
else
|
||||
log_debug("Client prefs found to be null in /proc/Broadcast_Message() for mob [R] and client [R.ckey], this should be investigated.")
|
||||
|
||||
if(istype(R, /mob/abstract/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 == 3 && istype(R, /mob/abstract/observer) && R.client && R.client.prefs && (R.client.prefs.toggles & CHAT_GHOSTRADIO))
|
||||
continue
|
||||
|
||||
// --- Check for compression ---
|
||||
if(compression > 0)
|
||||
heard_gibberish += R
|
||||
continue
|
||||
|
||||
// --- Can understand the speech ---
|
||||
|
||||
if (!M || R.say_understands(M, speaking))
|
||||
|
||||
// - 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)
|
||||
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 == 3) // intercepted radio message
|
||||
part_b_extra = " <i>(Intercepted)</i>"
|
||||
var/part_a = "<span class='[frequency_span_class(display_freq)]'>%ACCENT%<b>\[[freq_text]\][part_b_extra]</b> <span class='name'>" // goes in the actual output
|
||||
|
||||
// --- Some more pre-message formatting ---
|
||||
var/part_b = "</span> <span class='message'></span>" // Tweaked for security headsets -- TLE
|
||||
var/part_c = "</span>"
|
||||
|
||||
|
||||
// --- Filter the message; place it in quotes apply a verb ---
|
||||
|
||||
var/quotedmsg = null
|
||||
if(M)
|
||||
quotedmsg = M.say_quote(message)
|
||||
else
|
||||
quotedmsg = "says, \"[message]\""
|
||||
|
||||
// --- This following recording is intended for research and feedback in the use of department radio channels ---
|
||||
|
||||
var/part_blackbox_b = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
|
||||
var/blackbox_msg = "[part_a][name][part_blackbox_b][quotedmsg][part_c]"
|
||||
//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(SSfeedback))
|
||||
switch(display_freq)
|
||||
if(PUB_FREQ)
|
||||
SSfeedback.msg_common += blackbox_msg
|
||||
if(SCI_FREQ)
|
||||
SSfeedback.msg_science += blackbox_msg
|
||||
if(COMM_FREQ)
|
||||
SSfeedback.msg_command += blackbox_msg
|
||||
if(MED_FREQ)
|
||||
SSfeedback.msg_medical += blackbox_msg
|
||||
if(ENG_FREQ)
|
||||
SSfeedback.msg_engineering += blackbox_msg
|
||||
if(SEC_FREQ)
|
||||
SSfeedback.msg_security += blackbox_msg
|
||||
if(DTH_FREQ)
|
||||
SSfeedback.msg_deathsquad += blackbox_msg
|
||||
if(SYND_FREQ)
|
||||
SSfeedback.msg_syndicate += blackbox_msg
|
||||
if(RAID_FREQ)
|
||||
SSfeedback.msg_raider += blackbox_msg
|
||||
if(NINJ_FREQ)
|
||||
SSfeedback.msg_ninja += blackbox_msg
|
||||
if(BLSP_FREQ)
|
||||
SSfeedback.msg_bluespace += blackbox_msg
|
||||
if(BURG_FREQ)
|
||||
SSfeedback.msg_burglar += blackbox_msg
|
||||
if(SUP_FREQ)
|
||||
SSfeedback.msg_cargo += blackbox_msg
|
||||
if(SRV_FREQ)
|
||||
SSfeedback.msg_service += blackbox_msg
|
||||
if(SHIP_FREQ)
|
||||
SSfeedback.msg_ship += blackbox_msg
|
||||
else
|
||||
SSfeedback.messages += blackbox_msg
|
||||
|
||||
//End of research and feedback code.
|
||||
|
||||
/* ###### Send the message ###### */
|
||||
|
||||
|
||||
/* --- Process all the mobs that heard a masked voice (understood) --- */
|
||||
//Note that accent tags are handled in hear_radio.
|
||||
if (length(heard_masked))
|
||||
for (var/mob/R in heard_masked)
|
||||
R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, 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, verbage, speaking, part_a, part_b, part_c, 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,verbage, speaking, part_a, part_b, part_c, 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, verbage, speaking, part_a, part_b, part_c, 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, verbage, speaking, part_a, part_b, part_c, M, 1)
|
||||
|
||||
return 1
|
||||
|
||||
/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level)
|
||||
|
||||
/* ###### Prepare the radio connection ###### */
|
||||
|
||||
if(!M)
|
||||
var/mob/living/carbon/human/H = new
|
||||
M = H
|
||||
|
||||
var/datum/radio_frequency/connection = SSradio.return_frequency(frequency)
|
||||
|
||||
var/display_freq = connection.frequency
|
||||
|
||||
var/list/receive = list()
|
||||
|
||||
|
||||
// --- Broadcast only to intercom devices ---
|
||||
|
||||
if(data == 1)
|
||||
for (var/obj/item/device/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 == 2)
|
||||
for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"])
|
||||
|
||||
if(istype(R, /obj/item/device/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 == 3)
|
||||
for(var/freq in ANTAG_FREQS)
|
||||
var/datum/radio_frequency/antag_connection = SSradio.return_frequency(freq)
|
||||
for (var/obj/item/device/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/device/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.client)
|
||||
if(R.client.prefs)
|
||||
if(!(R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios.
|
||||
continue
|
||||
else
|
||||
log_debug("Client prefs found to be null in /proc/Broadcast_SimpleMessage() for mob [R] and client [R.ckey], this should be investigated.")
|
||||
|
||||
|
||||
// --- 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 == 3) // intercepted radio message
|
||||
part_b_extra = " <i>(Intercepted)</i>"
|
||||
|
||||
var/part_b = "</span><b> \[[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)
|
||||
SSfeedback.msg_common += blackbox_msg
|
||||
if(SCI_FREQ)
|
||||
SSfeedback.msg_science += blackbox_msg
|
||||
if(COMM_FREQ)
|
||||
SSfeedback.msg_command += blackbox_msg
|
||||
if(MED_FREQ)
|
||||
SSfeedback.msg_medical += blackbox_msg
|
||||
if(ENG_FREQ)
|
||||
SSfeedback.msg_engineering += blackbox_msg
|
||||
if(SEC_FREQ)
|
||||
SSfeedback.msg_security += blackbox_msg
|
||||
if(DTH_FREQ)
|
||||
SSfeedback.msg_deathsquad += blackbox_msg
|
||||
if(SYND_FREQ)
|
||||
SSfeedback.msg_syndicate += blackbox_msg
|
||||
if(RAID_FREQ)
|
||||
SSfeedback.msg_raider += blackbox_msg
|
||||
if(NINJ_FREQ)
|
||||
SSfeedback.msg_ninja += blackbox_msg
|
||||
if(BLSP_FREQ)
|
||||
SSfeedback.msg_bluespace += blackbox_msg
|
||||
if(BURG_FREQ)
|
||||
SSfeedback.msg_burglar += blackbox_msg
|
||||
if(SUP_FREQ)
|
||||
SSfeedback.msg_cargo += blackbox_msg
|
||||
if(SRV_FREQ)
|
||||
SSfeedback.msg_service += blackbox_msg
|
||||
if(SHIP_FREQ)
|
||||
SSfeedback.msg_ship += blackbox_msg
|
||||
else
|
||||
SSfeedback.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/turf/position = get_turf(src)
|
||||
return (position.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/turf/pos = get_turf(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" = 4, // 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))
|
||||
|
||||
//world.log << "Level: [signal.data["level"]] - Done: [signal.data["done"]]"
|
||||
|
||||
return signal
|
||||
|
||||
/proc/telecomms_process_active(var/level = 5)
|
||||
|
||||
// First, we want to generate a new radio signal
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = TRANSMISSION_SUBSPACE
|
||||
|
||||
// --- 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" = 4, // determines what type of radio input it is: test broadcast
|
||||
"reject" = 0,
|
||||
"done" = 0,
|
||||
"level" = level // 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)
|
||||
|
||||
return signal
|
||||
259
code/game/machinery/telecomms/broadcasting.dm
Normal file
259
code/game/machinery/telecomms/broadcasting.dm
Normal file
@@ -0,0 +1,259 @@
|
||||
// Subtype of /datum/signal with additional processing information.
|
||||
/datum/signal/subspace
|
||||
transmission_method = TRANSMISSION_SUBSPACE
|
||||
var/server_type = /obj/machinery/telecomms/server
|
||||
var/datum/signal/subspace/original
|
||||
var/origin_level
|
||||
var/list/levels
|
||||
var/obj/effect/overmap/visitable/sector
|
||||
|
||||
/datum/signal/subspace/New(obj/source, frequency, message = "", data = null)
|
||||
src.source = source
|
||||
src.frequency = frequency
|
||||
var/turf/T = get_turf(source)
|
||||
if(isturf(T))
|
||||
origin_level = T.z
|
||||
|
||||
if(data)
|
||||
src.data = data
|
||||
else
|
||||
src.data = list(
|
||||
"compression" = rand(35, 65),
|
||||
"message" = message
|
||||
)
|
||||
|
||||
if(current_map.use_overmap && istype(source))
|
||||
sector = map_sectors["[source.z]"]
|
||||
|
||||
/datum/signal/subspace/proc/copy()
|
||||
var/datum/signal/subspace/copy = new
|
||||
copy.original = src
|
||||
copy.source = source
|
||||
copy.levels = levels
|
||||
copy.origin_level = origin_level
|
||||
copy.frequency = frequency
|
||||
copy.server_type = server_type
|
||||
copy.transmission_method = transmission_method
|
||||
copy.sector = sector
|
||||
copy.data = data.Copy()
|
||||
return copy
|
||||
|
||||
/datum/signal/subspace/proc/mark_done()
|
||||
var/datum/signal/subspace/current = src
|
||||
while (current)
|
||||
current.data["done"] = TRUE
|
||||
current = current.original
|
||||
|
||||
/datum/signal/subspace/proc/send_to_receivers()
|
||||
if(!source.loc)
|
||||
// It's an announcer message, just send it to the horizon's receiver
|
||||
for(var/obj/machinery/telecomms/receiver/R in SSmachinery.all_receivers)
|
||||
if(R.z in current_map.station_levels)
|
||||
R.receive_signal(src)
|
||||
return
|
||||
|
||||
var/closest_range = 999999
|
||||
var/list/candidates = list()
|
||||
var/obj/machinery/telecomms/selected_receiver
|
||||
var/t_range = -1
|
||||
|
||||
for(var/obj/machinery/telecomms/R in SSmachinery.all_receivers)
|
||||
t_range = R.receive_range(src)
|
||||
if(t_range <= -1)
|
||||
continue
|
||||
|
||||
if(t_range < closest_range)
|
||||
candidates = list(R)
|
||||
closest_range = t_range
|
||||
else if(t_range == closest_range)
|
||||
candidates |= R
|
||||
|
||||
if(!length(candidates))
|
||||
return
|
||||
|
||||
if(length(candidates) > 1)
|
||||
// Unlikely we ever have two receivers at the same distance listening to one frequency, but still
|
||||
closest_range = 128 // get_dist returns 127 max
|
||||
t_range = -1
|
||||
for(var/obj/machinery/telecomms/R in candidates)
|
||||
t_range = get_dist(R, source)
|
||||
if(t_range < closest_range)
|
||||
selected_receiver = R
|
||||
closest_range = t_range
|
||||
continue
|
||||
|
||||
else
|
||||
selected_receiver = candidates[1]
|
||||
|
||||
selected_receiver.receive_signal(src)
|
||||
|
||||
/datum/signal/subspace/proc/broadcast()
|
||||
set waitfor = FALSE
|
||||
|
||||
// Vocal transmissions (i.e. using saycode).
|
||||
// Despite "subspace" in the name, these transmissions can also be RADIO
|
||||
// (intercoms and SBRs) or SUPERSPACE (CentCom).
|
||||
/datum/signal/subspace/vocal
|
||||
var/datum/weakref/speaker
|
||||
var/datum/language/language
|
||||
|
||||
/datum/signal/subspace/vocal/New(obj/source, frequency, datum/weakref/speaker, datum/language/language, message, say_verb)
|
||||
src.source = source
|
||||
src.frequency = frequency
|
||||
src.language = language
|
||||
src.speaker = speaker
|
||||
|
||||
var/turf/T = get_turf(source)
|
||||
if(isturf(T))
|
||||
origin_level = T.z
|
||||
levels = list(T.z)
|
||||
if(current_map.use_overmap)
|
||||
sector = map_sectors["[T.z]"]
|
||||
else // if the source is in nullspace, it's probably an autosay
|
||||
levels = current_map.station_levels
|
||||
origin_level = levels[1]
|
||||
sector = map_sectors["[levels[1]]"]
|
||||
|
||||
var/mob/M = speaker.resolve()
|
||||
|
||||
data = list(
|
||||
"name" = M.name,
|
||||
"job" = M.job,
|
||||
"message" = message,
|
||||
"compression" = rand(35, 65),
|
||||
"language" = language,
|
||||
"say_verb" = say_verb
|
||||
)
|
||||
|
||||
/datum/signal/subspace/vocal/copy()
|
||||
var/datum/signal/subspace/vocal/copy = new(source, frequency, speaker, language)
|
||||
copy.original = src
|
||||
copy.data = data.Copy()
|
||||
copy.levels = levels
|
||||
return copy
|
||||
|
||||
// THE MEAT for making radios hear vocal transmissions.
|
||||
/datum/signal/subspace/vocal/broadcast()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/message = copytext(data["message"], 1, MAX_MESSAGE_LEN)
|
||||
if(!message || message == "")
|
||||
return
|
||||
|
||||
var/list/signal_reaches_every_z_level = levels
|
||||
|
||||
if(0 in levels)
|
||||
signal_reaches_every_z_level = RADIO_NO_Z_LEVEL_RESTRICTION
|
||||
|
||||
var/list/radios = list()
|
||||
switch (transmission_method)
|
||||
if (TRANSMISSION_SUBSPACE)
|
||||
// Reach any radios on the levels
|
||||
var/list/all_radios_of_our_frequency = SSradio.get_devices(frequency, RADIO_CHAT)
|
||||
radios = all_radios_of_our_frequency.Copy()
|
||||
|
||||
for (var/obj/item/device/radio/subspace_radio in radios)
|
||||
if(!subspace_radio.can_receive(frequency, signal_reaches_every_z_level))
|
||||
radios -= subspace_radio
|
||||
|
||||
// Cool antag radios can hear all Horizon comms
|
||||
for (var/antag_freq in list(SYND_FREQ, RAID_FREQ, NINJ_FREQ))
|
||||
for (var/obj/item/device/radio/syndicate_radios in SSradio.get_devices(antag_freq, RADIO_CHAT))
|
||||
if(syndicate_radios.can_receive(antag_freq, signal_reaches_every_z_level))
|
||||
radios |= syndicate_radios
|
||||
|
||||
if (TRANSMISSION_RADIO)
|
||||
// Only radios not in subspace mode
|
||||
for (var/obj/item/device/radio/non_subspace_radio in SSradio.get_devices(frequency, RADIO_CHAT))
|
||||
if(!non_subspace_radio.subspace_transmission && non_subspace_radio.can_receive(frequency, levels))
|
||||
radios += non_subspace_radio
|
||||
|
||||
if (TRANSMISSION_SUPERSPACE)
|
||||
// Independent radios
|
||||
for (var/obj/item/device/radio/indie_radio in SSradio.get_devices(frequency, RADIO_CHAT))
|
||||
if(indie_radio.independent && indie_radio.can_receive(frequency, levels))
|
||||
radios += indie_radio
|
||||
|
||||
var/list/receive = get_hearers_in_radio_ranges(radios)
|
||||
|
||||
// Cut out admins which have radio chatter disabled
|
||||
for (var/mob/R in receive)
|
||||
if(R.client && R.client.holder && !(R.client.prefs.toggles & CHAT_RADIO))
|
||||
receive -= R
|
||||
|
||||
// Add observers who have ghost radio enabled
|
||||
for (var/mob/abstract/observer/M in player_list)
|
||||
if(M.client && (M.client.prefs?.toggles & CHAT_GHOSTRADIO))
|
||||
receive |= M
|
||||
|
||||
/* --- Some miscellaneous variables to format the string output --- */
|
||||
var/freq_text = get_frequency_name(frequency)
|
||||
|
||||
var/part_b_extra = ""
|
||||
if(data == 3) // intercepted radio message
|
||||
part_b_extra = " <i>(Intercepted)</i>"
|
||||
var/part_a = "<span class='[frequency_span_class(frequency)]'>%ACCENT%<b>\[[freq_text]\][part_b_extra]</b> <span class='name'>" // goes in the actual output
|
||||
|
||||
// --- Some more pre-message formatting ---
|
||||
var/part_b = "</span> <span class='message'></span>" // Tweaked for security headsets -- TLE
|
||||
var/part_c = "</span>"
|
||||
|
||||
|
||||
// --- Filter the message; place it in quotes apply a verb ---
|
||||
var/mob/M = speaker.resolve()
|
||||
|
||||
var/quotedmsg = null
|
||||
if(M)
|
||||
quotedmsg = M.say_quote(message)
|
||||
else
|
||||
quotedmsg = "says, \"[message]\""
|
||||
|
||||
var/compression = data["compression"]
|
||||
|
||||
for (var/mob/hearer in receive)
|
||||
if(!hearer)
|
||||
crash_with("null found in the hearers list returned by the spatial grid")
|
||||
continue
|
||||
|
||||
hearer.hear_radio(message, data["say_verb"], language, part_a, part_b, part_c, M, !!compression)
|
||||
|
||||
// --- This following recording is intended for research and feedback in the use of department radio channels ---
|
||||
|
||||
var/part_blackbox_b = "</span><b> \[[freq_text]\]</b> <span class='message'>" // Tweaked for security headsets -- TLE
|
||||
var/blackbox_msg = "[part_a][data["name"]][part_blackbox_b][quotedmsg][part_c]"
|
||||
|
||||
if(istype(SSfeedback))
|
||||
switch(frequency)
|
||||
if(PUB_FREQ)
|
||||
SSfeedback.msg_common += blackbox_msg
|
||||
if(SCI_FREQ)
|
||||
SSfeedback.msg_science += blackbox_msg
|
||||
if(COMM_FREQ)
|
||||
SSfeedback.msg_command += blackbox_msg
|
||||
if(MED_FREQ)
|
||||
SSfeedback.msg_medical += blackbox_msg
|
||||
if(ENG_FREQ)
|
||||
SSfeedback.msg_engineering += blackbox_msg
|
||||
if(SEC_FREQ)
|
||||
SSfeedback.msg_security += blackbox_msg
|
||||
if(DTH_FREQ)
|
||||
SSfeedback.msg_deathsquad += blackbox_msg
|
||||
if(SYND_FREQ)
|
||||
SSfeedback.msg_syndicate += blackbox_msg
|
||||
if(RAID_FREQ)
|
||||
SSfeedback.msg_raider += blackbox_msg
|
||||
if(NINJ_FREQ)
|
||||
SSfeedback.msg_ninja += blackbox_msg
|
||||
if(BLSP_FREQ)
|
||||
SSfeedback.msg_bluespace += blackbox_msg
|
||||
if(BURG_FREQ)
|
||||
SSfeedback.msg_burglar += blackbox_msg
|
||||
if(SUP_FREQ)
|
||||
SSfeedback.msg_cargo += blackbox_msg
|
||||
if(SRV_FREQ)
|
||||
SSfeedback.msg_service += blackbox_msg
|
||||
else
|
||||
if(frequency in AWAY_FREQS_ASSIGNED)
|
||||
SSfeedback.msg_ship += blackbox_msg
|
||||
else
|
||||
SSfeedback.messages += blackbox_msg
|
||||
@@ -61,7 +61,7 @@
|
||||
else
|
||||
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
|
||||
|
||||
dat += log_entries_to_text(SelectedServer)
|
||||
dat += log_entries_to_text(user, SelectedServer)
|
||||
|
||||
user << browse(dat, "window=comm_monitor;size=575x400")
|
||||
onclose(user, "server_control")
|
||||
@@ -183,7 +183,7 @@
|
||||
src.updateUsrDialog()
|
||||
return 1
|
||||
|
||||
/obj/machinery/computer/telecomms/server/proc/log_entries_to_text(var/obj/machinery/telecomms/server/SelectedServer, start = 1, end = SelectedServer.log_entries.len)
|
||||
/obj/machinery/computer/telecomms/server/proc/log_entries_to_text(mob/user, var/obj/machinery/telecomms/server/SelectedServer, start = 1, end = SelectedServer.log_entries.len)
|
||||
if(!end)
|
||||
end = SelectedServer.log_entries.len
|
||||
start = between(1, start, SelectedServer.log_entries.len)
|
||||
@@ -201,28 +201,25 @@
|
||||
|
||||
. += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=\ref[src];delete=[i]'>\[X\]</a></font><br>"
|
||||
|
||||
// -- Determine race of orator --
|
||||
|
||||
var/race = C.parameters["race"] // The actual race of the mob
|
||||
var/language = C.parameters["language"] // The language spoken, or null/""
|
||||
|
||||
// -- If the orator is a human, or universal translate is active, OR mob has universal speech on --
|
||||
|
||||
if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"])
|
||||
. += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
|
||||
. += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
|
||||
. += "<u><font color = #18743E>Class</font></u>: [race]<br>"
|
||||
. += "<u><font color = #18743E>Contents</font></u>: \"[C.parameters["message"]]\"<br>"
|
||||
if(language)
|
||||
. += "<u><font color = #18743E>Language</font></u>: [language]<br/>"
|
||||
|
||||
// -- Orator is not human and universal translate not active --
|
||||
var/datum/language/language = C.parameters["language"]
|
||||
var/message_out = ""
|
||||
var/message_in = C.parameters["message"]
|
||||
|
||||
if(universal_translate || (language in user.languages))
|
||||
message_out = "\"[message_in]\""
|
||||
else if(!(language in user.languages))
|
||||
// Language unknown by viewer, scramble
|
||||
message_out = "\"[language.scramble(message_in, user.languages)]\""
|
||||
else
|
||||
. += "<u><font color = #18743E>Data type</font></u>: Audio File<br>"
|
||||
. += "<u><font color = #18743E>Source</font></u>: <i>Unidentifiable</i><br>"
|
||||
. += "<u><font color = #18743E>Class</font></u>: [race]<br>"
|
||||
. += "<u><font color = #18743E>Contents</font></u>: <i>Unintelligble</i><br>"
|
||||
// Entirely unintelligible
|
||||
message_out = "(Unintelligible)"
|
||||
|
||||
. += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
|
||||
. += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] [C.parameters["job"] ? "(Job: [C.parameters["job"]])" : ""]<br>"
|
||||
. += "<u><font color = #18743E>Class</font></u>: [C.parameters["race"]]<br>"
|
||||
. += "<u><font color = #18743E>Contents</font></u>: [message_out]<br>"
|
||||
if(language)
|
||||
. += "<u><font color = #18743E>Language</font></u>: [language.name]<br/>"
|
||||
|
||||
. += "</li><br>"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Allows you to monitor messages that passes the server.
|
||||
/*
|
||||
Monitoring computer for the messaging server.
|
||||
Lets you read request console messages.
|
||||
*/
|
||||
|
||||
// The monitor itself.
|
||||
/obj/machinery/computer/message_monitor
|
||||
name = "messaging monitor console"
|
||||
desc = "Used to access and maintain data on messaging servers. Allows you to view requests console messages."
|
||||
@@ -9,7 +13,7 @@
|
||||
var/hack_icon = "error"
|
||||
circuit = /obj/item/circuitboard/message_monitor
|
||||
//Server linked to.
|
||||
var/obj/machinery/message_server/linkedServer = null
|
||||
var/obj/machinery/telecomms/message_server/linkedServer = null
|
||||
//Sparks effect - For emag
|
||||
var/datum/effect_system/sparks/spark_system
|
||||
//Messages - Saves me time if I want to change something.
|
||||
@@ -54,18 +58,18 @@
|
||||
// Will create sparks and print out the console's password. You will then have to wait a while for the console to be back online.
|
||||
// It'll take more time if there's more characters in the password..
|
||||
if(!emag && operable())
|
||||
if(!isnull(src.linkedServer))
|
||||
emag = 1
|
||||
if(!isnull(linkedServer))
|
||||
emag = TRUE
|
||||
screen = 2
|
||||
src.spark_system.queue()
|
||||
spark_system.queue()
|
||||
var/obj/item/paper/monitorkey/MK = new/obj/item/paper/monitorkey
|
||||
MK.forceMove(src.loc)
|
||||
MK.forceMove(loc)
|
||||
// Will help make emagging the console not so easy to get away with.
|
||||
MK.info += "<br><br><span class='warning'>£%@%(*$%&(£&?*(%&£/{}</span>"
|
||||
addtimer(CALLBACK(src, .proc/UnmagConsole), 100 * length(linkedServer.decryptkey))
|
||||
message = rebootmsg
|
||||
update_icon()
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, "<span class='notice'>A no server error appears on the screen.</span>")
|
||||
|
||||
@@ -77,11 +81,15 @@
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/message_monitor/Initialize()
|
||||
. = ..()
|
||||
//Is the server isn't linked to a server, and there's a server available, default it to the first one in the list.
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/computer/message_monitor/LateInitialize()
|
||||
//If the server isn't linked to a server, and there's a server available, default it to the first one in the list.
|
||||
if(!linkedServer)
|
||||
if(message_servers && message_servers.len > 0)
|
||||
linkedServer = message_servers[1]
|
||||
for(var/obj/machinery/telecomms/message_server/S in SSmachinery.all_telecomms)
|
||||
linkedServer = S
|
||||
break
|
||||
|
||||
/obj/machinery/computer/message_monitor/attack_hand(var/mob/living/user as mob)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -97,10 +105,10 @@
|
||||
|
||||
if(auth)
|
||||
dat += "<h4><dd><A href='?src=\ref[src];auth=1'>	<font color='green'>\[Authenticated\]</font></a>	/"
|
||||
dat += " Server Power: <A href='?src=\ref[src];active=1'>[src.linkedServer && src.linkedServer.active ? "<font color='green'>\[On\]</font>":"<span class='warning'>\[Off\]</span>"]</a></h4>"
|
||||
dat += " Server Power: <A href='?src=\ref[src];active=1'>[src.linkedServer && src.linkedServer.use_power ? "<font color='green'>\[On\]</font>":"<span class='warning'>\[Off\]</span>"]</a></h4>"
|
||||
else
|
||||
dat += "<h4><dd><A href='?src=\ref[src];auth=1'>	<span class='warning'>\[Unauthenticated\]</span></a>	/"
|
||||
dat += " Server Power: <u>[src.linkedServer && src.linkedServer.active ? "<font color='green'>\[On\]</font>":"<span class='warning'>\[Off\]</span>"]</u></h4>"
|
||||
dat += " Server Power: <u>[src.linkedServer && src.linkedServer.use_power ? "<font color='green'>\[On\]</font>":"<span class='warning'>\[Off\]</span>"]</u></h4>"
|
||||
|
||||
if(hacking || emag)
|
||||
screen = 2
|
||||
@@ -272,13 +280,17 @@
|
||||
|
||||
//Turn the server on/off.
|
||||
if (href_list["active"])
|
||||
if(auth) linkedServer.active = !linkedServer.active
|
||||
if(auth) linkedServer.use_power = !linkedServer.use_power
|
||||
//Find a server
|
||||
if (href_list["find"])
|
||||
if(message_servers && message_servers.len > 1)
|
||||
src.linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers
|
||||
var/list/message_servers = list()
|
||||
for(var/obj/machinery/telecomms/message_server/M in SSmachinery.all_telecomms)
|
||||
message_servers += M
|
||||
|
||||
if(message_servers.len > 1)
|
||||
linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers
|
||||
message = "<span class='alert'>NOTICE: Server selected.</span>"
|
||||
else if(message_servers && message_servers.len > 0)
|
||||
else if(message_servers.len > 0)
|
||||
linkedServer = message_servers[1]
|
||||
message = "<span class='notice'>NOTICE: Only Single Server Detected - Server selected.</span>"
|
||||
else
|
||||
@@ -403,15 +415,14 @@
|
||||
/obj/item/paper/monitorkey
|
||||
//..()
|
||||
name = "Monitor Decryption Key"
|
||||
var/obj/machinery/message_server/server = null
|
||||
var/obj/machinery/telecomms/message_server/server = null
|
||||
|
||||
/obj/item/paper/monitorkey/Initialize()
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/item/paper/monitorkey/LateInitialize()
|
||||
if(message_servers)
|
||||
for(var/obj/machinery/message_server/server in message_servers)
|
||||
for(var/obj/machinery/telecomms/message_server/server in SSmachinery.all_telecomms)
|
||||
if(!isnull(server))
|
||||
if(!isnull(server.decryptkey))
|
||||
info = "<center><h2>Daily Key Reset</h2></center><br>The new message monitor key is '[server.decryptkey]'.<br>Please keep this a secret and away from unauthorized personnel.<br>If necessary, change the password to a more secure one."
|
||||
161
code/game/machinery/telecomms/computers/telemonitor.dm
Normal file
161
code/game/machinery/telecomms/computers/telemonitor.dm
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Telecomms monitor tracks the overall trafficing of a telecommunications network
|
||||
and displays a hierarchy of linked machines.
|
||||
*/
|
||||
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor
|
||||
name = "telecommunications monitor"
|
||||
desc = "A monitor that tracks the overall traffic of a telecommunications network, and displays a hierarchy of linked machines."
|
||||
icon_screen = "comm_monitor"
|
||||
icon_keyboard = "green_key"
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
var/screen = 0 // the screen number:
|
||||
var/list/machinelist = list() // the machines located by the computer
|
||||
var/obj/machinery/telecomms/SelectedMachine
|
||||
|
||||
var/network = "NULL" // the network to probe
|
||||
|
||||
var/temp = "" // temporary feedback messages
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = "<TITLE>Telecommunications Monitor</TITLE><center><b>Telecommunications Monitor</b></center>"
|
||||
|
||||
switch(screen)
|
||||
|
||||
|
||||
// --- Main Menu ---
|
||||
|
||||
if(0)
|
||||
dat += "<br>[temp]<br><br>"
|
||||
dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
|
||||
if(machinelist.len)
|
||||
dat += "<br>Detected Network Entities:<ul>"
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
dat += "<li><a href='?src=\ref[src];viewmachine=[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 += "<a href='?src=\ref[src];operation=probe'>\[Probe Network\]</a>"
|
||||
|
||||
|
||||
// --- Viewing Machine ---
|
||||
|
||||
if(1)
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a></center>"
|
||||
dat += "<br>Current Network: [network]<br>"
|
||||
dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])<br>"
|
||||
dat += "Linked Entities: <ol>"
|
||||
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
|
||||
if(!T.hide)
|
||||
dat += "<li><a href='?src=\ref[src];viewmachine=[T.id]'>\ref[T.id] [T.name]</a> ([T.id])</li>"
|
||||
dat += "</ol>"
|
||||
|
||||
|
||||
|
||||
user << browse(dat, "window=comm_monitor;size=575x400")
|
||||
onclose(user, "server_control")
|
||||
|
||||
temp = ""
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["viewmachine"])
|
||||
screen = 1
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
if(T.id == href_list["viewmachine"])
|
||||
SelectedMachine = T
|
||||
break
|
||||
|
||||
if(href_list["operation"])
|
||||
switch(href_list["operation"])
|
||||
|
||||
if("release")
|
||||
machinelist = list()
|
||||
screen = 0
|
||||
|
||||
if("mainmenu")
|
||||
screen = 0
|
||||
|
||||
if("probe")
|
||||
if(machinelist.len > 0)
|
||||
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/T in range(25, src))
|
||||
if(T.network == network)
|
||||
machinelist.Add(T)
|
||||
|
||||
if(!machinelist.len)
|
||||
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -</font>"
|
||||
else
|
||||
temp = "<font color = #336699>- [machinelist.len] ENTITIES LOCATED & BUFFERED -</font>"
|
||||
|
||||
screen = 0
|
||||
|
||||
|
||||
if(href_list["network"])
|
||||
|
||||
var/newnet = sanitize(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
|
||||
machinelist = list()
|
||||
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font>"
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/attackby(var/obj/item/D as obj, var/mob/user as mob)
|
||||
if(D.isscrewdriver())
|
||||
if(D.use_tool(src, user, 20, volume = 50))
|
||||
if (src.stat & BROKEN)
|
||||
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
new /obj/item/material/shard( src.loc )
|
||||
var/obj/item/circuitboard/comm_monitor/M = new /obj/item/circuitboard/comm_monitor( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 3
|
||||
A.icon_state = "3"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
var/obj/item/circuitboard/comm_monitor/M = new /obj/item/circuitboard/comm_monitor( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 4
|
||||
A.icon_state = "4"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src.loc, '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
|
||||
238
code/game/machinery/telecomms/computers/traffic_control.dm
Normal file
238
code/game/machinery/telecomms/computers/traffic_control.dm
Normal file
@@ -0,0 +1,238 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
|
||||
|
||||
/obj/machinery/computer/telecomms/traffic
|
||||
name = "telecommunications traffic control"
|
||||
icon_screen = "computer_generic"
|
||||
icon_keyboard = "green_key"
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
req_access = list(access_tcomsat)
|
||||
|
||||
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
|
||||
|
||||
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 = sanitize(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/attackby(var/obj/item/D as obj, var/mob/user as mob)
|
||||
if(D.isscrewdriver())
|
||||
if(D.use_tool(src, user, 20, volume = 50))
|
||||
if (src.stat & BROKEN)
|
||||
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
new /obj/item/material/shard( src.loc )
|
||||
var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 3
|
||||
A.icon_state = "3"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 4
|
||||
A.icon_state = "4"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/traffic/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src.loc, '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
|
||||
@@ -1,12 +1,3 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
|
||||
|
||||
|
||||
/*
|
||||
|
||||
All telecommunications interactions:
|
||||
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms
|
||||
var/temp = "" // output message
|
||||
var/construct_op = 0
|
||||
@@ -26,9 +17,9 @@
|
||||
if (integrity < 100) //Damaged, let's repair!
|
||||
if (T.use(1))
|
||||
integrity = between(0, initial(integrity) / 2, initial(integrity))
|
||||
to_chat(usr, "You apply the Nanopaste to [src], repairing some of the damage.")
|
||||
to_chat(user, "You apply the Nanopaste to [src], repairing some of the damage.")
|
||||
else
|
||||
to_chat(usr, "This machine is already in perfect condition.")
|
||||
to_chat(user, "This machine is already in perfect condition.")
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -118,8 +109,8 @@
|
||||
M = user.get_multitool()
|
||||
var/dat
|
||||
dat += "<br>[temp]<br><br>"
|
||||
dat += "Power Status: <a href='?src=\ref[src];input=toggle'>[src.toggled ? "On" : "Off"]</a>"
|
||||
if(on && toggled)
|
||||
dat += "Power Status: <a href='?src=\ref[src];input=toggle'>[src.use_power ? "On" : "Off"]</a>"
|
||||
if(operable() && use_power)
|
||||
if(id != "" && id)
|
||||
dat += "<br>Identification String: <a href='?src=\ref[src];input=id'>[id]</a>"
|
||||
else
|
||||
@@ -195,23 +186,6 @@
|
||||
temp = "<font color = #666633>-% Processing mode changed. %-</font>"
|
||||
src.process_mode = !src.process_mode
|
||||
*/
|
||||
|
||||
// RELAY
|
||||
|
||||
/obj/machinery/telecomms/relay/Options_Menu()
|
||||
var/dat = ""
|
||||
dat += "<br>Broadcasting: <A href='?src=\ref[src];broadcast=1'>[broadcasting ? "YES" : "NO"]</a>"
|
||||
dat += "<br>Receiving: <A href='?src=\ref[src];receive=1'>[receiving ? "YES" : "NO"]</a>"
|
||||
return dat
|
||||
|
||||
/obj/machinery/telecomms/relay/Options_Topic(href, href_list)
|
||||
|
||||
if(href_list["receive"])
|
||||
receiving = !receiving
|
||||
temp = "<font color = #666633>-% Receiving mode changed. %-</font>"
|
||||
if(href_list["broadcast"])
|
||||
broadcasting = !broadcasting
|
||||
temp = "<font color = #666633>-% Broadcasting mode changed. %-</font>"
|
||||
// BUS
|
||||
|
||||
/obj/machinery/telecomms/bus/Options_Menu()
|
||||
@@ -250,9 +224,8 @@
|
||||
|
||||
if("toggle")
|
||||
|
||||
src.toggled = !src.toggled
|
||||
temp = "<font color = #666633>-% [src] has been [src.toggled ? "activated" : "deactivated"].</font>"
|
||||
update_power()
|
||||
toggle_power()
|
||||
temp = "<font color = #666633>-% [src] has been [src.use_power ? "activated" : "deactivated"].</font>"
|
||||
|
||||
/*
|
||||
if("hide")
|
||||
@@ -275,7 +248,7 @@
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/T in links)
|
||||
T.links.Remove(src)
|
||||
remove_link(T)
|
||||
|
||||
network = newnet
|
||||
links = list()
|
||||
@@ -303,27 +276,17 @@
|
||||
|
||||
if(text2num(href_list["unlink"]) <= length(links))
|
||||
var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])]
|
||||
if(T)
|
||||
temp = "<font color = #666633>-% Removed \ref[T] [T.name] from linked entities. %-</font>"
|
||||
|
||||
// Remove link entries from both T and src.
|
||||
|
||||
if(src in T.links)
|
||||
T.links.Remove(src)
|
||||
links.Remove(T)
|
||||
remove_link(T)
|
||||
|
||||
if(href_list["link"])
|
||||
|
||||
if(P)
|
||||
var/obj/machinery/telecomms/device = P.get_buffer()
|
||||
if(istype(device) && device != src)
|
||||
if(!(src in device.links))
|
||||
device.links.Add(src)
|
||||
|
||||
if(!(device in src.links))
|
||||
src.links.Add(device)
|
||||
|
||||
if(device)
|
||||
add_new_link(device)
|
||||
temp = "<font color = #666633>-% Successfully linked with \ref[device] [device.name] %-</font>"
|
||||
|
||||
else
|
||||
temp = "<font color = #666633>-% Unable to acquire buffer %-</font>"
|
||||
|
||||
@@ -346,6 +309,37 @@
|
||||
|
||||
updateDialog()
|
||||
|
||||
// Adds new_connection to src's links list AND vice versa. also updates links_by_telecomms_type
|
||||
/obj/machinery/telecomms/proc/add_new_link(obj/machinery/telecomms/new_connection)
|
||||
if (!istype(new_connection) || new_connection == src)
|
||||
return FALSE
|
||||
|
||||
if ((new_connection in links) && (src in new_connection.links))
|
||||
return FALSE
|
||||
|
||||
links |= new_connection
|
||||
new_connection.links |= src
|
||||
|
||||
LAZYADDASSOCLIST(links_by_telecomms_type, new_connection.telecomms_type, new_connection)
|
||||
LAZYADDASSOCLIST(new_connection.links_by_telecomms_type, telecomms_type, src)
|
||||
|
||||
return TRUE
|
||||
|
||||
// Removes old_connection from src's links list AND vice versa. also updates links_by_telecomms_type
|
||||
/obj/machinery/telecomms/proc/remove_link(obj/machinery/telecomms/old_connection)
|
||||
if (!istype(old_connection) || old_connection == src)
|
||||
return FALSE
|
||||
|
||||
if (old_connection in links)
|
||||
links -= old_connection
|
||||
LAZYREMOVEASSOC(links_by_telecomms_type, old_connection.telecomms_type, old_connection)
|
||||
|
||||
if (src in old_connection.links)
|
||||
old_connection.links -= src
|
||||
LAZYREMOVEASSOC(old_connection.links_by_telecomms_type, telecomms_type, src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/telecomms/proc/canAccess(var/mob/user)
|
||||
if(issilicon(user) || in_range(user, src))
|
||||
return 1
|
||||
|
||||
83
code/game/machinery/telecomms/machines/allinone.dm
Normal file
83
code/game/machinery/telecomms/machines/allinone.dm
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Basically just an empty shell for receiving and broadcasting radio messages. Not
|
||||
very flexible, but it gets the job done.
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms/allinone
|
||||
name = "telecommunications mainframe"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "comm_server"
|
||||
desc = "A compact machine used for portable subspace telecommuniations processing."
|
||||
idle_power_usage = 0
|
||||
active_power_usage = 0
|
||||
produces_heat = FALSE
|
||||
overmap_range = 2 // AIOs aren't true relays
|
||||
|
||||
var/away_aio = FALSE
|
||||
var/list/recent_broadcasts
|
||||
|
||||
/obj/machinery/telecomms/allinone/Initialize()
|
||||
. = ..()
|
||||
if(!freq_listening.len)
|
||||
freq_listening = ANTAG_FREQS
|
||||
LAZYINITLIST(recent_broadcasts)
|
||||
SSmachinery.all_receivers += src
|
||||
|
||||
desc += " It has an effective reception range of [overmap_range] grids on the overmap."
|
||||
|
||||
/obj/machinery/telecomms/allinone/Destroy()
|
||||
SSmachinery.all_receivers -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/allinone/receive_signal(datum/signal/subspace/signal)
|
||||
signal.levels = broadcast_levels(signal)
|
||||
|
||||
// Decompress the signal, mark it received
|
||||
signal.data["compression"] = 0
|
||||
signal.mark_done()
|
||||
|
||||
var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]"
|
||||
if(signal_message in recent_broadcasts)
|
||||
return
|
||||
|
||||
LAZYADD(recent_broadcasts, signal_message)
|
||||
|
||||
if(signal.data["slow"] > 0)
|
||||
addtimer(CALLBACK(signal, /datum/signal/subspace/proc/broadcast), signal.data["slow"]) // network lag
|
||||
else
|
||||
signal.broadcast()
|
||||
|
||||
spawn(10)
|
||||
recent_broadcasts -= signal_message
|
||||
|
||||
/obj/machinery/telecomms/allinone/ship/LateInitialize()
|
||||
. = ..()
|
||||
if(!linked)
|
||||
return
|
||||
|
||||
if(away_aio)
|
||||
if(linked.comms_name)
|
||||
name = "[lowertext(linked.comms_name)] [initial(name)]"
|
||||
freq_listening = list(
|
||||
HAIL_FREQ,
|
||||
assign_away_freq(linked.name)
|
||||
)
|
||||
|
||||
//This goes on the station map so away ships can maintain radio contact.
|
||||
/obj/machinery/telecomms/allinone/ship/station_relay
|
||||
name = "external signal receiver"
|
||||
icon = 'icons/obj/machines/telecomms.dmi'
|
||||
icon_state = "ntnet"
|
||||
desc = "This device allows nearby third-party ships to maintain radio contact with their crew that are aboard the %STATIONNAME."
|
||||
desc_info = "This device does not need to be linked to other telecommunications equipment; it will receive and broadcast on its own. It only needs to be powered."
|
||||
idle_power_usage = 25
|
||||
active_power_usage = 200
|
||||
freq_listening = list(HAIL_FREQ)
|
||||
away_aio = FALSE
|
||||
|
||||
/obj/machinery/telecomms/allinone/ship/station_relay/LateInitialize()
|
||||
. = ..()
|
||||
desc = replacetext(desc, "%STATIONNAME", current_map.station_name)
|
||||
freq_listening |= AWAY_FREQS_ASSIGNED
|
||||
freq_listening |= AWAY_FREQS_UNASSIGNED
|
||||
freq_listening |= ANTAG_FREQS
|
||||
55
code/game/machinery/telecomms/machines/broadcaster.dm
Normal file
55
code/game/machinery/telecomms/machines/broadcaster.dm
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms/broadcaster
|
||||
name = "subspace broadcaster"
|
||||
icon_state = "broadcaster"
|
||||
desc = "A dish-shaped machine used to broadcast processed subspace signals."
|
||||
telecomms_type = /obj/machinery/telecomms/broadcaster
|
||||
idle_power_usage = 100 // WATTS
|
||||
active_power_usage = 3 KILOWATTS
|
||||
produces_heat = FALSE
|
||||
delay = 7
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/broadcaster"
|
||||
var/list/recent_broadcasts
|
||||
|
||||
/obj/machinery/telecomms/broadcaster/Initialize(mapload)
|
||||
. = ..()
|
||||
LAZYINITLIST(recent_broadcasts)
|
||||
|
||||
/obj/machinery/telecomms/broadcaster/receive_information(datum/signal/subspace/signal, obj/machinery/telecomms/machine_from)
|
||||
// Don't broadcast rejected signals
|
||||
if(!istype(signal))
|
||||
return
|
||||
if(signal.data["reject"])
|
||||
return
|
||||
if(!signal.data["message"])
|
||||
return
|
||||
|
||||
// Prevents massive radio spam
|
||||
signal.mark_done()
|
||||
var/datum/signal/subspace/original = signal.original
|
||||
if(original && ("compression" in signal.data))
|
||||
original.data["compression"] = signal.data["compression"]
|
||||
|
||||
signal.levels = broadcast_levels(signal)
|
||||
|
||||
var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]"
|
||||
if(signal_message in recent_broadcasts)
|
||||
return
|
||||
LAZYADD(recent_broadcasts, signal_message)
|
||||
|
||||
if(signal.data["slow"] > 0)
|
||||
addtimer(CALLBACK(signal, /datum/signal/subspace/proc/broadcast), signal.data["slow"]) // network lag
|
||||
else
|
||||
signal.broadcast()
|
||||
|
||||
/* --- Do a snazzy animation! --- */
|
||||
flick("broadcaster_send", src)
|
||||
|
||||
spawn(10)
|
||||
recent_broadcasts -= signal_message
|
||||
43
code/game/machinery/telecomms/machines/bus.dm
Normal file
43
code/game/machinery/telecomms/machines/bus.dm
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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_state = "bus"
|
||||
desc = "A mighty piece of hardware used to send massive amounts of data quickly."
|
||||
telecomms_type = /obj/machinery/telecomms/bus
|
||||
idle_power_usage = 1 KILOWATTS
|
||||
active_power_usage = 3 KILOWATTS
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/bus"
|
||||
netspeed = 40
|
||||
var/change_frequency = 0
|
||||
|
||||
/obj/machinery/telecomms/bus/receive_information(datum/signal/subspace/signal, obj/machinery/telecomms/machine_from)
|
||||
if(!istype(signal) || !is_freq_listening(signal))
|
||||
return
|
||||
|
||||
if(change_frequency && !(signal.frequency in ANTAG_FREQS))
|
||||
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
|
||||
if(relay_information(signal, /obj/machinery/telecomms/processor))
|
||||
return
|
||||
|
||||
signal.data["slow"] += rand(1, 5) // Failed, relay it anyway, a little slower
|
||||
|
||||
// Try sending it!
|
||||
var/list/try_send = list(signal.server_type, /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)
|
||||
i++
|
||||
if(relay_information(signal, send))
|
||||
break
|
||||
31
code/game/machinery/telecomms/machines/hub.dm
Normal file
31
code/game/machinery/telecomms/machines/hub.dm
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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_state = "hub"
|
||||
desc = "A mighty piece of hardware used to send and receive massive amounts of data."
|
||||
telecomms_type = /obj/machinery/telecomms/hub
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
idle_power_usage = 1.6 KILOWATTS
|
||||
active_power_usage = 5 KILOWATTS
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/hub"
|
||||
netspeed = 40
|
||||
|
||||
/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
|
||||
if(!is_freq_listening(signal))
|
||||
return
|
||||
|
||||
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) // ideally relay the copied information to bus units
|
||||
else
|
||||
relay_information(signal, /obj/machinery/telecomms/broadcaster) // Broadcast the current signal to our z-levels
|
||||
@@ -1,31 +1,48 @@
|
||||
#define MESSAGE_SERVER_SPAM_REJECT 1
|
||||
#define MESSAGE_SERVER_DEFAULT_SPAM_LIMIT 10
|
||||
|
||||
var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
|
||||
// Log datums stored by the message server.
|
||||
/datum/data_pda_msg
|
||||
var/recipient = "Unspecified" //name of the person
|
||||
var/sender = "Unspecified" //name of the sender
|
||||
var/sender = "Unspecified"
|
||||
var/recipient = "Unspecified"
|
||||
var/message = "Blank" // transferred message
|
||||
var/icon/photo // attached photo
|
||||
|
||||
/datum/data_pda_msg/New(var/param_rec = "",var/param_sender = "",var/param_message = "")
|
||||
|
||||
/datum/data_pda_msg/New(param_rec, param_sender, param_message, param_photo)
|
||||
if(param_rec)
|
||||
recipient = param_rec
|
||||
if(param_sender)
|
||||
sender = param_sender
|
||||
if(param_message)
|
||||
message = param_message
|
||||
if(param_photo)
|
||||
photo = param_photo
|
||||
|
||||
/datum/data_pda_msg/proc/get_photo_ref()
|
||||
if(photo)
|
||||
return "<a href='byond://?src=["\ref[src]"];photo=1'>(Photo)</a>"
|
||||
return ""
|
||||
|
||||
/datum/data_pda_msg/Topic(href,href_list)
|
||||
..()
|
||||
if(href_list["photo"])
|
||||
var/mob/M = usr
|
||||
M << browse_rsc(photo, "pda_photo.png")
|
||||
M << browse("<html><head><title>PDA Photo</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "</body></html>", "window=pdaphoto;size=192x192")
|
||||
onclose(M, "pdaphoto")
|
||||
|
||||
/datum/data_rc_msg
|
||||
var/rec_dpt = "Unspecified" //name of the person
|
||||
var/send_dpt = "Unspecified" //name of the sender
|
||||
var/message = "Blank" //transferred message
|
||||
var/rec_dpt = "Unspecified" // receiving department
|
||||
var/send_dpt = "Unspecified" // sending department
|
||||
var/message = "Blank"
|
||||
var/stamp = "Unstamped"
|
||||
var/id_auth = "Unauthenticated"
|
||||
var/priority = "Normal"
|
||||
|
||||
/datum/data_rc_msg/New(var/param_rec = "",var/param_sender = "",var/param_message = "",var/param_stamp = "",var/param_id_auth = "",var/param_priority)
|
||||
/datum/data_rc_msg/New(param_rec, param_sender, param_message, param_stamp, param_id_auth, param_priority)
|
||||
if(param_rec)
|
||||
rec_dpt = param_rec
|
||||
if(param_sender)
|
||||
@@ -47,18 +64,17 @@ var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
else
|
||||
priority = "Undetermined"
|
||||
|
||||
/obj/machinery/message_server
|
||||
/obj/machinery/telecomms/message_server
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "server"
|
||||
name = "messaging server"
|
||||
density = 1
|
||||
anchored = 1.0
|
||||
desc = "A machine that processes and routes request console messages."
|
||||
telecomms_type = /obj/machinery/telecomms/message_server
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 100
|
||||
|
||||
var/list/datum/data_pda_msg/pda_msgs = list()
|
||||
var/list/datum/data_pda_msg/pda_msgs = list() // TODO: actually re-link modular PDAs to the message servers
|
||||
var/list/datum/data_rc_msg/rc_msgs = list()
|
||||
var/active = 1
|
||||
var/decryptkey = "password"
|
||||
|
||||
//Spam filtering stuff
|
||||
@@ -67,19 +83,13 @@ var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
//Messages having theese tokens will be rejected by server. Case sensitive
|
||||
var/spamfilter_limit = MESSAGE_SERVER_DEFAULT_SPAM_LIMIT //Maximal amount of tokens
|
||||
|
||||
/obj/machinery/message_server/New()
|
||||
message_servers += src
|
||||
/obj/machinery/telecomms/message_server/Initialize()
|
||||
. = ..()
|
||||
if(!decryptkey)
|
||||
decryptkey = GenerateKey()
|
||||
send_pda_message("System Administrator", "system", "This is an automated message. The messaging system is functioning correctly.")
|
||||
..()
|
||||
return
|
||||
// send_pda_message("System Administrator", "system", "This is an automated message. The messaging system is functioning correctly.")
|
||||
|
||||
/obj/machinery/message_server/Destroy()
|
||||
message_servers -= src
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/message_server/proc/GenerateKey()
|
||||
/obj/machinery/telecomms/message_server/proc/GenerateKey()
|
||||
//Feel free to move to Helpers.
|
||||
var/newKey
|
||||
newKey += pick("the", "if", "of", "as", "in", "a", "you", "from", "to", "an", "too", "little", "snow", "dead", "drunk", "rosebud", "duck", "al", "le")
|
||||
@@ -87,25 +97,20 @@ var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
newKey += pick("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
|
||||
return newKey
|
||||
|
||||
/obj/machinery/message_server/process()
|
||||
//if(decryptkey == "password")
|
||||
// decryptkey = generateKey()
|
||||
if(active && (stat & (BROKEN|NOPOWER)))
|
||||
active = 0
|
||||
return
|
||||
update_icon()
|
||||
/obj/machinery/telecomms/message_server/receive_information(datum/signal/subspace/pda/signal, obj/machinery/telecomms/machine_from)
|
||||
// can't log non-PDA signals
|
||||
if(!istype(signal) || !signal.data["message"] || !use_power || inoperable())
|
||||
return
|
||||
|
||||
/obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "")
|
||||
var/result
|
||||
for (var/token in spamfilter)
|
||||
if (findtextEx(message,token))
|
||||
message = "<font color=\"red\">[message]</font>" //Rejected messages will be indicated by red color.
|
||||
result = token //Token caused rejection (if there are multiple, last will be chosen)
|
||||
pda_msgs += new/datum/data_pda_msg(recipient,sender,message)
|
||||
return result
|
||||
// log the signal
|
||||
pda_msgs += new /datum/data_pda_msg(signal.format_target(), "[signal.data["name"]] ([signal.data["job"]])", signal.data["message"], signal.data["photo"])
|
||||
signal.data -= "reject" // only gets through if it's logged
|
||||
|
||||
/obj/machinery/message_server/proc/send_rc_message(var/recipient = "",var/sender = "",var/message = "",var/stamp = "", var/id_auth = "", var/priority = 1)
|
||||
// pass it along to either the hub or the broadcaster
|
||||
if(!relay_information(signal, /obj/machinery/telecomms/hub))
|
||||
relay_information(signal, /obj/machinery/telecomms/broadcaster)
|
||||
|
||||
/obj/machinery/telecomms/message_server/proc/send_rc_message(var/recipient = "",var/sender = "",var/message = "",var/stamp = "", var/id_auth = "", var/priority = 1)
|
||||
rc_msgs += new/datum/data_rc_msg(recipient,sender,message,stamp,id_auth)
|
||||
var/authmsg = "[message]<br>"
|
||||
if (id_auth)
|
||||
@@ -140,16 +145,16 @@ var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
Console.set_light(2)
|
||||
|
||||
|
||||
/obj/machinery/message_server/attack_hand(user as mob)
|
||||
/obj/machinery/telecomms/message_server/attack_hand(user as mob)
|
||||
// to_chat(user, "\blue There seem to be some parts missing from this server. They should arrive on the station in a few days, give or take a few CentCom delays.")
|
||||
to_chat(user, "You toggle request console message passing from [active ? "On" : "Off"] to [active ? "Off" : "On"]")
|
||||
active = !active
|
||||
to_chat(user, "You toggle request console message passing from [use_power ? "On" : "Off"] to [use_power ? "Off" : "On"]")
|
||||
toggle_power()
|
||||
update_icon()
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/message_server/attackby(obj/item/O as obj, mob/living/user as mob)
|
||||
if (active && !(stat & (BROKEN|NOPOWER)) && (spamfilter_limit < MESSAGE_SERVER_DEFAULT_SPAM_LIMIT*2) && \
|
||||
/obj/machinery/telecomms/message_server/attackby(obj/item/O as obj, mob/living/user as mob)
|
||||
if (use_power && !inoperable(EMPED) && (spamfilter_limit < MESSAGE_SERVER_DEFAULT_SPAM_LIMIT*2) && \
|
||||
istype(O,/obj/item/circuitboard/message_monitor))
|
||||
spamfilter_limit += round(MESSAGE_SERVER_DEFAULT_SPAM_LIMIT / 2)
|
||||
user.drop_from_inventory(O,get_turf(src))
|
||||
@@ -158,22 +163,66 @@ var/global/list/obj/machinery/message_server/message_servers = list()
|
||||
else
|
||||
..(O, user)
|
||||
|
||||
/obj/machinery/message_server/update_icon()
|
||||
if((stat & (BROKEN|NOPOWER)))
|
||||
/obj/machinery/telecomms/message_server/update_icon()
|
||||
if(inoperable(EMPED))
|
||||
icon_state = "server-nopower"
|
||||
else if (!active)
|
||||
else if (!use_power)
|
||||
icon_state = "server-off"
|
||||
else
|
||||
icon_state = "server-on"
|
||||
|
||||
/datum/signal/subspace/pda
|
||||
frequency = PUB_FREQ
|
||||
server_type = /obj/machinery/telecomms/message_server
|
||||
|
||||
/datum/signal/subspace/pda/New(source, data)
|
||||
src.source = source
|
||||
src.data = data
|
||||
var/turf/T = get_turf(source)
|
||||
levels = list(T.z)
|
||||
data["reject"] = TRUE // set to FALSE if a messaging server logs it
|
||||
|
||||
/datum/signal/subspace/pda/copy()
|
||||
var/datum/signal/subspace/pda/copy = new(source, data.Copy())
|
||||
copy.original = src
|
||||
copy.levels = levels
|
||||
return copy
|
||||
|
||||
/datum/signal/subspace/pda/proc/format_target()
|
||||
if (length(data["targets"]) > 1)
|
||||
return "Everyone"
|
||||
return data["targets"][1]
|
||||
|
||||
/datum/signal/subspace/pda/proc/format_message()
|
||||
if (data["photo"])
|
||||
return "[data["message"]] <a href='byond://?src=["\ref[src]"];photo=1'>(Photo)</a>"
|
||||
return data["message"]
|
||||
|
||||
/datum/signal/subspace/pda/broadcast()
|
||||
// TODO: need an iterable list of available PDAs
|
||||
// for (var/obj/item/modular_computer in SSmachinery.machinery)
|
||||
// if ("[P.owner] ([P.ownjob])" in data["targets"])
|
||||
// P.receive_message(src)
|
||||
|
||||
/datum/signal/subspace/pda/Topic(href, href_list)
|
||||
..()
|
||||
if (href_list["photo"])
|
||||
var/mob/M = usr
|
||||
M << browse_rsc(data["photo"], "pda_photo.png")
|
||||
M << browse("<html><head><title>PDA Photo</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "</body></html>", "window=pdaphoto;size=192x192")
|
||||
onclose(M, "pdaphoto")
|
||||
|
||||
var/obj/machinery/blackbox_recorder/blackbox
|
||||
|
||||
/obj/machinery/blackbox_recorder
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "blackbox"
|
||||
name = "blackbox recorder"
|
||||
density = 1
|
||||
anchored = 1.0
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 100
|
||||
|
||||
37
code/game/machinery/telecomms/machines/processor.dm
Normal file
37
code/game/machinery/telecomms/machines/processor.dm
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#define COMPRESS 0
|
||||
#define UNCOMPRESS 1
|
||||
|
||||
/obj/machinery/telecomms/processor
|
||||
name = "processor unit"
|
||||
icon_state = "processor"
|
||||
desc = "This machine is used to process large quantities of information."
|
||||
telecomms_type = /obj/machinery/telecomms/processor
|
||||
delay = 5
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/processor"
|
||||
var/process_mode = UNCOMPRESS
|
||||
|
||||
/obj/machinery/telecomms/processor/receive_information(datum/signal/subspace/signal, obj/machinery/telecomms/machine_from)
|
||||
if(!is_freq_listening(signal))
|
||||
return
|
||||
|
||||
if(!process_mode)
|
||||
signal.data["compression"] = 100 // even more compressed signal
|
||||
else if (signal.data["compression"])
|
||||
signal.data["compression"] = 0 // uncompress subspace 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, signal.server_type)
|
||||
|
||||
#undef COMPRESS
|
||||
#undef UNCOMPRESS
|
||||
27
code/game/machinery/telecomms/machines/receiver.dm
Normal file
27
code/game/machinery/telecomms/machines/receiver.dm
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
The receiver idles and receives messages from subspace-compatible radio equipment;
|
||||
primarily headsets. Received messages are then passed to the network hub, or failing that,
|
||||
the network bus for further processing and broadcast.
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms/receiver
|
||||
name = "subspace receiver"
|
||||
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."
|
||||
telecomms_type = /obj/machinery/telecomms/receiver
|
||||
produces_heat = FALSE
|
||||
overmap_range = 2
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/receiver"
|
||||
|
||||
/obj/machinery/telecomms/receiver/Initialize(mapload)
|
||||
. = ..()
|
||||
SSmachinery.all_receivers += src
|
||||
desc += " It has an effective reception range of [overmap_range] grids on the overmap."
|
||||
|
||||
/obj/machinery/telecomms/receiver/Destroy()
|
||||
SSmachinery.all_receivers -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/receiver/receive_signal(datum/signal/subspace/signal)
|
||||
if(!relay_information(signal, /obj/machinery/telecomms/hub, TRUE))
|
||||
relay_information(signal, /obj/machinery/telecomms/bus, TRUE)
|
||||
104
code/game/machinery/telecomms/machines/server.dm
Normal file
104
code/game/machinery/telecomms/machines/server.dm
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
The server logs all traffic and signal data. Once it records the signal, it sends
|
||||
it to the subspace broadcaster.
|
||||
|
||||
Store a maximum of 400 logs and then deletes them.
|
||||
*/
|
||||
|
||||
// Simple log entry datum
|
||||
|
||||
/datum/comm_log_entry
|
||||
var/input_type = "Speech File"
|
||||
var/name = "data packet (#)"
|
||||
var/parameters = list()
|
||||
|
||||
/obj/machinery/telecomms/server
|
||||
name = "telecommunication server"
|
||||
icon_state = "comm_server"
|
||||
desc = "A machine used to store data and network statistics."
|
||||
telecomms_type = /obj/machinery/telecomms/server
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
idle_power_usage = 300 // WATTS
|
||||
active_power_usage = 1 KILOWATTS
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/server"
|
||||
var/list/log_entries = list()
|
||||
var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes)
|
||||
|
||||
var/rawcode = "" // the code to compile (raw text)
|
||||
var/datum/ntsl2_program/tcomm/Program // NTSL2++ datum responsible for script execution
|
||||
var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up
|
||||
|
||||
/obj/machinery/telecomms/server/Initialize()
|
||||
. = ..()
|
||||
Program = SSntsl2.new_program_tcomm(src)
|
||||
|
||||
/obj/machinery/telecomms/server/receive_information(datum/signal/subspace/vocal/signal, obj/machinery/telecomms/machine_from)
|
||||
// can't log non-vocal signals
|
||||
if(!istype(signal) || !signal.data["message"] || !is_freq_listening(signal))
|
||||
return
|
||||
|
||||
if(traffic > 0)
|
||||
totaltraffic += traffic
|
||||
|
||||
// Delete particularly old logs
|
||||
if (log_entries.len >= 400)
|
||||
log_entries.Cut(1, 2)
|
||||
|
||||
var/datum/comm_log_entry/log = new
|
||||
var/mob/speaker = signal.speaker.resolve()
|
||||
|
||||
if(!istype(speaker))
|
||||
return
|
||||
|
||||
log.parameters["name"] = signal.data["name"]
|
||||
log.parameters["job"] = signal.data["job"]
|
||||
log.parameters["message"] = signal.data["message"]
|
||||
log.parameters["language"] = signal.language || all_languages[LANGUAGE_TCB]
|
||||
|
||||
var/race = "Unidentifiable"
|
||||
if(ishuman(speaker) || isbrain(speaker))
|
||||
race = "Sapient Species"
|
||||
else if(speaker.isMonkey())
|
||||
race = "Monkey"
|
||||
else if(issilicon(speaker) || isobj(speaker))
|
||||
race = "Machinery"
|
||||
else if(isslime(speaker))
|
||||
race = "Slime"
|
||||
else if(isanimal(speaker))
|
||||
race = "Domestic Animal"
|
||||
else if(istype(speaker, /mob/living/announcer))
|
||||
race = "Announcement"
|
||||
|
||||
log.parameters["race"] = race
|
||||
|
||||
// If the signal is still compressed, make the log entry gibberish
|
||||
var/compression = signal.data["compression"]
|
||||
if (compression > 0)
|
||||
log.input_type = "Corrupt File"
|
||||
log.parameters["name"] = Gibberish(signal.data["name"], compression + 50)
|
||||
log.parameters["job"] = Gibberish(signal.data["job"], compression + 50)
|
||||
log.parameters["message"] = Gibberish(signal.data["message"], compression + 50)
|
||||
|
||||
// Give the log a name and store it
|
||||
var/identifier = num2text ( rand(-1000, 1000) + world.time )
|
||||
log.name = "data packet ([md5(identifier)])"
|
||||
log_entries.Add(log)
|
||||
|
||||
if(istype(Program))
|
||||
Program.process_message(signal, CALLBACK(src, .proc/program_receive_information, signal))
|
||||
|
||||
finish_receive_information(signal)
|
||||
|
||||
/obj/machinery/telecomms/server/proc/program_receive_information(datum/signal/signal)
|
||||
Program.retrieve_messages(CALLBACK(src, .proc/finish_receive_information, signal))
|
||||
|
||||
/obj/machinery/telecomms/server/proc/finish_receive_information(datum/signal/signal)
|
||||
var/can_send = relay_information(signal, /obj/machinery/telecomms/hub)
|
||||
if(!can_send)
|
||||
relay_information(signal, /obj/machinery/telecomms/broadcaster)
|
||||
|
||||
/obj/machinery/telecomms/server/process()
|
||||
. = ..()
|
||||
if(istype(Program))
|
||||
Program.retrieve_messages()
|
||||
@@ -1,77 +1,107 @@
|
||||
// ### Preset machines ###
|
||||
|
||||
//Relay
|
||||
|
||||
/obj/machinery/telecomms/relay/preset
|
||||
network = "tcommsat"
|
||||
|
||||
/obj/machinery/telecomms/relay/preset/station
|
||||
id = "Station Relay"
|
||||
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
|
||||
autolinkers = list("r_relay")
|
||||
|
||||
/obj/machinery/telecomms/relay/preset/centcom
|
||||
id = "Centcom Relay"
|
||||
hide = 1
|
||||
toggled = 1
|
||||
//anchored = 1
|
||||
//use_power = POWER_USE_OFF
|
||||
//idle_power_usage = 0
|
||||
produces_heat = 0
|
||||
autolinkers = list("c_relay")
|
||||
|
||||
//HUB
|
||||
|
||||
/obj/machinery/telecomms/hub/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] Hub"
|
||||
network = "tcomm_[name_lower]"
|
||||
autolinkers = list(
|
||||
"[name_lower]_broadcaster",
|
||||
"[name_lower]_hub",
|
||||
"[name_lower]_receiver",
|
||||
"[name_lower]_server"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/hub/preset
|
||||
id = "Hub"
|
||||
network = "tcommsat"
|
||||
autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "science", "medical",
|
||||
"supply", "service", "common", "command", "engineering", "security", "unused",
|
||||
autolinkers = list("hub", "science", "medical", "supply", "service", "common", "command", "engineering", "security", "unused",
|
||||
"receiverA", "broadcasterA")
|
||||
|
||||
/obj/machinery/telecomms/hub/preset_cent
|
||||
id = "CentComm Hub"
|
||||
network = "tcommsat"
|
||||
produces_heat = 0
|
||||
autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay",
|
||||
"centcomm", "receiverCent", "broadcasterCent")
|
||||
autolinkers = list("hub_cent", "centcomm", "receiverCent", "broadcasterCent")
|
||||
|
||||
//Receivers
|
||||
|
||||
/obj/machinery/telecomms/receiver/preset_map
|
||||
var/use_common = FALSE
|
||||
|
||||
/obj/machinery/telecomms/receiver/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] Receiver"
|
||||
network = "tcomm_[name_lower]"
|
||||
freq_listening += list(assign_away_freq(preset_name), HAIL_FREQ)
|
||||
if (use_common)
|
||||
freq_listening += PUB_FREQ
|
||||
autolinkers = list(
|
||||
"[name_lower]_receiver"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/receiver/preset_right
|
||||
id = "Receiver A"
|
||||
network = "tcommsat"
|
||||
autolinkers = list("receiverA") // link to relay
|
||||
autolinkers = list("receiverA")
|
||||
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
|
||||
New()
|
||||
/obj/machinery/telecomms/receiver/preset_right/Initialize()
|
||||
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
|
||||
freq_listening |= i
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/telecomms/receiver/preset_cent
|
||||
id = "CentComm Receiver"
|
||||
network = "tcommsat"
|
||||
produces_heat = 0
|
||||
produces_heat = FALSE
|
||||
autolinkers = list("receiverCent")
|
||||
freq_listening = list(ERT_FREQ, DTH_FREQ)
|
||||
|
||||
|
||||
//Buses
|
||||
/obj/machinery/telecomms/bus/preset_map
|
||||
var/use_common = FALSE
|
||||
|
||||
/obj/machinery/telecomms/bus/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] Bus"
|
||||
network = "tcomm_[name_lower]"
|
||||
freq_listening += list(assign_away_freq(preset_name), HAIL_FREQ)
|
||||
if (use_common)
|
||||
freq_listening += PUB_FREQ
|
||||
autolinkers = list(
|
||||
"[name_lower]_processor",
|
||||
"[name_lower]_server"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/bus/preset_one
|
||||
id = "Bus 1"
|
||||
@@ -85,12 +115,12 @@
|
||||
freq_listening = list(SUP_FREQ, SRV_FREQ)
|
||||
autolinkers = list("processor2", "supply", "service", "unused")
|
||||
|
||||
/obj/machinery/telecomms/bus/preset_two/New()
|
||||
/obj/machinery/telecomms/bus/preset_two/Initialize()
|
||||
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
|
||||
if(i == PUB_FREQ)
|
||||
if(i == PUB_FREQ || i == ENT_FREQ)
|
||||
continue
|
||||
freq_listening |= i
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/bus/preset_three
|
||||
id = "Bus 3"
|
||||
@@ -101,18 +131,35 @@
|
||||
/obj/machinery/telecomms/bus/preset_four
|
||||
id = "Bus 4"
|
||||
network = "tcommsat"
|
||||
freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ, ENT_FREQ)
|
||||
freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ, ENT_FREQ, HAIL_FREQ)
|
||||
autolinkers = list("processor4", "engineering", "common")
|
||||
|
||||
/obj/machinery/telecomms/bus/preset_cent
|
||||
id = "CentComm Bus"
|
||||
network = "tcommsat"
|
||||
freq_listening = list(ERT_FREQ, DTH_FREQ, ENT_FREQ)
|
||||
produces_heat = 0
|
||||
produces_heat = FALSE
|
||||
autolinkers = list("processorCent", "centcomm")
|
||||
|
||||
//Processors
|
||||
|
||||
/obj/machinery/telecomms/processor/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] Processor"
|
||||
network = "tcomm_[name_lower]"
|
||||
autolinkers = list(
|
||||
"[name_lower]_processor"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/processor/preset_one
|
||||
id = "Processor 1"
|
||||
network = "tcommsat"
|
||||
@@ -136,13 +183,37 @@
|
||||
/obj/machinery/telecomms/processor/preset_cent
|
||||
id = "CentComm Processor"
|
||||
network = "tcommsat"
|
||||
produces_heat = 0
|
||||
produces_heat = FALSE
|
||||
autolinkers = list("processorCent")
|
||||
|
||||
//Servers
|
||||
/obj/machinery/telecomms/server/preset_map
|
||||
var/use_common = FALSE
|
||||
|
||||
/obj/machinery/telecomms/server/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] server"
|
||||
network = "tcomm_[name_lower]"
|
||||
freq_listening += list(
|
||||
assign_away_freq(preset_name),
|
||||
HAIL_FREQ
|
||||
)
|
||||
if(use_common)
|
||||
freq_listening += PUB_FREQ
|
||||
autolinkers = list(
|
||||
"[name_lower]_server"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/server/presets
|
||||
|
||||
network = "tcommsat"
|
||||
|
||||
/obj/machinery/telecomms/server/presets/science
|
||||
@@ -167,7 +238,7 @@
|
||||
|
||||
/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, MED_I_FREQ, SEC_I_FREQ, HAIL_FREQ) // AI Private, Common, and Dept. Intercoms
|
||||
autolinkers = list("common")
|
||||
|
||||
// "Unused" channels, AKA all others.
|
||||
@@ -178,7 +249,7 @@
|
||||
|
||||
/obj/machinery/telecomms/server/presets/unused/New()
|
||||
for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2)
|
||||
if(i == AI_FREQ || i == PUB_FREQ)
|
||||
if(i == AI_FREQ || i == PUB_FREQ || i == ENT_FREQ || i == MED_I_FREQ || i == SEC_I_FREQ || i == HAIL_FREQ)
|
||||
continue
|
||||
freq_listening |= i
|
||||
..()
|
||||
@@ -209,6 +280,23 @@
|
||||
|
||||
//--PRESET LEFT--//
|
||||
|
||||
/obj/machinery/telecomms/broadcaster/preset_map/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(istype(linked) && linked.comms_support)
|
||||
var/preset_name = linked.comms_name
|
||||
var/name_lower = replacetext(lowertext(preset_name), " ", "_")
|
||||
id = "[preset_name] broadcaster"
|
||||
network = "tcomm_[name_lower]"
|
||||
autolinkers = list(
|
||||
"[name_lower]_broadcaster"
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/telecomms/broadcaster/preset_right
|
||||
id = "Broadcaster A"
|
||||
network = "tcommsat"
|
||||
|
||||
247
code/game/machinery/telecomms/telecommunications.dm
Normal file
247
code/game/machinery/telecomms/telecommunications.dm
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
Telecommunications machines handle communications over radio and subspace networks, primarily for radio communication
|
||||
but also for a variety of other networked machines.
|
||||
|
||||
Signals are received by the closest active and viable receiver, i.e. one listening on their frequency and powered. Only one receiver processes any given signal normally.
|
||||
Hubs take incoming signals from receivers and passes them to the bus for processing, and take completed messages from the server to broadcast
|
||||
Buses move signals from hub to processor, and then to the signal's designated server (usually the Tcomms server)
|
||||
Processors decompress compressed signals (and vice versa), sending the processed signal back to the bus.
|
||||
Servers log the processed radio messages and perform any NTSL functions on the messages before sending them to be broadcast via the hub.
|
||||
Broadcasters take completed messages and send them to all available devices within their broadcasting range.
|
||||
|
||||
All-in-Ones, as the name suggests, provide all of this functionality (to some extent) in a compact package, capable of receiving and broadcasting signals to their own connected z-level(s).
|
||||
AIOs by default only receive and broadcast communications on their own bespoke frequency and the hailing frequency.
|
||||
|
||||
The routing that radio-frequency machines take is relatively simple:
|
||||
|
||||
Inbound Signal -> Receiver -> Hub -> Bus -> Processor -> Bus -> Server -> Hub -> Broadcaster
|
||||
*/
|
||||
|
||||
/obj/machinery/telecomms
|
||||
icon = 'icons/obj/machines/telecomms.dmi'
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
idle_power_usage = 600 // WATTS
|
||||
active_power_usage = 2 KILOWATTS
|
||||
|
||||
var/list/links = list() // list of machines this machine is linked to
|
||||
/*
|
||||
Associative lazylist of the telecomms_type of linked telecomms machines and a list of said machines
|
||||
eg list(telecomms_type1 = list(everything linked to us with that type), telecomms_type2 = list(everything linked to us with THAT type, etc.))
|
||||
*/
|
||||
var/list/links_by_telecomms_type
|
||||
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/telecomms_type = null // Relevant typepath of the machine (important to use machine's base path rather than server/preset or w.e)
|
||||
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/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/circuitboard = null // string pointing to a circuitboard type
|
||||
var/hide = FALSE // Is it a hidden machine?
|
||||
|
||||
// Overmap ranges in terms of map tile distance, used by receivers, relays, and broadcasters (and AIOs)
|
||||
var/overmap_range = 0
|
||||
|
||||
///Looping sounds for any servers
|
||||
// var/datum/looping_sound/server/soundloop
|
||||
|
||||
|
||||
/obj/machinery/telecomms/Initialize(mapload)
|
||||
. = ..()
|
||||
// soundloop = new(list(src), on)
|
||||
SSmachinery.all_telecomms += src
|
||||
|
||||
if(mapload)
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/telecomms/LateInitialize()
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
if(autolinkers.len)
|
||||
for(var/obj/machinery/telecomms/T in SSmachinery.all_telecomms)
|
||||
if(T != src && (T.z in GetConnectedZlevels(z)))
|
||||
add_automatic_link(T)
|
||||
|
||||
/obj/machinery/telecomms/Destroy()
|
||||
// QDEL_NULL(soundloop)
|
||||
SSmachinery.all_telecomms -= src
|
||||
for(var/obj/machinery/telecomms/comm in SSmachinery.all_telecomms)
|
||||
remove_link(comm)
|
||||
links = list()
|
||||
return ..()
|
||||
|
||||
// This proc returns distance, so -1 is our error value
|
||||
/obj/machinery/telecomms/proc/receive_range(datum/signal/subspace/sig)
|
||||
if(!use_power || !istype(sig) || !is_freq_listening(sig))
|
||||
return -1
|
||||
|
||||
return get_signal_dist(sig)
|
||||
|
||||
/obj/machinery/telecomms/proc/broadcast_levels(datum/signal/subspace/sig)
|
||||
if(!use_power || !istype(sig) || !is_freq_listening(sig))
|
||||
return
|
||||
|
||||
. = GetConnectedZlevels(z)
|
||||
if(current_map.use_overmap && linked)
|
||||
for(var/obj/effect/overmap/visitable/V in range(overmap_range, linked))
|
||||
. |= V.map_z
|
||||
|
||||
// Used in auto linking
|
||||
/obj/machinery/telecomms/proc/add_automatic_link(var/obj/machinery/telecomms/T)
|
||||
if(src == T)
|
||||
return
|
||||
|
||||
for(var/autolinker_id in autolinkers)
|
||||
if(autolinker_id in T.autolinkers)
|
||||
add_new_link(T)
|
||||
return
|
||||
|
||||
/obj/machinery/telecomms/update_icon()
|
||||
var/state = construct_op ? "[initial(icon_state)]_o" : initial(icon_state)
|
||||
if(!use_power)
|
||||
state += "_off"
|
||||
|
||||
icon_state = state
|
||||
|
||||
/obj/machinery/telecomms/process()
|
||||
if(!use_power) return
|
||||
if(inoperable(EMPED))
|
||||
toggle_power(additional_flags = EMPED)
|
||||
return
|
||||
|
||||
// Check heat and generate some
|
||||
check_heat()
|
||||
traffic = max(0, traffic - netspeed)
|
||||
|
||||
if(traffic > 0)
|
||||
toggle_power(POWER_USE_ACTIVE)
|
||||
else
|
||||
toggle_power(POWER_USE_IDLE)
|
||||
|
||||
/obj/machinery/telecomms/emp_act(severity)
|
||||
. = ..()
|
||||
if(stat & EMPED || !prob(100/severity))
|
||||
return
|
||||
stat |= EMPED
|
||||
var/duration = (300 SECONDS)/severity
|
||||
spawn(duration + rand(-20, 20))
|
||||
stat &= ~EMPED
|
||||
|
||||
/obj/machinery/telecomms/proc/check_heat()
|
||||
// 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(use_power)
|
||||
produce_heat()
|
||||
delay = initial(delay)
|
||||
|
||||
/obj/machinery/telecomms/proc/produce_heat()
|
||||
if (!produces_heat || !use_power || inoperable(EMPED))
|
||||
return
|
||||
|
||||
var/turf/simulated/L = loc
|
||||
if(!istype(L))
|
||||
return
|
||||
|
||||
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)
|
||||
return
|
||||
|
||||
var/heat_produced = get_power_usage() //obviously can't produce more heat than the machine draws from it's power source
|
||||
if (use_power < POWER_USE_ACTIVE)
|
||||
heat_produced *= 0.30 //if idle, produce less heat.
|
||||
|
||||
removed.add_thermal_energy(heat_produced)
|
||||
env.merge(removed)
|
||||
|
||||
// relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending
|
||||
/obj/machinery/telecomms/proc/relay_information(datum/signal/subspace/signal, filter, copysig, amount = 20)
|
||||
if(!use_power)
|
||||
return
|
||||
|
||||
if(!filter || !ispath(filter, /obj/machinery/telecomms))
|
||||
CRASH("null or non /obj/machinery/telecomms typepath given as the filter argument! given typepath: [filter]")
|
||||
|
||||
var/send_count = 0
|
||||
|
||||
if(integrity < 100)
|
||||
signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity
|
||||
|
||||
// Loop through all linked machines and send the signal or copy.
|
||||
for(var/obj/machinery/telecomms/filtered_machine in links_by_telecomms_type?[filter])
|
||||
if(!filtered_machine.use_power || !(z in GetConnectedZlevels(filtered_machine.z)))
|
||||
continue
|
||||
|
||||
if(amount && send_count >= amount)
|
||||
break
|
||||
|
||||
send_count++
|
||||
|
||||
if(filtered_machine.is_freq_listening(signal))
|
||||
filtered_machine.traffic++
|
||||
|
||||
if(copysig)
|
||||
filtered_machine.receive_information(signal.copy(), src)
|
||||
else
|
||||
filtered_machine.receive_information(signal, src)
|
||||
|
||||
if(send_count > 0 && is_freq_listening(signal))
|
||||
traffic++
|
||||
|
||||
return send_count
|
||||
|
||||
// send signal directly to a machine
|
||||
/obj/machinery/telecomms/proc/relay_direct_information(datum/signal/signal, obj/machinery/telecomms/machine)
|
||||
if(use_power)
|
||||
machine.receive_information(signal, src)
|
||||
|
||||
// receive information from linked machinery
|
||||
/obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
|
||||
return
|
||||
|
||||
/obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal)
|
||||
// return TRUE if found, FALSE if not found
|
||||
return signal && (!freq_listening.len || (signal.frequency in freq_listening))
|
||||
|
||||
// Reception range of telecomms machines is limited via overmap_range
|
||||
// Returns distance, not a boolean value, so don't do !get_reception or so help me god
|
||||
/obj/machinery/telecomms/proc/get_signal_dist(datum/signal/subspace/signal)
|
||||
if(!current_map.use_overmap || !istype(linked) || !istype(signal.sector))
|
||||
if(z == signal.origin_level || (signal.origin_level in GetConnectedZlevels(z)))
|
||||
return 1
|
||||
else
|
||||
return -1
|
||||
|
||||
if (signal.sector == linked)
|
||||
return 0
|
||||
|
||||
var/overmap_dist = get_dist(signal.sector, linked)
|
||||
if (overmap_dist > overmap_range)
|
||||
return -1
|
||||
return overmap_dist
|
||||
@@ -1,648 +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/machines/telecomms.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/circuitboard = null // string pointing to a circuitboard type
|
||||
var/hide = 0 // Is it a hidden machine?
|
||||
var/list/listening_level = 0 // 0 = auto set in New() - this is the z level that the machine is listening to.
|
||||
|
||||
var/overmap_range = 2 //OVERMAP: Number of sectors out we can communicate
|
||||
|
||||
///Looping sounds for any servers
|
||||
// var/datum/looping_sound/server/soundloop
|
||||
|
||||
/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
|
||||
var/send_count = 0
|
||||
|
||||
signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity
|
||||
|
||||
// Loop through all linked machines and send the signal or copy.
|
||||
for(var/obj/machinery/telecomms/machine in links)
|
||||
if(filter && !istype( machine, text2path(filter) ))
|
||||
continue
|
||||
if(!machine.on)
|
||||
continue
|
||||
if(amount && send_count >= amount)
|
||||
break
|
||||
if(!(machine.loc.z in 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
|
||||
|
||||
//OVERMAP: Since telecomms is subspace, limit how far it goes. This prevents double-broadcasts across the entire overmap, and gives the ability to intrude on comms range of other ships
|
||||
/obj/machinery/telecomms/proc/check_receive_sector(datum/signal/signal)
|
||||
if(isAdminLevel(z) || isAdminLevel(signal.data["level"])) //Messages to and from centcomm levels are not sector-restricted.
|
||||
return TRUE
|
||||
if(current_map.use_overmap)
|
||||
if(!linked) //If we're using overmap and not associated with a sector, doesn't work.
|
||||
return FALSE
|
||||
var/obj/effect/overmap/visitable/S = signal.data["sector"]
|
||||
if(istype(S)) //If our signal isn't sending a sector, it's something associated with telecomms_process_active(), which has their own limits.
|
||||
if(S != linked) //If we're not the same ship, check range
|
||||
if(get_dist(S, linked) > overmap_range && !(S in view(overmap_range, linked)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/telecomms/New()
|
||||
telecomms_list += src
|
||||
..()
|
||||
|
||||
/obj/machinery/telecomms/Initialize()
|
||||
. = ..()
|
||||
// soundloop = new(list(src), on)
|
||||
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)
|
||||
if(!listening_level)
|
||||
listening_level = list(z)
|
||||
var/turf/above = GetAbove(src)
|
||||
var/turf/below = GetBelow(src)
|
||||
if(above)
|
||||
listening_level += above.z
|
||||
if(below)
|
||||
listening_level += below.z
|
||||
|
||||
if(current_map.use_overmap && !linked)
|
||||
var/my_sector = map_sectors["[z]"]
|
||||
if (istype(my_sector, /obj/effect/overmap/visitable))
|
||||
attempt_hook_up(my_sector)
|
||||
|
||||
/obj/machinery/telecomms/Destroy()
|
||||
// QDEL_NULL(soundloop)
|
||||
telecomms_list -= src
|
||||
for(var/obj/machinery/telecomms/comm in telecomms_list)
|
||||
comm.links -= src
|
||||
links = list()
|
||||
return ..()
|
||||
|
||||
// Used in auto linking
|
||||
/obj/machinery/telecomms/proc/add_link(var/obj/machinery/telecomms/T)
|
||||
var/turf/position = get_turf(src)
|
||||
var/turf/T_position = get_turf(T)
|
||||
if((position.z == T_position.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()
|
||||
var/state = construct_op ? "[initial(icon_state)]_o" : initial(icon_state)
|
||||
if(!on)
|
||||
state += "_off"
|
||||
|
||||
icon_state = state
|
||||
|
||||
/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 = FALSE
|
||||
// soundloop.stop(src)
|
||||
else
|
||||
on = TRUE
|
||||
// soundloop.start(src)
|
||||
else
|
||||
on = FALSE
|
||||
// soundloop.stop(src)
|
||||
|
||||
/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_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
|
||||
idle_power_usage = 600
|
||||
machinetype = 1
|
||||
produces_heat = 0
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/receiver"
|
||||
|
||||
/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(!check_receive_sector(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(!(signal.data["level"] in listening_level))
|
||||
for(var/obj/machinery/telecomms/hub/H in links)
|
||||
var/list/connected_levels = list()
|
||||
for(var/obj/machinery/telecomms/relay/R in H.links)
|
||||
if(R.can_receive(signal))
|
||||
connected_levels |= R.listening_level
|
||||
if(signal.data["level"] in connected_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_state = "hub"
|
||||
desc = "A mighty piece of hardware used to send/receive massive amounts of data."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 1600
|
||||
machinetype = 7
|
||||
circuitboard = "/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_state = "relay"
|
||||
desc = "A mighty piece of hardware used to send massive amounts of data far away."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 600
|
||||
machinetype = 8
|
||||
produces_heat = 0
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/relay"
|
||||
netspeed = 5
|
||||
long_range_link = 1
|
||||
var/broadcasting = TRUE
|
||||
var/receiving = 1
|
||||
|
||||
/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"] |= 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_state = "bus"
|
||||
desc = "A mighty piece of hardware used to send massive amounts of data quickly."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 1000
|
||||
machinetype = 2
|
||||
circuitboard = "/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_state = "processor"
|
||||
desc = "This machine is used to process large quantities of information."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 600
|
||||
machinetype = 3
|
||||
delay = 5
|
||||
circuitboard = "/obj/item/circuitboard/telecomms/processor"
|
||||
var/process_mode = 1 // 1 = Uncompress Signals, 0 = Compress Signals
|
||||
|
||||
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_state = "comm_server"
|
||||
desc = "A machine used to store data and network statistics."
|
||||
density = 1
|
||||
anchored = 1
|
||||
idle_power_usage = 300
|
||||
machinetype = 4
|
||||
circuitboard = "/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/ntsl2_program/tcomm/Program // NTSL2++ datum responsible for script execution
|
||||
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/language = "human"
|
||||
var/obj/item/device/radio/headset/server_radio = null
|
||||
|
||||
/obj/machinery/telecomms/server/Initialize()
|
||||
. = ..()
|
||||
Program = SSntsl2.new_program_tcomm(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"] != 4)
|
||||
|
||||
// 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"] = signal.data["message"]
|
||||
log.parameters["vname"] = signal.data["vname"]
|
||||
log.parameters["message"] = signal.data["message"]
|
||||
log.parameters["name"] = signal.data["name"]
|
||||
log.parameters["realname"] = signal.data["realname"]
|
||||
log.parameters["language"] = signal.data["language"]
|
||||
|
||||
var/race = "Unknown"
|
||||
if(ishuman(M) || isbrain(M))
|
||||
race = "Sapient Species"
|
||||
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"
|
||||
else if(istype(M, /mob/living/announcer))
|
||||
race = "Announcer"
|
||||
|
||||
log.parameters["race"] = race
|
||||
|
||||
if(!istype(M, /mob/abstract/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(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(istype(Program))
|
||||
Program.process_message(signal, CALLBACK(src, .proc/program_receive_information, signal))
|
||||
|
||||
finish_receive_information(signal)
|
||||
|
||||
/obj/machinery/telecomms/server/proc/program_receive_information(datum/signal/signal)
|
||||
Program.retrieve_messages(CALLBACK(src, .proc/finish_receive_information, signal))
|
||||
|
||||
/obj/machinery/telecomms/server/proc/finish_receive_information(datum/signal/signal)
|
||||
var/can_send = relay_information(signal, "/obj/machinery/telecomms/hub")
|
||||
if(!can_send)
|
||||
relay_information(signal, "/obj/machinery/telecomms/broadcaster")
|
||||
|
||||
|
||||
/obj/machinery/telecomms/server/process()
|
||||
. = ..()
|
||||
if(istype(Program))
|
||||
Program.retrieve_messages()
|
||||
|
||||
/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_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"
|
||||
|
||||
|
||||
|
||||
// NTSL2++ code
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
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 = "A monitor that tracks the overall traffic of a telecommunicaations network, and displays a hierarchy of linked machines."
|
||||
icon_screen = "comm_monitor"
|
||||
icon_keyboard = "green_key"
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
var/screen = 0 // the screen number:
|
||||
var/list/machinelist = list() // the machines located by the computer
|
||||
var/obj/machinery/telecomms/SelectedMachine
|
||||
|
||||
var/network = "NULL" // the network to probe
|
||||
|
||||
var/temp = "" // temporary feedback messages
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = "<TITLE>Telecommunications Monitor</TITLE><center><b>Telecommunications Monitor</b></center>"
|
||||
|
||||
switch(screen)
|
||||
|
||||
|
||||
// --- Main Menu ---
|
||||
|
||||
if(0)
|
||||
dat += "<br>[temp]<br><br>"
|
||||
dat += "<br>Current Network: <a href='?src=\ref[src];network=1'>[network]</a><br>"
|
||||
if(machinelist.len)
|
||||
dat += "<br>Detected Network Entities:<ul>"
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
dat += "<li><a href='?src=\ref[src];viewmachine=[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 += "<a href='?src=\ref[src];operation=probe'>\[Probe Network\]</a>"
|
||||
|
||||
|
||||
// --- Viewing Machine ---
|
||||
|
||||
if(1)
|
||||
dat += "<br>[temp]<br>"
|
||||
dat += "<center><a href='?src=\ref[src];operation=mainmenu'>\[Main Menu\]</a></center>"
|
||||
dat += "<br>Current Network: [network]<br>"
|
||||
dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])<br>"
|
||||
dat += "Linked Entities: <ol>"
|
||||
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
|
||||
if(!T.hide)
|
||||
dat += "<li><a href='?src=\ref[src];viewmachine=[T.id]'>\ref[T.id] [T.name]</a> ([T.id])</li>"
|
||||
dat += "</ol>"
|
||||
|
||||
|
||||
|
||||
user << browse(dat, "window=comm_monitor;size=575x400")
|
||||
onclose(user, "server_control")
|
||||
|
||||
temp = ""
|
||||
return
|
||||
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["viewmachine"])
|
||||
screen = 1
|
||||
for(var/obj/machinery/telecomms/T in machinelist)
|
||||
if(T.id == href_list["viewmachine"])
|
||||
SelectedMachine = T
|
||||
break
|
||||
|
||||
if(href_list["operation"])
|
||||
switch(href_list["operation"])
|
||||
|
||||
if("release")
|
||||
machinelist = list()
|
||||
screen = 0
|
||||
|
||||
if("mainmenu")
|
||||
screen = 0
|
||||
|
||||
if("probe")
|
||||
if(machinelist.len > 0)
|
||||
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font>"
|
||||
|
||||
else
|
||||
for(var/obj/machinery/telecomms/T in range(25, src))
|
||||
if(T.network == network)
|
||||
machinelist.Add(T)
|
||||
|
||||
if(!machinelist.len)
|
||||
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -</font>"
|
||||
else
|
||||
temp = "<font color = #336699>- [machinelist.len] ENTITIES LOCATED & BUFFERED -</font>"
|
||||
|
||||
screen = 0
|
||||
|
||||
|
||||
if(href_list["network"])
|
||||
|
||||
var/newnet = sanitize(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
|
||||
machinelist = list()
|
||||
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font>"
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
attackby(var/obj/item/D as obj, var/mob/user as mob)
|
||||
if(D.isscrewdriver())
|
||||
if(D.use_tool(src, user, 20, volume = 50))
|
||||
if (src.stat & BROKEN)
|
||||
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
new /obj/item/material/shard( src.loc )
|
||||
var/obj/item/circuitboard/comm_monitor/M = new /obj/item/circuitboard/comm_monitor( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 3
|
||||
A.icon_state = "3"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
var/obj/item/circuitboard/comm_monitor/M = new /obj/item/circuitboard/comm_monitor( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 4
|
||||
A.icon_state = "4"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src.loc, '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
|
||||
@@ -1,246 +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"
|
||||
icon_screen = "computer_generic"
|
||||
icon_keyboard = "green_key"
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
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
|
||||
|
||||
var/network = "NULL" // the network to probe
|
||||
var/temp = "" // temporary feedback messages
|
||||
|
||||
var/storedcode = "" // code stored
|
||||
|
||||
|
||||
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()
|
||||
|
||||
|
||||
|
||||
req_access = list(access_tcomsat)
|
||||
|
||||
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
|
||||
|
||||
|
||||
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 = sanitize(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
|
||||
|
||||
attackby(var/obj/item/D as obj, var/mob/user as mob)
|
||||
if(D.isscrewdriver())
|
||||
if(D.use_tool(src, user, 20, volume = 50))
|
||||
if (src.stat & BROKEN)
|
||||
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
new /obj/item/material/shard( src.loc )
|
||||
var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 3
|
||||
A.icon_state = "3"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
|
||||
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
|
||||
var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A )
|
||||
for (var/obj/C in src)
|
||||
C.forceMove(src.loc)
|
||||
A.circuit = M
|
||||
A.state = 4
|
||||
A.icon_state = "4"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/telecomms/traffic/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src.loc, '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
|
||||
@@ -280,13 +280,13 @@
|
||||
<table class="request">
|
||||
<tr>
|
||||
<td class="radio">Transmit:</td>
|
||||
<td><a href='byond://?src=\ref[src];wires=4'>[radio.broadcasting ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
|
||||
<td><a href='byond://?src=\ref[src];wires=4'>[radio.get_broadcasting() ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="radio">Receive:</td>
|
||||
<td><a href='byond://?src=\ref[src];wires=2'>[radio.listening ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
|
||||
<td><a href='byond://?src=\ref[src];wires=2'>[radio.get_listening() ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -371,9 +371,9 @@
|
||||
var/t1 = text2num(href_list["wires"])
|
||||
switch(t1)
|
||||
if(4)
|
||||
radio.ToggleBroadcast()
|
||||
radio.set_broadcasting(!radio.get_broadcasting())
|
||||
if(2)
|
||||
radio.ToggleReception()
|
||||
radio.set_listening(!radio.get_listening())
|
||||
if(href_list["setlaws"])
|
||||
var/newlaws = sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.pai_laws) as message)
|
||||
if(newlaws)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#define CHANNEL_COMMON "Common"
|
||||
#define CHANNEL_ENTERTAINMENT "Entertainment"
|
||||
#define CHANNEL_HAILING "Hailing"
|
||||
#define CHANNEL_COMMAND "Command"
|
||||
#define CHANNEL_SCIENCE "Science"
|
||||
#define CHANNEL_MEDICAL "Medical"
|
||||
@@ -17,11 +18,11 @@
|
||||
#define CHANNEL_NINJA "Ninja"
|
||||
#define CHANNEL_BLUESPACE "Bluespace"
|
||||
#define CHANNEL_BURGLAR "Burglar"
|
||||
#define CHANNEL_SHIP "Ship"
|
||||
|
||||
var/global/list/ALL_RADIO_CHANNELS = list(
|
||||
CHANNEL_COMMON = TRUE,
|
||||
CHANNEL_ENTERTAINMENT = TRUE,
|
||||
CHANNEL_HAILING = TRUE,
|
||||
CHANNEL_COMMAND = TRUE,
|
||||
CHANNEL_SCIENCE = TRUE,
|
||||
CHANNEL_MEDICAL = TRUE,
|
||||
@@ -36,6 +37,5 @@ var/global/list/ALL_RADIO_CHANNELS = list(
|
||||
CHANNEL_MERCENARY = TRUE,
|
||||
CHANNEL_NINJA = TRUE,
|
||||
CHANNEL_BLUESPACE = TRUE,
|
||||
CHANNEL_BURGLAR = TRUE,
|
||||
CHANNEL_SHIP = TRUE
|
||||
CHANNEL_BURGLAR = TRUE
|
||||
)
|
||||
@@ -3,7 +3,6 @@
|
||||
desc = "Dance my monkeys! DANCE!!!"
|
||||
icon_state = "electropack0"
|
||||
item_state = "electropack"
|
||||
frequency = 1449
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BACK
|
||||
w_class = ITEMSIZE_HUGE
|
||||
@@ -12,6 +11,10 @@
|
||||
|
||||
var/code = 2
|
||||
|
||||
/obj/item/device/radio/electropack/Initialize()
|
||||
. = ..()
|
||||
set_frequency(1449)
|
||||
|
||||
/obj/item/device/radio/electropack/attack_hand(mob/user as mob)
|
||||
if(src == user.back)
|
||||
to_chat(user, "<span class='notice'>You need help taking this off!</span>")
|
||||
|
||||
@@ -9,34 +9,60 @@
|
||||
var/translate_binary = FALSE
|
||||
var/translate_hivenet = FALSE
|
||||
var/syndie = FALSE // Signifies that it de-crypts Syndicate transmissions
|
||||
var/independent = FALSE // Signifies that it lets you talk on the spicy channel
|
||||
var/list/channels = list(CHANNEL_COMMON = TRUE, CHANNEL_ENTERTAINMENT = TRUE)
|
||||
var/list/additional_channels = list()
|
||||
|
||||
/obj/item/device/encryptionkey/attackby(obj/item/W, mob/user)
|
||||
return
|
||||
|
||||
/obj/item/device/encryptionkey/ship
|
||||
var/use_common = FALSE
|
||||
channels = list()
|
||||
|
||||
/obj/item/device/encryptionkey/ship/Initialize()
|
||||
if(!current_map.use_overmap)
|
||||
return ..()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/overmap/visitable/V = map_sectors["[T.z]"]
|
||||
if(istype(V) && V.comms_support)
|
||||
if(V.comms_name)
|
||||
name = "[V.comms_name] encryption key"
|
||||
|
||||
channels += list(
|
||||
"[V.name]" = TRUE,
|
||||
CHANNEL_HAILING = TRUE
|
||||
)
|
||||
|
||||
if(use_common)
|
||||
channels += list(CHANNEL_COMMON, TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/ship/common
|
||||
use_common = TRUE
|
||||
|
||||
/obj/item/device/encryptionkey/syndicate
|
||||
icon_state = "cypherkey"
|
||||
additional_channels = list(CHANNEL_MERCENARY = TRUE)
|
||||
additional_channels = list(CHANNEL_MERCENARY = TRUE, CHANNEL_HAILING = TRUE)
|
||||
origin_tech = list(TECH_ILLEGAL = 3)
|
||||
desc_antag = "An encryption key that allows you to intercept comms and speak on private non-station channels. Use :t to access the private channel."
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/encryptionkey/raider
|
||||
icon_state = "cypherkey"
|
||||
additional_channels = list(CHANNEL_RAIDER = TRUE)
|
||||
additional_channels = list(CHANNEL_RAIDER = TRUE, CHANNEL_HAILING = TRUE)
|
||||
origin_tech = list(TECH_ILLEGAL = 2)
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/encryptionkey/burglar
|
||||
icon_state = "cypherkey"
|
||||
additional_channels = list(CHANNEL_BURGLAR = TRUE)
|
||||
additional_channels = list(CHANNEL_BURGLAR = TRUE, CHANNEL_HAILING = TRUE)
|
||||
origin_tech = list(TECH_ILLEGAL = 2)
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/encryptionkey/ninja
|
||||
icon_state = "cypherkey"
|
||||
additional_channels = list(CHANNEL_NINJA = TRUE)
|
||||
additional_channels = list(CHANNEL_NINJA = TRUE, CHANNEL_HAILING = TRUE)
|
||||
origin_tech = list(TECH_ILLEGAL = 3)
|
||||
syndie = TRUE
|
||||
|
||||
@@ -48,10 +74,6 @@
|
||||
origin_tech = list(TECH_BLUESPACE = 3)
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/encryptionkey/ship
|
||||
icon_state = "cypherkey"
|
||||
additional_channels = list(CHANNEL_SHIP = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/binary
|
||||
icon_state = "cypherkey"
|
||||
translate_binary = TRUE
|
||||
@@ -107,43 +129,43 @@
|
||||
/obj/item/device/encryptionkey/headset_com
|
||||
name = "command radio encryption key"
|
||||
icon_state = "com_cypherkey"
|
||||
channels = list(CHANNEL_COMMAND = TRUE)
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/captain
|
||||
name = "captain's encryption key"
|
||||
icon_state = "cap_cypherkey"
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE)
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/ai_integrated
|
||||
name = "ai integrated encryption key"
|
||||
desc = "Integrated encryption key"
|
||||
icon_state = "cap_cypherkey"
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE, CHANNEL_AI_PRIVATE = TRUE)
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE, CHANNEL_AI_PRIVATE = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/rd
|
||||
name = "research director's encryption key"
|
||||
icon_state = "rd_cypherkey"
|
||||
channels = list(CHANNEL_SCIENCE = TRUE, CHANNEL_COMMAND = TRUE)
|
||||
channels = list(CHANNEL_SCIENCE = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/hos
|
||||
name = "head of security's encryption key"
|
||||
icon_state = "hos_cypherkey"
|
||||
channels = list(CHANNEL_SECURITY = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_PENAL = TRUE)
|
||||
channels = list(CHANNEL_SECURITY = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/ce
|
||||
name = "chief engineer's encryption key"
|
||||
icon_state = "ce_cypherkey"
|
||||
channels = list(CHANNEL_ENGINEERING = TRUE, CHANNEL_COMMAND = TRUE)
|
||||
channels = list(CHANNEL_ENGINEERING = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/cmo
|
||||
name = "chief medical officer's encryption key"
|
||||
icon_state = "cmo_cypherkey"
|
||||
channels = list(CHANNEL_MEDICAL = TRUE, CHANNEL_COMMAND = TRUE)
|
||||
channels = list(CHANNEL_MEDICAL = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/xo
|
||||
name = "executive officer's encryption key"
|
||||
icon_state = "hop_cypherkey"
|
||||
channels = list(CHANNEL_SERVICE = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE)
|
||||
channels = list(CHANNEL_SERVICE = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_PENAL = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_cargo
|
||||
name = "operations radio encryption key"
|
||||
@@ -153,7 +175,7 @@
|
||||
/obj/item/device/encryptionkey/headset_operations_manager
|
||||
name = "operations managaer radio encryption key"
|
||||
icon_state = "cargo_cypherkey"
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SUPPLY = TRUE)
|
||||
channels = list(CHANNEL_COMMAND = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_service
|
||||
name = "service radio encryption key"
|
||||
@@ -162,7 +184,7 @@
|
||||
|
||||
/obj/item/device/encryptionkey/ert
|
||||
name = "\improper ERT radio encryption key"
|
||||
channels = list(CHANNEL_RESPONSE_TEAM = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE)
|
||||
channels = list(CHANNEL_RESPONSE_TEAM = TRUE, CHANNEL_SCIENCE = TRUE, CHANNEL_COMMAND = TRUE, CHANNEL_MEDICAL = TRUE, CHANNEL_ENGINEERING = TRUE, CHANNEL_SECURITY = TRUE, CHANNEL_SUPPLY = TRUE, CHANNEL_SERVICE = TRUE, CHANNEL_HAILING = TRUE)
|
||||
|
||||
/obj/item/device/encryptionkey/onlyert
|
||||
name = "\improper ERT radio encryption key"
|
||||
|
||||
@@ -29,13 +29,27 @@
|
||||
keyslot1 = new ks1type(src)
|
||||
if(ks2type)
|
||||
keyslot2 = new ks2type(src)
|
||||
set_listening(TRUE)
|
||||
recalculateChannels(TRUE)
|
||||
possibly_deactivate_in_loc()
|
||||
moved_event.register(src, src, /obj/item/device/radio/headset/proc/possibly_deactivate_in_loc)
|
||||
|
||||
/obj/item/device/radio/headset/proc/possibly_deactivate_in_loc()
|
||||
if(ismob(loc))
|
||||
set_listening(should_be_listening)
|
||||
else
|
||||
set_listening(FALSE, actual_setting = FALSE)
|
||||
|
||||
/obj/item/device/radio/headset/Destroy()
|
||||
QDEL_NULL(keyslot1)
|
||||
QDEL_NULL(keyslot2)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/headset/set_listening(new_listening, actual_setting = TRUE)
|
||||
. = ..()
|
||||
if(listening && on)
|
||||
recalculateChannels()
|
||||
|
||||
/obj/item/device/radio/headset/list_channels(var/mob/user)
|
||||
return list_secure_channels()
|
||||
|
||||
@@ -64,16 +78,16 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/headset/receive_range(freq, level, aiOverride = 0)
|
||||
/obj/item/device/radio/headset/can_receive(input_frequency, level, aiOverride = FALSE)
|
||||
if (aiOverride)
|
||||
return ..(freq, level)
|
||||
return ..(input_frequency, level)
|
||||
if(ishuman(src.loc))
|
||||
var/mob/living/carbon/human/H = src.loc
|
||||
if(H.l_ear == src || H.r_ear == src)
|
||||
return ..(freq, level)
|
||||
return ..(input_frequency, level)
|
||||
if(!EarSound)
|
||||
return ..(freq, level)
|
||||
return -1
|
||||
return ..(input_frequency, level)
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/radio/headset/attack_hand(mob/user)
|
||||
if(ishuman(user))
|
||||
@@ -127,10 +141,12 @@
|
||||
|
||||
|
||||
/obj/item/device/radio/headset/proc/recalculateChannels(var/setDescription = FALSE)
|
||||
src.channels = list()
|
||||
src.translate_binary = FALSE
|
||||
src.translate_hivenet = FALSE
|
||||
src.syndie = FALSE
|
||||
channels = list()
|
||||
translate_binary = FALSE
|
||||
translate_hivenet = FALSE
|
||||
syndie = FALSE
|
||||
|
||||
SSradio.remove_object_all(src)
|
||||
|
||||
for(var/keyslot in list(keyslot1, keyslot2))
|
||||
if(!keyslot)
|
||||
@@ -138,31 +154,28 @@
|
||||
var/obj/item/device/encryptionkey/K = keyslot
|
||||
|
||||
for(var/ch_name in K.channels)
|
||||
if(ch_name in src.channels)
|
||||
if(ch_name in channels)
|
||||
continue
|
||||
src.channels[ch_name] = K.channels[ch_name]
|
||||
LAZYSET(channels, ch_name, K.channels[ch_name])
|
||||
|
||||
for(var/ch_name in K.additional_channels)
|
||||
if(ch_name in src.channels)
|
||||
if(ch_name in channels)
|
||||
continue
|
||||
src.channels[ch_name] = K.additional_channels[ch_name]
|
||||
LAZYSET(channels, ch_name, K.additional_channels[ch_name])
|
||||
|
||||
if(K.translate_binary)
|
||||
src.translate_binary = TRUE
|
||||
translate_binary = TRUE
|
||||
|
||||
if(K.translate_hivenet)
|
||||
src.translate_hivenet = TRUE
|
||||
translate_hivenet = TRUE
|
||||
|
||||
if(K.syndie)
|
||||
src.syndie = TRUE
|
||||
syndie = TRUE
|
||||
|
||||
if(K.independent)
|
||||
independent = TRUE
|
||||
|
||||
for (var/ch_name in channels)
|
||||
if(!SSradio)
|
||||
sleep(30) // Waiting for the SSradio to be created.
|
||||
if(!SSradio)
|
||||
src.name = "broken radio headset"
|
||||
return
|
||||
|
||||
secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
|
||||
|
||||
if(setDescription)
|
||||
@@ -638,7 +651,7 @@
|
||||
name = "military headset"
|
||||
icon_state = "syn_headset"
|
||||
origin_tech = list(TECH_ILLEGAL = 3)
|
||||
syndie = 1
|
||||
syndie = TRUE
|
||||
ks1type = /obj/item/device/encryptionkey/syndicate
|
||||
|
||||
/obj/item/device/radio/headset/syndicate/alt
|
||||
@@ -662,6 +675,7 @@
|
||||
icon_state = "syn_headset"
|
||||
origin_tech = list(TECH_ILLEGAL = 3)
|
||||
syndie = TRUE
|
||||
independent = TRUE
|
||||
ks1type = /obj/item/device/encryptionkey/ninja
|
||||
|
||||
/obj/item/device/radio/headset/bluespace
|
||||
@@ -670,12 +684,34 @@
|
||||
icon_state = "bs_headset"
|
||||
item_state = "com_headset" // laziness or genius, you decide
|
||||
syndie = TRUE
|
||||
independent = TRUE
|
||||
ks1type = /obj/item/device/encryptionkey/bluespace
|
||||
|
||||
//Ghostrole headset
|
||||
/obj/item/device/radio/headset/ship
|
||||
icon_state = "syn_headset"
|
||||
ks1type = /obj/item/device/encryptionkey/ship
|
||||
var/use_common = FALSE
|
||||
|
||||
/obj/item/device/radio/headset/ship/Initialize()
|
||||
if(!current_map.use_overmap)
|
||||
return ..()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/overmap/visitable/V = map_sectors["[T.z]"]
|
||||
if(istype(V) && V.comms_support)
|
||||
default_frequency = assign_away_freq(V.name)
|
||||
if(V.comms_name)
|
||||
name = "[V.comms_name] radio headset"
|
||||
|
||||
. = ..()
|
||||
|
||||
if (use_common)
|
||||
set_frequency(PUB_FREQ)
|
||||
|
||||
/obj/item/device/radio/headset/ship/common
|
||||
use_common = TRUE
|
||||
ks1type = /obj/item/device/encryptionkey/ship/common
|
||||
|
||||
/obj/item/device/radio/headset/binary
|
||||
origin_tech = list(TECH_ILLEGAL = 3)
|
||||
@@ -724,10 +760,8 @@
|
||||
var/myAi = null // Atlantis: Reference back to the AI which has this radio.
|
||||
var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via intellicard menu.
|
||||
|
||||
/obj/item/device/radio/headset/heads/ai_integrated/receive_range(freq, level)
|
||||
if (disabledAi)
|
||||
return -1 //Transciever Disabled.
|
||||
return ..(freq, level, 1)
|
||||
/obj/item/device/radio/headset/heads/ai_integrated/can_receive(input_frequency, level)
|
||||
return ..(input_frequency, level, !disabledAi)
|
||||
|
||||
/obj/item/device/radio/headset/heads/ai_integrated/Destroy()
|
||||
myAi = null
|
||||
|
||||
@@ -16,45 +16,112 @@
|
||||
var/radio_sound = null
|
||||
clickvol = 40
|
||||
|
||||
/obj/item/device/radio/intercom/ship
|
||||
channels = list()
|
||||
var/default_hailing = FALSE
|
||||
|
||||
/obj/item/device/radio/intercom/ship/Initialize()
|
||||
if(!current_map.use_overmap)
|
||||
return ..()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/overmap/visitable/V = map_sectors["[T.z]"]
|
||||
if(istype(V) && V.comms_support)
|
||||
if(V.comms_name)
|
||||
name = "intercom ([V.comms_name])"
|
||||
default_frequency = assign_away_freq(V.name)
|
||||
channels += list(
|
||||
V.name = TRUE,
|
||||
CHANNEL_HAILING = TRUE
|
||||
)
|
||||
|
||||
. = ..()
|
||||
|
||||
if (default_hailing)
|
||||
set_frequency(HAIL_FREQ)
|
||||
|
||||
/obj/item/device/radio/intercom/ship/hailing
|
||||
default_hailing = TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/custom
|
||||
name = "intercom (custom)"
|
||||
broadcasting = FALSE
|
||||
listening = FALSE
|
||||
|
||||
/obj/item/device/radio/intercom/custom/Initialize()
|
||||
. = ..()
|
||||
set_broadcasting(FALSE)
|
||||
set_listening(FALSE)
|
||||
|
||||
/obj/item/device/radio/intercom/hailing
|
||||
name = "intercom (hailing)"
|
||||
|
||||
/obj/item/device/radio/intercom/hailing/Initialize()
|
||||
. = ..()
|
||||
set_frequency(HAIL_FREQ)
|
||||
|
||||
/obj/item/device/radio/intercom/interrogation
|
||||
name = "intercom (interrogation)"
|
||||
frequency = 1449
|
||||
|
||||
/obj/item/device/radio/intercom/interrogation/broadcasting // The detainee's side.
|
||||
broadcasting = TRUE
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/intercom/interrogation/Initialize()
|
||||
. = ..()
|
||||
set_frequency(1449)
|
||||
|
||||
/obj/item/device/radio/intercom/interrogation/broadcasting/Initialize() // The detainee's side.
|
||||
set_broadcasting(TRUE)
|
||||
set_listening(FALSE)
|
||||
|
||||
/obj/item/device/radio/intercom/private
|
||||
name = "intercom (private)"
|
||||
frequency = AI_FREQ
|
||||
|
||||
/obj/item/device/radio/intercom/private/Initialize()
|
||||
. = ..()
|
||||
set_frequency(AI_FREQ)
|
||||
|
||||
/obj/item/device/radio/intercom/specops
|
||||
name = "intercom (spec ops)"
|
||||
frequency = ERT_FREQ
|
||||
|
||||
/obj/item/device/radio/intercom/specops/Initialize()
|
||||
. = ..()
|
||||
set_frequency(ERT_FREQ)
|
||||
|
||||
/obj/item/device/radio/intercom/department
|
||||
canhear_range = 5
|
||||
broadcasting = FALSE
|
||||
listening = TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/department/Initialize()
|
||||
. = ..()
|
||||
set_broadcasting(FALSE)
|
||||
set_listening(TRUE)
|
||||
|
||||
/obj/item/device/radio/intercom/department/medbay
|
||||
name = "intercom (medical)"
|
||||
frequency = MED_I_FREQ
|
||||
|
||||
/obj/item/device/radio/intercom/department/medbay/Initialize()
|
||||
. = ..()
|
||||
set_frequency(MED_I_FREQ)
|
||||
internal_channels = default_medbay_channels.Copy()
|
||||
|
||||
/obj/item/device/radio/intercom/department/security
|
||||
name = "intercom (security)"
|
||||
frequency = SEC_I_FREQ
|
||||
|
||||
/obj/item/device/radio/intercom/department/security/Initialize()
|
||||
. = ..()
|
||||
set_frequency(SEC_I_FREQ)
|
||||
internal_channels = list(
|
||||
num2text(PUB_FREQ) = list(),
|
||||
num2text(SEC_I_FREQ) = list(access_security)
|
||||
)
|
||||
|
||||
/obj/item/device/radio/intercom/entertainment
|
||||
name = "intercom (entertainment)"
|
||||
frequency = ENT_FREQ
|
||||
canhear_range = 4
|
||||
|
||||
/obj/item/device/radio/intercom/entertainment/Initialize()
|
||||
. = ..()
|
||||
set_frequency(ENT_FREQ)
|
||||
internal_channels = list(
|
||||
num2text(PUB_FREQ) = list(),
|
||||
num2text(ENT_FREQ) = list()
|
||||
)
|
||||
|
||||
/obj/item/device/radio/intercom/Initialize()
|
||||
. = ..()
|
||||
power_interface = new(loc, src)
|
||||
@@ -70,44 +137,26 @@
|
||||
screen_overlays["intercom_b"] = make_screen_overlay(icon, "intercom_b")
|
||||
screen_overlays["intercom_l"] = make_screen_overlay(icon, "intercom_l")
|
||||
|
||||
/obj/item/device/radio/intercom/department/medbay/Initialize()
|
||||
. = ..()
|
||||
internal_channels = default_medbay_channels.Copy()
|
||||
|
||||
/obj/item/device/radio/intercom/department/security/Initialize()
|
||||
. = ..()
|
||||
internal_channels = list(
|
||||
num2text(PUB_FREQ) = list(),
|
||||
num2text(SEC_I_FREQ) = list(access_security)
|
||||
)
|
||||
|
||||
/obj/item/device/radio/intercom/entertainment/Initialize()
|
||||
. = ..()
|
||||
internal_channels = list(
|
||||
num2text(PUB_FREQ) = list(),
|
||||
num2text(ENT_FREQ) = list()
|
||||
)
|
||||
|
||||
/obj/item/device/radio/intercom/syndicate
|
||||
name = "illegally modified intercom"
|
||||
desc = "Talk through this. Evilly."
|
||||
frequency = SYND_FREQ
|
||||
subspace_transmission = 1
|
||||
syndie = 1
|
||||
subspace_transmission = TRUE
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/syndicate/Initialize()
|
||||
. = ..()
|
||||
set_frequency(SYND_FREQ)
|
||||
internal_channels[num2text(SYND_FREQ)] = list(access_syndicate)
|
||||
|
||||
/obj/item/device/radio/intercom/raider
|
||||
name = "illegally modified intercom"
|
||||
desc = "Pirate radio, but not in the usual sense of the word."
|
||||
frequency = RAID_FREQ
|
||||
subspace_transmission = 1
|
||||
syndie = 1
|
||||
subspace_transmission = TRUE
|
||||
syndie = TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/syndicate/Initialize()
|
||||
. = ..()
|
||||
set_frequency(RAID_FREQ)
|
||||
internal_channels[num2text(RAID_FREQ)] = list(access_syndicate)
|
||||
|
||||
/obj/item/device/radio/intercom/Destroy()
|
||||
@@ -124,27 +173,19 @@
|
||||
src.add_fingerprint(user)
|
||||
INVOKE_ASYNC(src, /obj/item/.proc/attack_self, user)
|
||||
|
||||
/obj/item/device/radio/intercom/receive_range(freq, level)
|
||||
if (!on)
|
||||
return -1
|
||||
if(!(0 in level))
|
||||
/obj/item/device/radio/intercom/can_receive(input_frequency, list/levels)
|
||||
if(levels != RADIO_NO_Z_LEVEL_RESTRICTION)
|
||||
var/turf/position = get_turf(src)
|
||||
if(isnull(position) || !(position.z in level))
|
||||
return -1
|
||||
if (!src.listening)
|
||||
return -1
|
||||
if(freq in ANTAG_FREQS)
|
||||
if(!(src.syndie))
|
||||
return -1//Prevents broadcast of messages over devices lacking the encryption
|
||||
if(!istype(position) || !(position.z in levels))
|
||||
return FALSE
|
||||
|
||||
return canhear_range
|
||||
if(input_frequency in ANTAG_FREQS && !syndie)
|
||||
return FALSE//Prevents broadcast of messages over devices lacking the encryption
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/proc/power_change(has_power)
|
||||
if (!src.loc)
|
||||
on = 0
|
||||
else
|
||||
on = has_power
|
||||
|
||||
set_on(has_power) // has_power is given by our listener machinery
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/radio/intercom/forceMove(atom/dest)
|
||||
@@ -166,8 +207,8 @@
|
||||
if(listening)
|
||||
add_overlay(screen_overlays["intercom_l"])
|
||||
|
||||
/obj/item/device/radio/intercom/broadcasting
|
||||
broadcasting = TRUE
|
||||
/obj/item/device/radio/intercom/broadcasting/Initialize()
|
||||
set_broadcasting(TRUE)
|
||||
|
||||
/obj/item/device/radio/intercom/locked
|
||||
var/locked_frequency
|
||||
@@ -181,10 +222,16 @@
|
||||
|
||||
/obj/item/device/radio/intercom/locked/ai_private
|
||||
name = "intercom (AI private)"
|
||||
frequency = AI_FREQ
|
||||
broadcasting = TRUE
|
||||
listening = TRUE
|
||||
|
||||
/obj/item/device/radio/intercom/locked/ai_private/Initialize()
|
||||
. = ..()
|
||||
set_frequency(AI_FREQ)
|
||||
set_broadcasting(TRUE)
|
||||
set_listening(TRUE)
|
||||
|
||||
/obj/item/device/radio/intercom/locked/confessional
|
||||
name = "intercom (confessional)"
|
||||
frequency = 1480
|
||||
|
||||
/obj/item/device/radio/intercom/locked/confessional/Initialize()
|
||||
. = ..()
|
||||
set_frequency(1480)
|
||||
|
||||
@@ -34,19 +34,6 @@ var/global/list/default_medbay_channels = list(
|
||||
suffix = "\[3\]"
|
||||
icon_state = "walkietalkie"
|
||||
item_state = "radio"
|
||||
var/on = 1 // 0 for off
|
||||
var/last_transmission
|
||||
var/frequency = PUB_FREQ //common chat
|
||||
var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies
|
||||
var/canhear_range = 3 // the range which mobs can hear this radio from
|
||||
var/mob/living/announcer/announcer = null // used in autosay, held by the radio for re-use
|
||||
var/datum/wires/radio/wires = null
|
||||
var/b_stat = 0
|
||||
var/broadcasting = FALSE
|
||||
var/listening = TRUE
|
||||
var/list/channels = list() //see communications.dm for full list. First non-common, non-entertainment channel is a "default" for :h
|
||||
var/subspace_transmission = 0
|
||||
var/syndie = 0//Holder to see if it's a syndicate encrypted radio
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
throw_speed = 2
|
||||
@@ -61,39 +48,131 @@ var/global/list/default_medbay_channels = list(
|
||||
var/obj/item/cell/cell = /obj/item/cell/device
|
||||
var/last_radio_sound = -INFINITY
|
||||
|
||||
/obj/item/device/radio
|
||||
var/datum/radio_frequency/radio_connection
|
||||
var/list/datum/radio_frequency/secure_radio_connections = new
|
||||
// If FALSE, broadcasting and listening don't matter and this radio does nothing
|
||||
VAR_PRIVATE/on = TRUE
|
||||
|
||||
proc/set_frequency(new_frequency)
|
||||
VAR_PRIVATE/frequency = PUB_FREQ // Current frequency the radio is set to
|
||||
var/default_frequency = PUB_FREQ // frequency the radio defaults to on reset / startup
|
||||
|
||||
// Whether the radio transmits dialogue it hears nearby onto its radio channel
|
||||
VAR_PRIVATE/broadcasting = FALSE
|
||||
// Whether the radio is currently receiving radio messages from its frequencies
|
||||
VAR_PRIVATE/listening = TRUE
|
||||
|
||||
//the below vars are used to track listening and broadcasting should they be forced off for whatever reason but "supposed" to be active
|
||||
//eg player sets the radio to listening, but an emp or whatever turns it off, its still supposed to be activated but was forced off,
|
||||
//when it wears off it sets listening to should_be_listening
|
||||
|
||||
///used for tracking what broadcasting should be in the absence of things forcing it off, eg its set to broadcast but gets emp'd temporarily
|
||||
var/should_be_broadcasting = FALSE
|
||||
///used for tracking what listening should be in the absence of things forcing it off, eg its set to listen but gets emp'd temporarily
|
||||
var/should_be_listening = TRUE
|
||||
|
||||
/// Both the range around the radio in which mobs can hear what it receives and the range the radio can hear
|
||||
var/canhear_range = 3
|
||||
|
||||
var/last_transmission
|
||||
var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies
|
||||
var/mob/living/announcer/announcer = null // used in autosay, held by the radio for re-use
|
||||
var/datum/wires/radio/wires = null
|
||||
var/b_stat = 0
|
||||
|
||||
var/list/channels = list() //see communications.dm for full list. First non-common, non-entertainment channel is a "default" for :h
|
||||
var/subspace_transmission = FALSE
|
||||
var/syndie = FALSE //Holder to see if it's a syndicate encrypted radio
|
||||
var/independent = FALSE // if TRUE, can say/hear on the Special Channel!!! (TBD)
|
||||
|
||||
var/datum/radio_frequency/radio_connection
|
||||
var/list/datum/radio_frequency/secure_radio_connections = list()
|
||||
|
||||
/obj/item/device/radio/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT)
|
||||
|
||||
/obj/item/device/radio/Destroy()
|
||||
listening_objects -= src
|
||||
QDEL_NULL(announcer)
|
||||
QDEL_NULL(wires)
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src, frequency)
|
||||
for (var/ch_name in channels)
|
||||
SSradio.remove_object(src, radiochannels[ch_name])
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/Initialize()
|
||||
. = ..()
|
||||
|
||||
wires = new(src)
|
||||
internal_channels = default_internal_channels.Copy()
|
||||
listening_objects += src
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
|
||||
if(frequency < RADIO_LOW_FREQ || frequency > RADIO_HIGH_FREQ)
|
||||
frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ)
|
||||
set_frequency(frequency)
|
||||
|
||||
for (var/ch_name in channels)
|
||||
secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
|
||||
|
||||
set_listening(listening)
|
||||
set_broadcasting(broadcasting)
|
||||
set_frequency(default_frequency)
|
||||
set_on(on)
|
||||
|
||||
/obj/item/device/radio/Destroy()
|
||||
SSradio.remove_object_all(src)
|
||||
QDEL_NULL(announcer)
|
||||
QDEL_NULL(wires)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/proc/is_on()
|
||||
return on
|
||||
|
||||
/obj/item/device/radio/proc/get_frequency()
|
||||
return frequency
|
||||
|
||||
/obj/item/device/radio/proc/get_broadcasting()
|
||||
return broadcasting
|
||||
|
||||
/obj/item/device/radio/proc/get_listening()
|
||||
return listening
|
||||
|
||||
/**
|
||||
* setter for the listener var, adds or removes this radio from the global radio list if we are also on
|
||||
*
|
||||
* * new_listening - the new value we want to set listening to
|
||||
* * actual_setting - whether or not the radio is supposed to be listening, sets should_be_listening to the new listening value if true, otherwise just changes listening
|
||||
*/
|
||||
/obj/item/device/radio/proc/set_listening(new_listening, actual_setting = TRUE)
|
||||
|
||||
listening = new_listening
|
||||
if(actual_setting)
|
||||
should_be_listening = listening
|
||||
|
||||
if(listening && on)
|
||||
SSradio.add_object(src, frequency, RADIO_CHAT)
|
||||
else if(!listening)
|
||||
SSradio.remove_object_all(src)
|
||||
|
||||
/**
|
||||
* setter for broadcasting that makes us not hearing sensitive if not broadcasting and hearing sensitive if broadcasting
|
||||
* hearing sensitive in this case only matters for the purposes of listening for words said in nearby tiles, talking into us directly bypasses hearing
|
||||
*
|
||||
* * new_broadcasting- the new value we want to set broadcasting to
|
||||
* * actual_setting - whether or not the radio is supposed to be broadcasting, sets should_be_broadcasting to the new value if true, otherwise just changes broadcasting
|
||||
*/
|
||||
/obj/item/device/radio/proc/set_broadcasting(new_broadcasting, actual_setting = TRUE)
|
||||
|
||||
broadcasting = new_broadcasting
|
||||
if(actual_setting)
|
||||
should_be_broadcasting = broadcasting
|
||||
|
||||
if(broadcasting && on) //we dont need hearing sensitivity if we arent broadcasting, because talk_into doesnt care about hearing
|
||||
become_hearing_sensitive(INNATE_TRAIT)
|
||||
else if(!broadcasting)
|
||||
lose_hearing_sensitivity(INNATE_TRAIT)
|
||||
|
||||
///setter for the on var that sets both broadcasting and listening to off or whatever they were supposed to be
|
||||
/obj/item/device/radio/proc/set_on(new_on)
|
||||
|
||||
on = new_on
|
||||
|
||||
if(on)
|
||||
set_broadcasting(should_be_broadcasting)//set them to whatever theyre supposed to be
|
||||
set_listening(should_be_listening)
|
||||
else
|
||||
set_broadcasting(FALSE, actual_setting = FALSE)//fake set them to off
|
||||
set_listening(FALSE, actual_setting = FALSE)
|
||||
|
||||
/obj/item/device/radio/attack_self(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
@@ -113,6 +192,7 @@ var/global/list/default_medbay_channels = list(
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["default_freq"] = format_frequency(default_frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
@@ -134,9 +214,15 @@ var/global/list/default_medbay_channels = list(
|
||||
|
||||
/obj/item/device/radio/proc/setupRadioDescription(var/additional_radio_desc)
|
||||
var/radio_text = ""
|
||||
var/found_first_department = FALSE
|
||||
for(var/i = 1 to channels.len)
|
||||
var/channel = channels[i]
|
||||
var/key = get_radio_key_from_channel(channel)
|
||||
if(!length(key) && !found_first_department && channel != CHANNEL_COMMON && channel != CHANNEL_ENTERTAINMENT)
|
||||
// if we don't have a key and it's the 'shortcut' channel, put the department key instead
|
||||
key = get_radio_key_from_channel("department")
|
||||
found_first_department = TRUE
|
||||
|
||||
radio_text += "[key] - [channel]"
|
||||
if(i != channels.len)
|
||||
radio_text += ", "
|
||||
@@ -196,12 +282,6 @@ var/global/list/default_medbay_channels = list(
|
||||
Speaker: <A href='byond://?src=\ref[src];ch_name=[chan_name];listen=[!list]'>[list ? "Engaged" : "Disengaged"]</A><BR>
|
||||
"}
|
||||
|
||||
/obj/item/device/radio/proc/ToggleBroadcast()
|
||||
broadcasting = !broadcasting && !(wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
/obj/item/device/radio/proc/ToggleReception()
|
||||
listening = !listening && !(wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL))
|
||||
|
||||
/obj/item/device/radio/CanUseTopic()
|
||||
if(!on)
|
||||
return STATUS_CLOSE
|
||||
@@ -214,7 +294,7 @@ var/global/list/default_medbay_channels = list(
|
||||
|
||||
/obj/item/device/radio/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
usr.set_machine(src)
|
||||
if (href_list["track"])
|
||||
@@ -222,7 +302,7 @@ var/global/list/default_medbay_channels = list(
|
||||
var/mob/living/silicon/ai/A = locate(href_list["track2"])
|
||||
if(A && target)
|
||||
A.ai_actual_track(target)
|
||||
. = 1
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["freq"])
|
||||
var/new_frequency = (frequency + text2num(href_list["freq"]))
|
||||
@@ -232,27 +312,32 @@ var/global/list/default_medbay_channels = list(
|
||||
if(hidden_uplink)
|
||||
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
|
||||
usr << browse(null, "window=radio")
|
||||
. = 1
|
||||
. = TRUE
|
||||
else if (href_list["talk"])
|
||||
ToggleBroadcast()
|
||||
. = 1
|
||||
set_broadcasting(!broadcasting)
|
||||
. = TRUE
|
||||
else if (href_list["listen"])
|
||||
var/chan_name = href_list["ch_name"]
|
||||
if (!chan_name)
|
||||
ToggleReception()
|
||||
set_listening(!listening)
|
||||
else
|
||||
if (channels[chan_name] & FREQ_LISTENING)
|
||||
channels[chan_name] &= ~FREQ_LISTENING
|
||||
else
|
||||
channels[chan_name] |= FREQ_LISTENING
|
||||
. = 1
|
||||
. = TRUE
|
||||
else if(href_list["spec_freq"])
|
||||
var freq = href_list["spec_freq"]
|
||||
if(has_channel_access(usr, freq))
|
||||
set_frequency(text2num(freq))
|
||||
. = 1
|
||||
. = TRUE
|
||||
else if(href_list["reset_freq"])
|
||||
if(default_frequency)
|
||||
set_frequency(default_frequency)
|
||||
. = TRUE
|
||||
|
||||
if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(.)
|
||||
SSnanoui.update_uis(src)
|
||||
@@ -277,16 +362,13 @@ var/global/list/default_medbay_channels = list(
|
||||
if (!istype(connection))
|
||||
return
|
||||
|
||||
if (!connection)
|
||||
return
|
||||
|
||||
if(!istype(announcer))
|
||||
announcer = new()
|
||||
|
||||
announcer.PrepareBroadcast(from)
|
||||
Broadcast_Message(connection, announcer,
|
||||
FALSE, "*garbled automated announcement*", src,
|
||||
message, from, "Automated Announcement", from, announcer.voice_name,
|
||||
4, 0, list(0), connection.frequency, "states", announcer.default_language)
|
||||
var/datum/weakref/speaker_weakref = WEAKREF(announcer)
|
||||
var/datum/signal/subspace/vocal/signal = new(src, frequency, speaker_weakref, announcer.default_language, message, "states")
|
||||
signal.send_to_receivers()
|
||||
announcer.ResetAfterBroadcast()
|
||||
|
||||
// Interprets the message mode when talking into a radio, possibly returning a connection datum
|
||||
@@ -311,12 +393,13 @@ var/global/list/default_medbay_channels = list(
|
||||
// If we were to send to a channel we don't have, drop it.
|
||||
return null
|
||||
|
||||
/obj/item/device/radio/talk_into(mob/living/M, message, channel, var/verb = "says", var/datum/language/speaking = null, var/ignore_restrained)
|
||||
/obj/item/device/radio/talk_into(mob/living/M, message, channel, var/say_verb = "says", var/datum/language/speaking = null, var/ignore_restrained)
|
||||
if(!on)
|
||||
return 0 // the device has to be on
|
||||
// Fix for permacell radios, but kinda eh about actually fixing them.
|
||||
return FALSE
|
||||
if(!M || !message)
|
||||
return 0
|
||||
return FALSE
|
||||
if(wires.IsIndexCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact
|
||||
return FALSE
|
||||
|
||||
if (iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
@@ -333,268 +416,85 @@ var/global/list/default_medbay_channels = list(
|
||||
return FALSE
|
||||
M.trigger_aiming(TARGET_CAN_RADIO)
|
||||
|
||||
// Uncommenting this. To the above comment:
|
||||
// The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom
|
||||
if(wires.IsIndexCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact
|
||||
return 0
|
||||
|
||||
if(!radio_connection)
|
||||
set_frequency(frequency)
|
||||
|
||||
if(loc == M)
|
||||
playsound(loc, 'sound/effects/walkietalkie.ogg', 5, 0, -1, required_asfx_toggles = ASFX_RADIO)
|
||||
|
||||
/* Quick introduction:
|
||||
This new radio system uses a very robust FTL signaling technology unoriginally
|
||||
dubbed "subspace" which is somewhat similar to 'blue-space' but can't
|
||||
actually transmit large mass. Headsets are the only radio devices capable
|
||||
of sending subspace transmissions to the Communications Satellite.
|
||||
|
||||
A headset sends a signal to a subspace listener/receiver elsewhere in space,
|
||||
the signal gets processed and logged, and an audible transmission gets sent
|
||||
to each individual headset.
|
||||
/*
|
||||
Roughly speaking, radios attempt to make a subspace transmission (which
|
||||
is received, processed, and rebroadcast by the telecomms satellite) and
|
||||
if that fails, they send a mundane radio transmission.
|
||||
Headsets cannot send/receive mundane transmissions, only subspace.
|
||||
Syndicate radios can hear transmissions on all well-known frequencies.
|
||||
CentCom radios can hear the CentCom frequency no matter what.
|
||||
*/
|
||||
|
||||
//#### Grab the connection datum ####//
|
||||
// Get the frequency
|
||||
var/datum/radio_frequency/connection = handle_message_mode(M, message, channel)
|
||||
if (!istype(connection))
|
||||
return 0
|
||||
if (!connection)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/turf/position = get_turf(src)
|
||||
// Determine the identify information attached to the signal
|
||||
var/datum/weakref/speaker_weakref = WEAKREF(M)
|
||||
var/datum/signal/subspace/vocal/signal = new(src, connection.frequency, speaker_weakref, speaking, message, say_verb)
|
||||
|
||||
var/obj/effect/overmap/visitable/sector
|
||||
if(current_map.use_overmap)
|
||||
var/my_sector = map_sectors["[position.z]"]
|
||||
if(istype(my_sector, /obj/effect/overmap/visitable))
|
||||
sector = my_sector
|
||||
|
||||
//#### Tagging the signal with all appropriate identity values ####//
|
||||
|
||||
// ||-- The mob's name identity --||
|
||||
var/displayname = M.name // grab the display name (name you get when you hover over someone's icon)
|
||||
var/real_name = M.real_name // mob's real name
|
||||
var/mobkey = "none" // player key associated with mob
|
||||
var/voicemask = 0 // the speaker is wearing a voice mask
|
||||
if(M.client)
|
||||
mobkey = M.key // assign the mob's key
|
||||
|
||||
|
||||
var/jobname // the mob's "job"
|
||||
|
||||
// --- Human: use their actual job ---
|
||||
if (ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
jobname = H.get_assignment()
|
||||
|
||||
// --- Carbon Nonhuman ---
|
||||
else if (iscarbon(M)) // Nonhuman carbon mob
|
||||
jobname = "No id"
|
||||
|
||||
// --- AI ---
|
||||
else if (isAI(M))
|
||||
jobname = "AI"
|
||||
|
||||
// --- Cyborg ---
|
||||
else if (isrobot(M))
|
||||
jobname = "Cyborg"
|
||||
|
||||
// --- Personal AI (pAI) ---
|
||||
else if (istype(M, /mob/living/silicon/pai))
|
||||
jobname = "Personal AI"
|
||||
|
||||
// --- Unidentifiable mob ---
|
||||
else
|
||||
jobname = "Unknown"
|
||||
|
||||
|
||||
// --- Modifications to the mob's identity ---
|
||||
|
||||
// The mob is disguising their identity:
|
||||
if (ishuman(M) && M.GetVoice() != real_name)
|
||||
displayname = M.GetVoice()
|
||||
jobname = "Unknown"
|
||||
voicemask = 1
|
||||
|
||||
|
||||
|
||||
/* ###### Radio headsets can only broadcast through subspace ###### */
|
||||
// All radios attempt to use the subspace system
|
||||
signal.send_to_receivers()
|
||||
|
||||
// If it's subspace only, that's all we can do
|
||||
if(subspace_transmission)
|
||||
// Check for jamming.
|
||||
if (within_jamming_range(src))
|
||||
return
|
||||
// First, we want to generate a new radio signal
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = TRANSMISSION_SUBSPACE
|
||||
|
||||
// --- Finally, tag the actual signal with the appropriate values ---
|
||||
signal.data = list(
|
||||
// Identity-associated tags:
|
||||
"mob" = M, // store a reference to the mob
|
||||
"mobtype" = M.type, // the mob's type
|
||||
"realname" = real_name, // the mob's real name
|
||||
"name" = displayname, // the mob's display name
|
||||
"job" = jobname, // the mob's job
|
||||
"key" = mobkey, // the mob's key
|
||||
"vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood
|
||||
"vname" = M.voice_name, // the name to display if the voice wasn't understood
|
||||
"vmask" = voicemask, // 1 if the mob is using a voice gas mask
|
||||
// Non-subspace radios will check in a couple of seconds, and if the signal was never received, we send a mundane broadcast
|
||||
addtimer(CALLBACK(src, .proc/backup_transmission, signal), 2 SECONDS)
|
||||
|
||||
// We store things that would otherwise be kept in the actual mob
|
||||
// so that they can be logged even AFTER the mob is deleted or something
|
||||
|
||||
// Other tags:
|
||||
"compression" = rand(45,50), // compressed radio signal
|
||||
"message" = message, // the actual sent message
|
||||
"connection" = connection, // the radio connection to use
|
||||
"radio" = src, // stores the radio used for transmission
|
||||
"slow" = 0, // how much to sleep() before broadcasting - simulates net lag
|
||||
"traffic" = 0, // dictates the total traffic sum that the signal went through
|
||||
"type" = 0, // determines what type of radio input it is: normal broadcast
|
||||
"server" = null, // the last server to log this signal
|
||||
"reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery
|
||||
"level" = position.z, // The source's z level
|
||||
"language" = speaking,
|
||||
"verb" = verb,
|
||||
"sector" = sector
|
||||
)
|
||||
signal.frequency = connection.frequency // Quick frequency set
|
||||
|
||||
//#### Sending the signal to all subspace receivers ####//
|
||||
|
||||
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
|
||||
INVOKE_ASYNC(R, /obj/proc/receive_signal, signal)
|
||||
|
||||
// Allinone can act as receivers.
|
||||
for(var/obj/machinery/telecomms/allinone/R in telecomms_list)
|
||||
INVOKE_ASYNC(R, /obj/proc/receive_signal, signal)
|
||||
|
||||
// Receiving code can be located in Telecommunications.dm
|
||||
var/position_z_in_level = FALSE // this particular band-aid is required to make antag radios say "talks into" and not "tries to talk into" when using a radio, due to how their signals are made
|
||||
if(islist(signal.data["level"]))
|
||||
if(position.z in signal.data["level"])
|
||||
position_z_in_level = TRUE
|
||||
else
|
||||
if(position.z == signal.data["level"])
|
||||
position_z_in_level = TRUE
|
||||
return signal.data["done"] && position_z_in_level
|
||||
|
||||
|
||||
/* ###### Intercoms and station-bounced radios ###### */
|
||||
|
||||
var/filter_type = 2
|
||||
|
||||
/* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */
|
||||
if(istype(src, /obj/item/device/radio/intercom))
|
||||
filter_type = 1
|
||||
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = TRANSMISSION_SUBSPACE
|
||||
|
||||
|
||||
/* --- Try to send a normal subspace broadcast first */
|
||||
|
||||
signal.data = list(
|
||||
|
||||
"mob" = M, // store a reference to the mob
|
||||
"mobtype" = M.type, // the mob's type
|
||||
"realname" = real_name, // the mob's real name
|
||||
"name" = displayname, // the mob's display name
|
||||
"job" = jobname, // the mob's job
|
||||
"key" = mobkey, // the mob's key
|
||||
"vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood
|
||||
"vname" = M.voice_name, // the name to display if the voice wasn't understood
|
||||
"vmask" = voicemask, // 1 if the mob is using a voice gas mas
|
||||
|
||||
"compression" = 0, // uncompressed radio signal
|
||||
"message" = message, // the actual sent message
|
||||
"connection" = connection, // the radio connection to use
|
||||
"radio" = src, // stores the radio used for transmission
|
||||
"slow" = 0,
|
||||
"traffic" = 0,
|
||||
"type" = 0,
|
||||
"server" = null,
|
||||
"reject" = 0,
|
||||
"level" = position.z,
|
||||
"language" = speaking,
|
||||
"verb" = verb,
|
||||
"sector" = sector
|
||||
)
|
||||
signal.frequency = connection.frequency // Quick frequency set
|
||||
|
||||
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
|
||||
INVOKE_ASYNC(R, /obj/proc/receive_signal, signal)
|
||||
|
||||
|
||||
sleep(rand(10,25)) // wait a little...
|
||||
|
||||
if(signal.data["done"] && (position.z in signal.data["level"]))
|
||||
// we're done here.
|
||||
return 1
|
||||
|
||||
// Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level.
|
||||
// Send a mundane broadcast with limited targets:
|
||||
|
||||
//THIS IS TEMPORARY. YEAH RIGHT
|
||||
if(!connection) return 0 //~Carn
|
||||
|
||||
return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote),
|
||||
src, message, displayname, jobname, real_name, M.voice_name,
|
||||
filter_type, signal.data["compression"], list(position.z), connection.frequency,verb,speaking)
|
||||
/obj/item/device/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal)
|
||||
var/turf/T = get_turf(src)
|
||||
if (signal.data["done"] && (T.z in signal.levels))
|
||||
return
|
||||
|
||||
// If we're here, the signal was never processed. Proceed with mundane broadcast:
|
||||
signal.data["compression"] = 0
|
||||
signal.transmission_method = TRANSMISSION_RADIO
|
||||
signal.levels = list(T.z)
|
||||
signal.broadcast()
|
||||
|
||||
/obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null)
|
||||
if (!broadcasting || get_dist(src, M) > canhear_range)
|
||||
return
|
||||
|
||||
if (broadcasting)
|
||||
if(get_dist(src, M) <= canhear_range)
|
||||
talk_into(M, msg, null, verb, speaking, ignore_restrained = TRUE)
|
||||
|
||||
/obj/item/device/radio/proc/receive_range(freq, level)
|
||||
// check if this radio can receive on the given frequency, and if so,
|
||||
// what the range is in which mobs will hear the radio
|
||||
// returns: -1 if can't receive, range otherwise
|
||||
|
||||
if (wires.IsIndexCut(WIRE_RECEIVE))
|
||||
return -1
|
||||
if(!listening)
|
||||
return -1
|
||||
if (within_jamming_range(src))
|
||||
return -1
|
||||
if(!(0 in level))
|
||||
/obj/item/device/radio/proc/can_receive(input_frequency, list/levels)
|
||||
// check if the radio can receive on the given frequency
|
||||
if (levels != RADIO_NO_Z_LEVEL_RESTRICTION)
|
||||
var/turf/position = get_turf(src)
|
||||
if(!position || !(position.z in level))
|
||||
return -1
|
||||
if(freq in ANTAG_FREQS)
|
||||
if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys
|
||||
return -1
|
||||
if (!on)
|
||||
return -1
|
||||
if (!freq) //received on main frequency
|
||||
if (!listening)
|
||||
return -1
|
||||
else
|
||||
var/accept = (freq==frequency && listening)
|
||||
if (!accept)
|
||||
if (!position || !(position.z in levels))
|
||||
return FALSE
|
||||
|
||||
if (within_jamming_range(src))
|
||||
return FALSE
|
||||
|
||||
if ((input_frequency in ANTAG_FREQS) && !syndie) //Checks to see if it's allowed on that frequency, based on the encryption keys
|
||||
return FALSE
|
||||
|
||||
if (input_frequency == frequency)
|
||||
return TRUE
|
||||
|
||||
for (var/ch_name in channels)
|
||||
var/datum/radio_frequency/RF = secure_radio_connections[ch_name]
|
||||
if (RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING))
|
||||
accept = 1
|
||||
break
|
||||
if (!accept)
|
||||
return -1
|
||||
return canhear_range
|
||||
if (RF.frequency == input_frequency && (channels[ch_name] & FREQ_LISTENING))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/radio/proc/send_hear(freq, level)
|
||||
if(!can_receive(freq, level))
|
||||
return
|
||||
|
||||
var/range = receive_range(freq, level)
|
||||
if(range > -1)
|
||||
var/list/mobs = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(get_turf(src), canhear_range, mobs, objs)
|
||||
return mobs
|
||||
return get_hearers_in_view(canhear_range, src)
|
||||
|
||||
|
||||
/obj/item/device/radio/examine(mob/user)
|
||||
@@ -624,8 +524,8 @@ var/global/list/default_medbay_channels = list(
|
||||
else return
|
||||
|
||||
/obj/item/device/radio/emp_act(severity)
|
||||
broadcasting = FALSE
|
||||
listening = FALSE
|
||||
set_broadcasting(FALSE)
|
||||
set_listening(FALSE)
|
||||
for (var/ch_name in channels)
|
||||
channels[ch_name] = 0
|
||||
..()
|
||||
@@ -719,6 +619,9 @@ var/global/list/default_medbay_channels = list(
|
||||
if(keyslot.syndie)
|
||||
syndie = TRUE
|
||||
|
||||
if(keyslot.independent)
|
||||
independent = TRUE
|
||||
|
||||
for(var/ch_name in src.channels)
|
||||
if(!SSradio)
|
||||
sleep(30) // Waiting for the SSradio to be created.
|
||||
@@ -774,6 +677,7 @@ var/global/list/default_medbay_channels = list(
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["default_freq"] = format_frequency(default_frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
var/list/chanlist = list_channels(user)
|
||||
@@ -799,7 +703,7 @@ var/global/list/default_medbay_channels = list(
|
||||
if(SSradio)
|
||||
for (var/ch_name in channels)
|
||||
SSradio.remove_object(src, radiochannels[ch_name])
|
||||
secure_radio_connections = new
|
||||
secure_radio_connections = list()
|
||||
channels = op
|
||||
if(SSradio)
|
||||
for (var/ch_name in op)
|
||||
@@ -810,57 +714,83 @@ var/global/list/default_medbay_channels = list(
|
||||
// Radio Variants
|
||||
//
|
||||
|
||||
/obj/item/device/radio/map_preset
|
||||
channels = list()
|
||||
|
||||
/obj/item/device/radio/map_preset/Initialize()
|
||||
if(!current_map.use_overmap)
|
||||
return ..()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/overmap/visitable/V = map_sectors["[T.z]"]
|
||||
if(istype(V) && V.comms_support)
|
||||
frequency = assign_away_freq(V.name)
|
||||
channels += list(
|
||||
V.name = TRUE,
|
||||
CHANNEL_HAILING = TRUE
|
||||
)
|
||||
if(V.comms_name)
|
||||
name = "[V.comms_name] shortwave radio"
|
||||
|
||||
return ..()
|
||||
|
||||
// Radio (Off)
|
||||
/obj/item/device/radio/off
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/off/Initialize()
|
||||
. = ..()
|
||||
set_listening(FALSE)
|
||||
|
||||
// Medical
|
||||
/obj/item/device/radio/med
|
||||
icon_state = "walkietalkie-med"
|
||||
|
||||
// Medical (Off)
|
||||
/obj/item/device/radio/med/off
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/med/off/Initialize()
|
||||
. = ..()
|
||||
set_listening(FALSE)
|
||||
|
||||
// Security
|
||||
/obj/item/device/radio/sec
|
||||
icon_state = "walkietalkie-sec"
|
||||
|
||||
// Security (Off)
|
||||
/obj/item/device/radio/sec/off
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/sec/off/Initialize()
|
||||
. = ..()
|
||||
set_listening(FALSE)
|
||||
|
||||
// Engineering
|
||||
/obj/item/device/radio/eng
|
||||
icon_state = "walkietalkie-eng"
|
||||
|
||||
// Engineering (Off)
|
||||
/obj/item/device/radio/eng/off
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/eng/off/Initialize()
|
||||
. = ..()
|
||||
set_listening(FALSE)
|
||||
|
||||
// Science
|
||||
/obj/item/device/radio/sci
|
||||
icon_state = "walkietalkie-sci"
|
||||
|
||||
// Science (Off)
|
||||
/obj/item/device/radio/sci/off
|
||||
listening = FALSE
|
||||
/obj/item/device/radio/sci/off/Initialize()
|
||||
. = ..()
|
||||
set_listening(FALSE)
|
||||
|
||||
// Phone
|
||||
/obj/item/device/radio/phone
|
||||
broadcasting = FALSE
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon_state = "red_phone"
|
||||
listening = TRUE
|
||||
name = "phone"
|
||||
var/radio_sound = null
|
||||
|
||||
// Medical Phone
|
||||
/obj/item/device/radio/phone/medbay
|
||||
frequency = MED_I_FREQ
|
||||
/obj/item/device/radio/phone/Initialize()
|
||||
. = ..()
|
||||
set_broadcasting(FALSE)
|
||||
set_listening(TRUE)
|
||||
|
||||
// Medical Phone
|
||||
/obj/item/device/radio/phone/medbay/Initialize()
|
||||
. = ..()
|
||||
set_frequency(MED_I_FREQ)
|
||||
internal_channels = default_medbay_channels.Copy()
|
||||
|
||||
// All-channel Radio
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
..()
|
||||
radio = new(src)
|
||||
camera = new(src)
|
||||
listening_objects += src
|
||||
|
||||
/obj/item/device/spy_bug/Destroy()
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
|
||||
/obj/item/device/spy_bug/examine(mob/user)
|
||||
. = ..(user, 0)
|
||||
@@ -36,8 +32,8 @@
|
||||
to_chat(user, "Needs to be both configured and brought in contact with monitor device to be fully functional.")
|
||||
|
||||
/obj/item/device/spy_bug/attack_self(mob/user)
|
||||
radio.broadcasting = !radio.broadcasting
|
||||
to_chat(user, "\The [src]'s radio is [radio.broadcasting ? "broadcasting" : "not broadcasting"] now. The current frequency is [radio.frequency].")
|
||||
radio.set_broadcasting(!radio.get_broadcasting())
|
||||
to_chat(user, "\The [src]'s radio is [radio.get_broadcasting() ? "broadcasting" : "not broadcasting"] now. The current frequency is [radio.get_frequency()].")
|
||||
radio.attack_self(user)
|
||||
|
||||
/obj/item/device/spy_bug/attackby(obj/W as obj, mob/living/user as mob)
|
||||
@@ -70,11 +66,7 @@
|
||||
|
||||
/obj/item/device/spy_monitor/New()
|
||||
radio = new(src)
|
||||
listening_objects += src
|
||||
|
||||
/obj/item/device/spy_monitor/Destroy()
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
|
||||
/obj/item/device/spy_monitor/examine(mob/user)
|
||||
. = ..(user, 1)
|
||||
@@ -161,9 +153,12 @@
|
||||
return 0
|
||||
|
||||
/obj/item/device/radio/spy
|
||||
listening = FALSE
|
||||
frequency = 1473
|
||||
broadcasting = FALSE
|
||||
canhear_range = 7
|
||||
name = "spy device"
|
||||
icon_state = "syn_cypherkey"
|
||||
|
||||
/obj/item/device/radio/spy/Initialize()
|
||||
. = ..()
|
||||
set_broadcasting(FALSE)
|
||||
set_listening(FALSE)
|
||||
set_frequency(1473)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
/obj/item/device/taperecorder/Initialize()
|
||||
. = ..()
|
||||
listening_objects += src
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
portable_drive = new /obj/item/computer_hardware/hard_drive/portable(src)
|
||||
|
||||
/obj/item/device/taperecorder/Destroy()
|
||||
|
||||
@@ -24,15 +24,6 @@
|
||||
"/obj/item/stack/cable_coil" = 2,
|
||||
"/obj/item/stock_parts/subspace/filter" = 2)
|
||||
|
||||
/obj/item/circuitboard/telecomms/relay
|
||||
name = T_BOARD("relay mainframe")
|
||||
build_path = /obj/machinery/telecomms/relay
|
||||
origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 4, TECH_BLUESPACE = 3)
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/manipulator" = 2,
|
||||
"/obj/item/stack/cable_coil" = 2,
|
||||
"/obj/item/stock_parts/subspace/filter" = 2)
|
||||
|
||||
/obj/item/circuitboard/telecomms/bus
|
||||
name = T_BOARD("bus mainframe")
|
||||
build_path = /obj/machinery/telecomms/bus
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
|
||||
/obj/item/grenade/flashbang/prime()
|
||||
..()
|
||||
for(var/obj/structure/closet/L in hear(7, get_turf(src)))
|
||||
for(var/obj/structure/closet/L in get_hear(7, get_turf(src)))
|
||||
if(locate(/mob/living/carbon/, L))
|
||||
for(var/mob/living/carbon/M in L)
|
||||
bang(get_turf(src), M)
|
||||
|
||||
for(var/mob/living/carbon/M in hear(7, get_turf(src)))
|
||||
for(var/mob/living/carbon/M in get_hear(7, get_turf(src)))
|
||||
bang(get_turf(src), M)
|
||||
|
||||
for(var/obj/effect/blob/B in hear(8,get_turf(src))) //Blob damage here
|
||||
for(var/obj/effect/blob/B in get_hear(8,get_turf(src))) //Blob damage here
|
||||
var/damage = round(30/(get_dist(B,get_turf(src))+1))
|
||||
B.health -= damage
|
||||
B.update_icon()
|
||||
|
||||
@@ -289,10 +289,9 @@ Implant Specifics:<BR>"}
|
||||
|
||||
/obj/item/implant/explosive/New()
|
||||
..()
|
||||
listening_objects += src
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
|
||||
/obj/item/implant/explosive/Destroy()
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/implant/explosive/full
|
||||
|
||||
@@ -77,7 +77,7 @@ Frequency:
|
||||
src.temp += "<B>Located Beacons:</B><BR>"
|
||||
|
||||
for(var/obj/item/device/radio/beacon/W in teleportbeacons)
|
||||
if (W.frequency == src.frequency)
|
||||
if (W.get_frequency() == src.frequency)
|
||||
var/turf/tr = get_turf(W)
|
||||
if (tr.z == sr.z && tr)
|
||||
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
being_shocked = 0
|
||||
|
||||
|
||||
/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
/obj/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
return
|
||||
|
||||
//To be called from things that spill objects on the floor.
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
icon_state = "morgue0"
|
||||
else
|
||||
icon_state = "morgue1"
|
||||
var/list/searching = GetAllContents(searchDepth = 3, checkClient = 0) // Search inside bodybags as well.
|
||||
var/list/searching = get_all_contents_of_type(/mob/living) // Search inside bodybags as well.
|
||||
for(var/mob/living/M in searching)
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
@@ -252,7 +252,7 @@
|
||||
update_icon()
|
||||
var/desperation = 0
|
||||
|
||||
var/list/searching = GetAllContents(searchDepth = 3, checkClient = 0)
|
||||
var/list/searching = get_all_contents_of_type(/mob/living)
|
||||
for(var/mob/living/M in searching)
|
||||
admin_attack_log(A, M, "Began cremating their victim.", "Has begun being cremated.", "began cremating")
|
||||
if(iscarbon(M))
|
||||
|
||||
@@ -120,13 +120,10 @@
|
||||
M.playsound_to(source_turf, S, use_random_freq = use_random_freq, use_pressure = use_pressure, modify_environment = modify_environment)
|
||||
|
||||
/proc/playsound_lineofsight(atom/source, sound/S, use_random_freq = FALSE, use_pressure = TRUE, modify_environment = TRUE, required_preferences = 0, required_asfx_toggles = 0)
|
||||
var/list/hearers = get_hearers_in_view(world.view, source)
|
||||
var/turf/source_turf = get_turf(source)
|
||||
var/list/mobs = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(source_turf, world.view, mobs, objs, ONLY_GHOSTS_IN_VIEW)
|
||||
|
||||
for (var/MM in mobs)
|
||||
var/mob/M = MM
|
||||
for (var/mob/M in hearers)
|
||||
if (!M.sound_can_play(required_preferences, required_asfx_toggles))
|
||||
continue
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
|
||||
turfs += src
|
||||
|
||||
if (isStationLevel(z))
|
||||
station_turfs += src
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
|
||||
@@ -66,6 +66,9 @@
|
||||
|
||||
turfs += src
|
||||
|
||||
if (isStationLevel(z))
|
||||
station_turfs += src
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
@@ -109,6 +112,9 @@
|
||||
changing_turf = FALSE
|
||||
turfs -= src
|
||||
|
||||
if (isStationLevel(z))
|
||||
station_turfs -= src
|
||||
|
||||
remove_cleanables()
|
||||
cleanup_roof()
|
||||
|
||||
|
||||
@@ -175,14 +175,13 @@
|
||||
|
||||
/obj/item/device/assembly_holder/Initialize(mapload, ...)
|
||||
. = ..()
|
||||
listening_objects += src
|
||||
become_hearing_sensitive()
|
||||
|
||||
/obj/item/device/assembly_holder/Destroy()
|
||||
if(a_left)
|
||||
a_left.holder = null
|
||||
if(a_right)
|
||||
a_right.holder = null
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/device/assembly_holder/hear_talk(mob/living/M, msg, verb, datum/language/speaking)
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
|
||||
/obj/item/device/assembly/voice/Initialize(mapload, ...)
|
||||
. = ..()
|
||||
listening_objects += src
|
||||
become_hearing_sensitive()
|
||||
|
||||
/obj/item/device/assembly/voice/Destroy()
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/device/assembly/voice/hear_talk(mob/living/M, msg)
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
/atom/proc/balloon_alert_to_viewers(message, self_message, vision_distance = 7, list/ignored_mobs)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
var/list/hearers = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(get_turf(src), vision_distance, hearers, objs, ONLY_GHOSTS_IN_VIEW)
|
||||
// This has to be unlinted because the linter thinks that oranges ears will add reagents and call send_asset
|
||||
// which violates SHOULD_NOT_SLEEP(TRUE)
|
||||
var/list/hearers = UNLINT(get_hearers_in_view(vision_distance, src))
|
||||
hearers -= ignored_mobs
|
||||
|
||||
for(var/mob/hearer as anything in hearers - src)
|
||||
|
||||
@@ -88,9 +88,7 @@
|
||||
// It handles items shipped for bounties.
|
||||
/datum/controller/subsystem/cargo/proc/bounty_ship_item_and_contents(atom/movable/AM, dry_run=FALSE)
|
||||
var/list/matched_one = FALSE
|
||||
var/list/contents = list()
|
||||
contents += AM
|
||||
contents += AM.GetAllContents()
|
||||
var/list/contents = AM.GetAllContents()
|
||||
for(var/thing in reverseRange(contents))
|
||||
var/matched_this = FALSE
|
||||
for(var/datum/bounty/B in bounties_list)
|
||||
@@ -227,4 +225,3 @@
|
||||
if(B.claimed)
|
||||
++count
|
||||
return count
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
|
||||
var/sold_str = ""
|
||||
var/cost = 0
|
||||
|
||||
var/list/contents = list()
|
||||
contents += AM //Also add the container object
|
||||
contents += AM.GetAllContents()
|
||||
var/list/contents = AM.GetAllContents()
|
||||
|
||||
// We go backwards, so it'll be innermost objects sold first
|
||||
for(var/i in reverseRange(contents))
|
||||
|
||||
@@ -138,7 +138,7 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
|
||||
/obj/effect/map_effect/portal/master/Initialize()
|
||||
LAZYADD(all_portal_masters, src)
|
||||
LAZYADD(listening_objects, src)
|
||||
become_hearing_sensitive()
|
||||
find_lines()
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
@@ -150,7 +150,6 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
|
||||
/obj/effect/map_effect/portal/master/Destroy()
|
||||
LAZYREMOVE(all_portal_masters, src)
|
||||
LAZYREMOVE(listening_objects, src)
|
||||
for(var/thing in portal_lines)
|
||||
qdel(thing)
|
||||
return ..()
|
||||
@@ -232,12 +231,9 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
if(!counterpart)
|
||||
return
|
||||
var/turf/T = counterpart.get_focused_turf()
|
||||
var/list/mobs_to_relay = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(T, world.view, mobs_to_relay, objs)
|
||||
var/list/mobs_to_relay = get_hearers_in_view(world.view, T)
|
||||
|
||||
for(var/thing in mobs_to_relay)
|
||||
var/mob/mob = thing
|
||||
for(var/mob/mob in mobs_to_relay)
|
||||
var/rendered = span("message", "[text]")
|
||||
mob.show_message(rendered)
|
||||
|
||||
@@ -249,12 +245,9 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
return
|
||||
var/rendered = span("message", "[msg]")
|
||||
var/turf/T = counterpart.get_focused_turf()
|
||||
var/list/mobs_to_relay = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(T, world.view, mobs_to_relay, objs)
|
||||
var/list/mobs_to_relay = get_hearers_in_view(world.view, T)
|
||||
|
||||
for(var/thing in mobs_to_relay)
|
||||
var/mob/mob = thing
|
||||
for(var/mob/mob in mobs_to_relay)
|
||||
mob.show_message(rendered)
|
||||
|
||||
..()
|
||||
@@ -264,12 +257,9 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
if(!counterpart)
|
||||
return
|
||||
var/turf/T = counterpart.get_focused_turf()
|
||||
var/list/mobs_to_relay = list()
|
||||
var/list/objs = list()
|
||||
get_mobs_or_objs_in_view(T, world.view, mobs_to_relay, objs)
|
||||
var/list/mobs_to_relay = get_hearers_in_view(world.view, T)
|
||||
|
||||
for(var/thing in mobs_to_relay)
|
||||
var/mob/mob = thing
|
||||
for(var/mob/mob in mobs_to_relay)
|
||||
var/accent_icon = M.get_accent_icon(speaking, src)
|
||||
var/name_used = M.GetVoice()
|
||||
var/rendered = null
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
to_chat(A, "<br>")
|
||||
to_chat(A, "<span class='warning'><b>Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT</b></span>")
|
||||
to_chat(A, "<br>")
|
||||
for(var/obj/machinery/telecomms/T in telecomms_list)
|
||||
for(var/obj/machinery/telecomms/T in SSmachinery.all_telecomms)
|
||||
T.emp_act(1)
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
|
||||
|
||||
/datum/event/communications_blackout/start()
|
||||
for(var/obj/machinery/telecomms/T in telecomms_list)
|
||||
for(var/obj/machinery/telecomms/T in SSmachinery.all_telecomms)
|
||||
if(T.z in affecting_z)
|
||||
T.emp_act(1)
|
||||
|
||||
@@ -87,8 +87,7 @@
|
||||
target.add_ion_law(law)
|
||||
target.show_laws()
|
||||
|
||||
if(message_servers)
|
||||
for (var/obj/machinery/message_server/MS in message_servers)
|
||||
for (var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
MS.spamfilter.Cut()
|
||||
var/i
|
||||
for (i = 1, i <= MS.spamfilter_limit, i++)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
Notifications will be sent as updates occur.<br>"
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
|
||||
if(!MS.active) continue
|
||||
for(var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
if(!MS.use_power) continue
|
||||
MS.send_rc_message("Executive Officer's Desk", my_department, message, "", "", 2)
|
||||
|
||||
|
||||
@@ -61,6 +61,6 @@
|
||||
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
|
||||
if(!MS.active) continue
|
||||
for(var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
if(!MS.use_power) continue
|
||||
MS.send_rc_message("Executive Officer's Desk", my_department, message, "", "", 2)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
if(areas && areas.len > 0)
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [worldtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.<br>"
|
||||
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
|
||||
for(var/obj/machinery/telecomms/message_server/MS in SSmachinery.all_telecomms)
|
||||
MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2)
|
||||
for(var/mob/living/silicon/ai/A in player_list)
|
||||
to_chat(A, "<span class='danger'>Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].</span>")
|
||||
|
||||
@@ -320,7 +320,8 @@ em {font-style: normal; font-weight: bold;}
|
||||
.centradio {color: #7272a7;}
|
||||
.airadio {color: #ec00ec;}
|
||||
.entradio {color: #cfcfcf;}
|
||||
.shipradio {color: #8b4cd8;}
|
||||
.hailradio {color: #8b4cd8;}
|
||||
.shipradio {color: #738465;}
|
||||
|
||||
.secradio {color: #e21111;}
|
||||
.engradio {color: #cc7b01;}
|
||||
|
||||
@@ -317,7 +317,8 @@ em {font-style: normal;font-weight: bold;}
|
||||
.centradio {color: #5C5C8A;}
|
||||
.airadio {color: #FF00FF;}
|
||||
.entradio {color: #bd893c;}
|
||||
.shipradio {color: #7331c4;}
|
||||
.hailradio {color: #7331c4;}
|
||||
.shipradio {color: #738465;}
|
||||
|
||||
.secradio {color: #A30000;}
|
||||
.engradio {color: #A66300;}
|
||||
|
||||
@@ -286,7 +286,8 @@ em {font-style: normal; font-weight: bold;}
|
||||
.centradio {color: #5C5C8A;}
|
||||
.airadio {color: #FF00FF;}
|
||||
.entradio {color: #bd893c;}
|
||||
.shipradio {color: #7331c4;}
|
||||
.hailradio {color: #7331c4;}
|
||||
.shipradio {color: #738465;}
|
||||
|
||||
.secradio {color: #A30000;}
|
||||
.engradio {color: #A66300;}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
UNSETEMPTY(pilots)
|
||||
|
||||
if(radio)
|
||||
radio.on = (head?.radio && head.radio.is_functional() && get_cell())
|
||||
radio.set_on(head?.radio && head.radio.is_functional() && get_cell())
|
||||
|
||||
if(camera)
|
||||
camera.status = (head?.camera && head.camera.is_functional())
|
||||
|
||||
@@ -459,10 +459,9 @@
|
||||
|
||||
/obj/item/integrated_circuit/input/microphone/Initialize()
|
||||
. = ..()
|
||||
listening_objects |= src
|
||||
become_hearing_sensitive()
|
||||
|
||||
/obj/item/integrated_circuit/input/microphone/Destroy()
|
||||
listening_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/integrated_circuit/input/microphone/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null)
|
||||
|
||||
@@ -65,6 +65,8 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
|
||||
var/stored_index = 1
|
||||
var/list/atoms_to_initialise = list()
|
||||
var/has_expanded_world_maxx = FALSE
|
||||
var/has_expanded_world_maxy = FALSE
|
||||
|
||||
while(dmmRegex.Find(tfile, stored_index))
|
||||
stored_index = dmmRegex.next
|
||||
@@ -104,6 +106,7 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
continue
|
||||
else
|
||||
world.maxz = zcrd //create a new z_level if needed
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_Z, world.maxz)
|
||||
if(!no_changeturf)
|
||||
WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/post_change is called.")
|
||||
|
||||
@@ -130,6 +133,7 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
if(!cropMap && ycrd > world.maxy)
|
||||
if(!measureOnly)
|
||||
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
|
||||
has_expanded_world_maxy = TRUE
|
||||
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(ycrd, y_lower, y_upper))
|
||||
else
|
||||
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(min(ycrd, world.maxy), y_lower, y_upper))
|
||||
@@ -154,6 +158,7 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
break
|
||||
else
|
||||
world.maxx = xcrd
|
||||
has_expanded_world_maxx = TRUE
|
||||
|
||||
if(xcrd >= 1)
|
||||
var/model_key = copytext(line, tpos, tpos + key_len)
|
||||
@@ -182,10 +187,13 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
else
|
||||
if(!measureOnly)
|
||||
if(!no_changeturf)
|
||||
for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
|
||||
var/turf/T = t
|
||||
for(var/turf/T as anything in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
|
||||
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
|
||||
T.post_change(FALSE)
|
||||
|
||||
if(has_expanded_world_maxx || has_expanded_world_maxy)
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPANDED_WORLD_BOUNDS, has_expanded_world_maxx, has_expanded_world_maxy)
|
||||
|
||||
var/datum/map_load_metadata/M = new
|
||||
M.bounds = bounds
|
||||
M.atoms_to_initialise = atoms_to_initialise
|
||||
|
||||
@@ -325,7 +325,9 @@ swapmap
|
||||
x2+=x1-1
|
||||
y2+=y1-1
|
||||
z2+=z1-1
|
||||
world.maxz=max(z2,world.maxz) // stretch z if necessary
|
||||
if(z2 > world.maxz)
|
||||
world.maxz = z2 // stretch z if necessary
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_Z, world.maxz)
|
||||
if(!ischunk)
|
||||
swapmaps_loaded[src]=null
|
||||
swapmaps_byname[id]=src
|
||||
|
||||
@@ -71,6 +71,9 @@ var/list/mineral_can_smooth_with = list(
|
||||
|
||||
turfs += src
|
||||
|
||||
if(isStationLevel(z))
|
||||
station_turfs += src
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
@@ -197,6 +200,9 @@ var/list/mineral_can_smooth_with = list(
|
||||
|
||||
turfs += src
|
||||
|
||||
if(isStationLevel(z))
|
||||
station_turfs += src
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
@@ -638,6 +644,9 @@ var/list/asteroid_floor_smooth = list(
|
||||
|
||||
turfs += src
|
||||
|
||||
if(isStationLevel(z))
|
||||
station_turfs += src
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
. = list()
|
||||
var/turf/pos = get_turf(source)
|
||||
if(pos)
|
||||
for(var/turf/T in hear(range, pos))
|
||||
for(var/turf/T in get_hear(range, pos))
|
||||
. += T
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
@@ -127,7 +127,7 @@
|
||||
if(vr_mob)
|
||||
to_chat(vr_mob, "[time] [message]")
|
||||
|
||||
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
|
||||
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
|
||||
if(!client && !vr_mob)
|
||||
return
|
||||
|
||||
@@ -165,13 +165,8 @@
|
||||
else
|
||||
speaker_name = "Unknown"
|
||||
|
||||
if(istype(speaker, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = speaker
|
||||
if(H.voice)
|
||||
speaker_name = H.voice
|
||||
|
||||
if(vname)
|
||||
speaker_name = vname
|
||||
if(ishuman(speaker) && speaker.GetVoice() != real_name)
|
||||
speaker_name = speaker.GetVoice()
|
||||
|
||||
if(hard_to_hear)
|
||||
speaker_name = "Unknown"
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
/obj/item/device/mmi/radio_enabled/Initialize()
|
||||
. = ..()
|
||||
radio = new(src)//Spawns a radio inside the MMI.
|
||||
radio.broadcasting = TRUE//So it's broadcasting from the start.
|
||||
radio.set_broadcasting(TRUE) //So it's broadcasting from the start.
|
||||
|
||||
//Allows the brain to toggle the radio functions.
|
||||
/obj/item/device/mmi/radio_enabled/verb/Toggle_Broadcasting()
|
||||
@@ -249,8 +249,8 @@
|
||||
if(brainmob.stat)//Only the brainmob will trigger these so no further check is necessary.
|
||||
to_chat(brainmob, "Can't do that while incapacitated or dead.")
|
||||
|
||||
radio.broadcasting = radio.broadcasting==1 ? 0 : 1
|
||||
to_chat(brainmob, SPAN_NOTICE("Radio is [radio.broadcasting==1 ? "now" : "no longer"] broadcasting."))
|
||||
radio.set_broadcasting(!radio.get_broadcasting())
|
||||
to_chat(brainmob, SPAN_NOTICE("Radio is [radio.get_broadcasting() ? "now" : "no longer"] broadcasting."))
|
||||
|
||||
/obj/item/device/mmi/radio_enabled/verb/Toggle_Listening()
|
||||
set name = "Toggle Listening"
|
||||
@@ -262,8 +262,8 @@
|
||||
if(brainmob.stat)
|
||||
to_chat(brainmob, "Can't do that while incapacitated or dead.")
|
||||
|
||||
radio.listening = radio.listening==1 ? 0 : 1
|
||||
to_chat(brainmob, SPAN_NOTICE("Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast."))
|
||||
radio.set_listening(!radio.get_listening())
|
||||
to_chat(brainmob, SPAN_NOTICE("Radio is [radio.get_listening() ? "now" : "no longer"] receiving broadcast."))
|
||||
|
||||
/obj/item/device/mmi/emp_act(severity)
|
||||
if(!brainmob)
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
return headsets[headsets[1]]
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper, var/is_singing = FALSE)
|
||||
/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper, var/is_singing = FALSE)
|
||||
if(!whisper && (paralysis || InStasis()))
|
||||
whisper(message, speaking)
|
||||
return TRUE
|
||||
@@ -170,53 +170,48 @@
|
||||
for(var/obj/item/device/radio/intercom/I in view(1))
|
||||
I.add_fingerprint(src)
|
||||
used_radios += I
|
||||
if(I.talk_into(src, message, null, verb, speaking))
|
||||
successful_radio += I
|
||||
I.talk_into(src, message, null, verb, speaking)
|
||||
if("headset")
|
||||
var/obj/item/device/radio/R = get_radio()
|
||||
if(R)
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message, null, verb, speaking))
|
||||
successful_radio += R
|
||||
R.talk_into(src, message, null, verb, speaking)
|
||||
if("right ear")
|
||||
var/obj/item/device/radio/R
|
||||
var/has_radio = 0
|
||||
var/has_radio = FALSE
|
||||
if(istype(r_ear,/obj/item/device/radio))
|
||||
R = r_ear
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(istype(r_hand, /obj/item/device/radio))
|
||||
R = r_hand
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(has_radio)
|
||||
used_radios += R
|
||||
if(R.talk_into(src,message,null,verb,speaking))
|
||||
successful_radio += R
|
||||
R.talk_into(src,message,null,verb,speaking)
|
||||
if("left ear")
|
||||
var/obj/item/device/radio/R
|
||||
var/has_radio = 0
|
||||
var/has_radio = FALSE
|
||||
if(istype(l_ear, /obj/item/device/radio))
|
||||
R = l_ear
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(istype(l_hand, /obj/item/device/radio))
|
||||
R = l_hand
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(has_radio)
|
||||
used_radios += R
|
||||
if(R.talk_into(src,message,null,verb,speaking))
|
||||
successful_radio += R
|
||||
R.talk_into(src,message,null,verb,speaking)
|
||||
if("wrist")
|
||||
var/obj/item/device/radio/R
|
||||
var/has_radio = 0
|
||||
var/has_radio = FALSE
|
||||
if(istype(wrists,/obj/item/device/radio))
|
||||
R = wrists
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(istype(r_hand, /obj/item/device/radio))
|
||||
R = wrists
|
||||
has_radio = 1
|
||||
has_radio = TRUE
|
||||
if(has_radio)
|
||||
used_radios += R
|
||||
if(R.talk_into(src,message,null,verb,speaking))
|
||||
successful_radio += R
|
||||
R.talk_into(src,message,null,verb,speaking)
|
||||
if("whisper")
|
||||
whisper(message, speaking, is_singing)
|
||||
return TRUE
|
||||
@@ -224,8 +219,7 @@
|
||||
var/obj/item/device/radio/R = get_radio()
|
||||
if(R)
|
||||
used_radios += R
|
||||
if(R.talk_into(src, message, message_mode, verb, speaking))
|
||||
successful_radio += R
|
||||
R.talk_into(src, message, message_mode, verb, speaking)
|
||||
|
||||
/mob/living/carbon/human/handle_speech_sound()
|
||||
var/list/returns = ..()
|
||||
|
||||
@@ -16,7 +16,7 @@ var/list/department_radio_keys = list(
|
||||
":x" = "Raider", ".x" = "Raider",
|
||||
":b" = "Burglar", ".b" = "Burglar",
|
||||
":j" = "Bluespace", ".j" = "Bluespace",
|
||||
":y" = "Ship", ".y" = "Ship",
|
||||
":y" = "Hailing", ".y" = "Hailing",
|
||||
":q" = "Ninja", ".q" = "Ninja",
|
||||
":u" = "Operations", ".u" = "Operations",
|
||||
":v" = "Service", ".v" = "Service",
|
||||
@@ -39,7 +39,7 @@ var/list/department_radio_keys = list(
|
||||
":X" = "Raider", ".X" = "Raider",
|
||||
":B" = "Burglar", ".B" = "Burglar",
|
||||
":J" = "Bluespace", ".J" = "Bluespace",
|
||||
":Y" = "Ship", ".Y" = "Ship",
|
||||
":Y" = "Hailing", ".Y" = "Hailing",
|
||||
":Q" = "Ninja", ".Q" = "Ninja",
|
||||
":U" = "Operations", ".U" = "Operations",
|
||||
":V" = "Service", ".V" = "Service",
|
||||
@@ -129,16 +129,17 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
/mob/living/proc/get_stutter_verbs()
|
||||
return list("stammers", "stutters")
|
||||
|
||||
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper)
|
||||
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper)
|
||||
if(message_mode == "intercom")
|
||||
for(var/obj/item/device/radio/intercom/I in view(1, null))
|
||||
for(var/obj/item/device/radio/intercom/I in view(1, src))
|
||||
used_radios += I
|
||||
if(I.talk_into(src, message, verb, speaking))
|
||||
successful_radio += I
|
||||
I.talk_into(src, message, verb, speaking)
|
||||
|
||||
if(message_mode == "whisper" && !whisper)
|
||||
whisper(message, speaking)
|
||||
return TRUE
|
||||
return 0
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/handle_speech_sound()
|
||||
var/list/returns[3]
|
||||
@@ -250,34 +251,28 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
return say_signlang(message, pick(speaking.signlang_verb), speaking, speaking.sign_adv_length)
|
||||
|
||||
var/list/obj/item/used_radios = new
|
||||
var/list/successful_radio = new // passes a list because standard vars don't work when passed
|
||||
if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper, is_singing))
|
||||
return 1
|
||||
if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper, is_singing))
|
||||
return TRUE
|
||||
|
||||
var/list/handle_v = handle_speech_sound()
|
||||
var/sound/speech_sound = handle_v[1]
|
||||
var/sound_vol = handle_v[2]
|
||||
var/italics = handle_v[3]
|
||||
|
||||
|
||||
|
||||
//speaking into radios
|
||||
if(length(used_radios))
|
||||
italics = 1
|
||||
message_range = 1
|
||||
if(speaking)
|
||||
message_range = speaking.get_talkinto_msg_range(message)
|
||||
var/msg
|
||||
if(!speaking || !(speaking.flags & NO_TALK_MSG))
|
||||
msg = "<span class='notice'>\The [src] [length(successful_radio) ? "talks into" : "tries talking into"] \the [used_radios[1]]</span>."
|
||||
for(var/mob/living/M in hearers(5, src) - src)
|
||||
if(msg)
|
||||
M.show_message(msg)
|
||||
var/msg = SPAN_NOTICE("\The [src] talks into \the [used_radios[1]].")
|
||||
for (var/mob/living/L in get_hearers_in_view(5, src) - src)
|
||||
L.show_message(msg)
|
||||
if(speech_sound)
|
||||
sound_vol *= 0.5
|
||||
|
||||
var/list/listening = list()
|
||||
var/list/listening_obj = list()
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
if(whisper)
|
||||
@@ -296,14 +291,21 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
italics = 1
|
||||
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
|
||||
|
||||
get_mobs_or_objs_in_view(T, message_range, listening, listening_obj, ghost_hearing)
|
||||
listening = get_hearers_in_view(message_range, src)
|
||||
|
||||
if(client)
|
||||
for (var/mob/player_mob in player_list)
|
||||
if(!player_mob || player_mob.stat != DEAD || (player_mob in listening))
|
||||
continue
|
||||
if(player_mob.client?.prefs.toggles & CHAT_GHOSTEARS)
|
||||
listening |= player_mob
|
||||
|
||||
var/list/hear_clients = list()
|
||||
for(var/m in listening)
|
||||
var/mob/M = m
|
||||
for(var/mob/M in listening)
|
||||
var/heard_say = M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol, get_font_size_modifier())
|
||||
if(heard_say && M.client)
|
||||
hear_clients += M.client
|
||||
listening -= M
|
||||
|
||||
var/speech_bubble_test = say_test(message)
|
||||
var/image/speech_bubble = image(get_talk_bubble(),src,"h[speech_bubble_test]")
|
||||
@@ -313,7 +315,7 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
|
||||
var/bypass_listen_obj = (speaking && (speaking.flags & PASSLISTENOBJ))
|
||||
if(!bypass_listen_obj)
|
||||
for(var/obj/O as anything in listening_obj)
|
||||
for(var/obj/O as anything in listening)
|
||||
if(O) //It's possible that it could be deleted in the meantime.
|
||||
INVOKE_ASYNC(O, /obj/.proc/hear_talk, src, message, verb, speaking)
|
||||
|
||||
|
||||
@@ -136,9 +136,9 @@
|
||||
|
||||
if(common_radio)
|
||||
if(!is_component_functioning("radio"))
|
||||
common_radio.on = FALSE
|
||||
common_radio.set_on(FALSE)
|
||||
else
|
||||
common_radio.on = TRUE
|
||||
common_radio.set_on(TRUE)
|
||||
|
||||
if(is_component_functioning("camera"))
|
||||
blinded = FALSE
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
returns[4] = world.view
|
||||
return returns
|
||||
|
||||
/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper)
|
||||
/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper)
|
||||
if(message_mode == "whisper" && !whisper)
|
||||
whisper(message, speaking)
|
||||
return TRUE
|
||||
@@ -36,7 +36,7 @@
|
||||
/mob/living/silicon/robot/drone/handle_message_mode()
|
||||
return null
|
||||
|
||||
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper)
|
||||
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper)
|
||||
if(message_mode == "whisper" && !whisper)
|
||||
whisper(message, speaking)
|
||||
return TRUE
|
||||
@@ -52,7 +52,7 @@
|
||||
log_say("[key_name(src)] : [message]",ckey=key_name(src))
|
||||
return ai_radio.talk_into(src, message, message_mode, verb, speaking)
|
||||
|
||||
/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper)
|
||||
/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper)
|
||||
if(message_mode)
|
||||
if(message_mode == "whisper" && !whisper)
|
||||
whisper(message, speaking)
|
||||
@@ -120,7 +120,7 @@
|
||||
var/turf/T = get_turf(H)
|
||||
|
||||
if(T)
|
||||
var/list/hear = hear(7, T)
|
||||
var/list/hear = get_hear(7, T)
|
||||
var/list/hearturfs = list()
|
||||
|
||||
for(var/I in hear)
|
||||
|
||||
@@ -339,7 +339,7 @@
|
||||
/mob/living/simple_animal/spiderbot/get_bullet_impact_effect_type(var/def_zone)
|
||||
return BULLET_IMPACT_METAL
|
||||
|
||||
/mob/living/simple_animal/spiderbot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio, whisper)
|
||||
/mob/living/simple_animal/spiderbot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whisper)
|
||||
switch(message_mode)
|
||||
if("whisper")
|
||||
if(!whisper)
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
/mob/living/simple_animal/hostile/hivebotbeacon/proc/generate_warp_destinations()
|
||||
|
||||
destinations.Cut()
|
||||
for(var/turf/simulated/floor/T in circlerange(src,10))
|
||||
for(var/turf/simulated/floor/T in circle_range(src,10))
|
||||
if(turf_clear(T))
|
||||
destinations += T
|
||||
var/area/A = get_area(src)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user