diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index 91347291e3..dad2a38afd 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -284,12 +284,11 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
GLOBAL_VAR(atmos_extools_initialized) // this must be an uninitialized (null) one or init_monstermos will be called twice because reasons
#define ATMOS_EXTOOLS_CHECK if(!GLOB.atmos_extools_initialized){\
GLOB.atmos_extools_initialized=TRUE;\
- var/extools = world.GetConfig("env", "EXTOOLS_DLL") || (world.system_type == MS_WINDOWS ? "./byond-extools.dll" : "./libbyond-extools.so");\
- if(fexists(extools)){\
- var/result = call(extools,"init_monstermos")();\
+ if(fexists(EXTOOLS)){\
+ var/result = call(EXTOOLS,"init_monstermos")();\
if(result != "ok") {CRASH(result);}\
} else {\
- CRASH("[extools] does not exist!");\
+ CRASH("[EXTOOLS] does not exist!");\
}\
}
diff --git a/code/__DEFINES/extools.dm b/code/__DEFINES/extools.dm
new file mode 100644
index 0000000000..ed78a1d992
--- /dev/null
+++ b/code/__DEFINES/extools.dm
@@ -0,0 +1,36 @@
+// _extools_api.dm - DM API for extools extension library
+// (blatently stolen from rust_g)
+//
+// To configure, create a `extools.config.dm` and set what you care about from
+// the following options:
+//
+// #define EXTOOLS "path/to/extools"
+// Override the .dll/.so detection logic with a fixed path or with detection
+// logic of your own.
+
+#ifndef EXTOOLS
+// Default automatic EXTOOLS detection.
+// On Windows, looks in the standard places for `byond-extools.dll`.
+// On Linux, looks in the standard places for`libbyond-extools.so`.
+
+/* This comment bypasses grep checks */ /var/__extools
+
+/proc/__detect_extools()
+ if (world.system_type == UNIX)
+ if (fexists("./libbyond-extools.so"))
+ // No need for LD_LIBRARY_PATH badness.
+ return __extools = "./libbyond-extools.so"
+ else
+ // It's not in the current directory, so try others
+ return __extools = "libbyond-extools.so"
+ else
+ return __extools = "byond-extools.dll"
+
+#define EXTOOLS (__extools || __detect_extools())
+#endif
+
+// #define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
+
+/proc/extools_log_write()
+
+/proc/extools_finalize_logging()
diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm
index 20e7975ec4..51eaddef72 100644
--- a/code/__DEFINES/rust_g.dm
+++ b/code/__DEFINES/rust_g.dm
@@ -1,19 +1,78 @@
// rust_g.dm - DM API for rust_g extension library
-#define RUST_G "rust_g"
+//
+// To configure, create a `rust_g.config.dm` and set what you care about from
+// the following options:
+//
+// #define RUST_G "path/to/rust_g"
+// Override the .dll/.so detection logic with a fixed path or with detection
+// logic of your own.
+//
+// #define RUSTG_OVERRIDE_BUILTINS
+// Enable replacement rust-g functions for certain builtins. Off by default.
-#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
-#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
-#define RUSTG_JOB_ERROR "JOB PANICKED"
+#ifndef RUST_G
+// Default automatic RUST_G detection.
+// On Windows, looks in the standard places for `rust_g.dll`.
+// On Linux, looks in `.`, `$LD_LIBRARY_PATH`, and `~/.byond/bin` for either of
+// `librust_g.so` (preferred) or `rust_g` (old).
+
+/* This comment bypasses grep checks */ /var/__rust_g
+
+/proc/__detect_rust_g()
+ if (world.system_type == UNIX)
+ if (fexists("./librust_g.so"))
+ // No need for LD_LIBRARY_PATH badness.
+ return __rust_g = "./librust_g.so"
+ else if (fexists("./rust_g"))
+ // Old dumb filename.
+ return __rust_g = "./rust_g"
+ else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/rust_g"))
+ // Old dumb filename in `~/.byond/bin`.
+ return __rust_g = "rust_g"
+ else
+ // It's not in the current directory, so try others
+ return __rust_g = "librust_g.so"
+ else
+ return __rust_g = "rust_g"
+
+#define RUST_G (__rust_g || __detect_rust_g())
+#endif
+
+/**
+ * This proc generates a cellular automata noise grid which can be used in procedural generation methods.
+ *
+ * Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell.
+ *
+ * Arguments:
+ * * percentage: The chance of a turf starting closed
+ * * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results
+ * * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born
+ * * death_limit: If the number of neighboring cells is lower than this amount, a cell dies
+ * * width: The width of the grid.
+ * * height: The height of the grid.
+ */
+#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \
+ call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height)
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data)
+#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype)
+
+#define rustg_file_read(fname) call(RUST_G, "file_read")(fname)
+#define rustg_file_exists(fname) call(RUST_G, "file_exists")(fname)
+#define rustg_file_write(text, fname) call(RUST_G, "file_write")(text, fname)
+#define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname)
+
+#define RUSTG_OVERRIDE_BUILTINS
+
+#ifdef RUSTG_OVERRIDE_BUILTINS
+ #define file2text(fname) rustg_file_read("[fname]")
+ #define text2file(text, fname) rustg_file_append(text, "[fname]")
+#endif
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
-#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
-/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
-
#define RUSTG_HTTP_METHOD_GET "get"
#define RUSTG_HTTP_METHOD_PUT "put"
#define RUSTG_HTTP_METHOD_DELETE "delete"
@@ -23,3 +82,21 @@
#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
+
+#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
+#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
+#define RUSTG_JOB_ERROR "JOB PANICKED"
+
+#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true")
+
+#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
+/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
+
+#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y)
+
+#define rustg_sql_connect_pool(options) call(RUST_G, "sql_connect_pool")(options)
+#define rustg_sql_query_async(handle, query, params) call(RUST_G, "sql_query_async")(handle, query, params)
+#define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params)
+#define rustg_sql_connected(handle) call(RUST_G, "sql_connected")(handle)
+#define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle)
+#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]")
diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm
index 568415edd9..4624b77940 100644
--- a/code/__DEFINES/spaceman_dmm.dm
+++ b/code/__DEFINES/spaceman_dmm.dm
@@ -29,6 +29,5 @@
#endif
/world/proc/enable_debugger()
- var/dll = world.GetConfig("env", "EXTOOLS_DLL")
- if (dll)
- call(dll, "debug_initialize")()
+ if (EXTOOLS)
+ call(EXTOOLS, "debug_initialize")()
diff --git a/code/__HELPERS/_extools_api.dm b/code/__HELPERS/_extools_api.dm
deleted file mode 100644
index af348dc939..0000000000
--- a/code/__HELPERS/_extools_api.dm
+++ /dev/null
@@ -1,5 +0,0 @@
-#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined
-
-/proc/extools_log_write()
-
-/proc/extools_finalize_logging()
diff --git a/code/controllers/subsystem/jukeboxes.dm b/code/controllers/subsystem/jukeboxes.dm
index c6f3911272..0f7e2a6e80 100644
--- a/code/controllers/subsystem/jukeboxes.dm
+++ b/code/controllers/subsystem/jukeboxes.dm
@@ -94,9 +94,7 @@ SUBSYSTEM_DEF(jukeboxes)
stack_trace("Nonexistant or invalid object associated with jukebox.")
continue
var/sound/song_played = sound(juketrack.song_path)
- var/area/currentarea = get_area(jukebox)
var/turf/currentturf = get_turf(jukebox)
- var/list/hearerscache = hearers(7, jukebox)
song_played.falloff = jukeinfo[4]
@@ -107,13 +105,8 @@ SUBSYSTEM_DEF(jukeboxes)
M.stop_sound_channel(jukeinfo[2])
continue
- var/inrange = FALSE
if(jukebox.z == M.z) //todo - expand this to work with mining planet z-levels when robust jukebox audio gets merged to master
song_played.status = SOUND_UPDATE
- if(get_area(M) == currentarea)
- inrange = TRUE
- else if(M in hearerscache)
- inrange = TRUE
else
song_played.status = SOUND_MUTE | SOUND_UPDATE //Setting volume = 0 doesn't let the sound properties update at all, which is lame.
M.playsound_local(currentturf, null, 100, channel = jukeinfo[2], S = song_played, use_reverb = FALSE)
diff --git a/code/game/world.dm b/code/game/world.dm
index 431c860a97..bf04e0b8d1 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -34,14 +34,13 @@ GLOBAL_LIST(topic_status_cache)
* All atoms in both compiled and uncompiled maps are initialized()
*/
/world/New()
- var/extools = world.GetConfig("env", "EXTOOLS_DLL") || (world.system_type == MS_WINDOWS ? "./byond-extools.dll" : "./libbyond-extools.so")
- if (fexists(extools))
- call(extools, "maptick_initialize")()
- #ifdef EXTOOLS_LOGGING
- call(extools, "init_logging")()
+ if (fexists(EXTOOLS))
+ call(EXTOOLS, "maptick_initialize")()
+#ifdef EXTOOLS_LOGGING
+ call(EXTOOLS, "init_logging")()
else
- CRASH("[extools] does not exist!")
- #endif
+ CRASH("[EXTOOLS] does not exist!")
+#endif
enable_debugger()
#ifdef REFERENCE_TRACKING
enable_reference_tracking()
@@ -367,6 +366,10 @@ GLOBAL_LIST(topic_status_cache)
maxz++
SSmobs.MaxZChanged()
SSidlenpcpool.MaxZChanged()
+ world.refresh_atmos_grid()
+
+/// Extools atmos
+/world/proc/refresh_atmos_grid()
/world/proc/change_fps(new_value = 20)
if(new_value <= 0)
diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm
index a8c9946c2d..c293500298 100644
--- a/code/modules/admin/view_variables/reference_tracking.dm
+++ b/code/modules/admin/view_variables/reference_tracking.dm
@@ -3,9 +3,8 @@
GLOBAL_LIST_EMPTY(deletion_failures)
/world/proc/enable_reference_tracking()
- var/extools = world.GetConfig("env", "EXTOOLS_DLL") || (world.system_type == MS_WINDOWS ? "./byond-extools.dll" : "./libbyond-extools.so")
- if (fexists(extools))
- call(extools, "ref_tracking_initialize")()
+ if (fexists(EXTOOLS))
+ call(EXTOOLS, "ref_tracking_initialize")()
/proc/get_back_references(datum/D)
CRASH("/proc/get_back_references not hooked by extools, reference tracking will not function!")
diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm
index 500ddc3774..a3e0653678 100644
--- a/code/modules/mapping/reader.dm
+++ b/code/modules/mapping/reader.dm
@@ -300,6 +300,9 @@
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(CHANGETURF_IGNORE_AIR)
+ if(did_expand)
+ world.refresh_atmos_grid()
+
#ifdef TESTING
if(turfsSkipped)
testing("Skipped loading [turfsSkipped] default turfs")
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index b6b74efe32..47b504c86e 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -1319,7 +1319,7 @@
if(E.phase > 1)
if(user.ckey == E.enthrallID && user.real_name == E.master.real_name)
E.master = user
- addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"), 5)
+ to_chat(H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]")
to_chat(user, "[H] looks at you with sparkling eyes, recognising you!")
//I dunno how to do state objectives without them revealing they're an antag
diff --git a/rust_g.dll b/rust_g.dll
index 8cd62b8ca4..8ef1c59a10 100755
Binary files a/rust_g.dll and b/rust_g.dll differ
diff --git a/tgstation.dme b/tgstation.dme
index 97b639e95a..7fda26f839 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -51,6 +51,7 @@
#include "code\__DEFINES\events.dm"
#include "code\__DEFINES\exosuit_fabs.dm"
#include "code\__DEFINES\exports.dm"
+#include "code\__DEFINES\extools.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm"
@@ -153,7 +154,6 @@
#include "code\__DEFINES\storage\_storage.dm"
#include "code\__DEFINES\storage\volumetrics.dm"
#include "code\__HELPERS\_cit_helpers.dm"
-#include "code\__HELPERS\_extools_api.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"
#include "code\__HELPERS\_string_lists.dm"