diff --git a/.github/alternate_byond_versions.txt b/.github/alternate_byond_versions.txt index 9a21320ab175..02ebe04a40b8 100644 --- a/.github/alternate_byond_versions.txt +++ b/.github/alternate_byond_versions.txt @@ -6,4 +6,4 @@ # Example: # 500.1337: runtimestation -515.1603: runtimestation +515.1620: runtimestation diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 82d0ac76f32f..91ab12cdb19f 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -8,7 +8,7 @@ permissions: jobs: autowiki: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: "Check for AUTOWIKI_USERNAME" id: secrets_set @@ -30,9 +30,6 @@ jobs: - name: Install rust-g if: steps.secrets_set.outputs.SECRETS_ENABLED run: | - sudo dpkg --add-architecture i386 - sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 bash tools/ci/install_rust_g.sh - name: Compile and generate Autowiki files if: steps.secrets_set.outputs.SECRETS_ENABLED diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index bfb8b4b8c947..49978ca25a3f 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -18,7 +18,7 @@ on: type: string jobs: run_integration_tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest services: mysql: image: mysql:latest @@ -43,9 +43,6 @@ jobs: mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql - name: Install rust-g run: | - sudo dpkg --add-architecture i386 - sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 bash tools/ci/install_rust_g.sh - name: Install auxlua run: | diff --git a/.tgs.yml b/.tgs.yml index b012bdffe231..091544877a67 100644 --- a/.tgs.yml +++ b/.tgs.yml @@ -3,7 +3,7 @@ version: 1 # The BYOND version to use (kept in sync with dependencies.sh by the "TGS Test Suite" CI job) # Must be interpreted as a string, keep quoted -byond: "514.1588" +byond: "515.1610" # Folders to create in "/Configuration/GameStaticFiles/" static_files: # Config directory should be static diff --git a/code/__DEFINES/_helpers.dm b/code/__DEFINES/_helpers.dm index fdbfde608225..3e88256b462a 100644 --- a/code/__DEFINES/_helpers.dm +++ b/code/__DEFINES/_helpers.dm @@ -25,14 +25,5 @@ } \ sleep(time); -#ifdef EXPERIMENT_515_DONT_CACHE_REF /// Takes a datum as input, returns its ref string #define text_ref(datum) ref(datum) -#else -/// Takes a datum as input, returns its ref string, or a cached version of it -/// This allows us to cache \ref creation, which ensures it'll only ever happen once per datum, saving string tree time -/// It is slightly less optimal then a []'d datum, but the cost is massively outweighed by the potential savings -/// It will only work for datums mind, for datum reasons -/// : because of the embedded typecheck -#define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]")) -#endif diff --git a/code/__DEFINES/_protect.dm b/code/__DEFINES/_protect.dm index 22fad2f63851..9152cfcb5706 100644 --- a/code/__DEFINES/_protect.dm +++ b/code/__DEFINES/_protect.dm @@ -1,4 +1,5 @@ ///Protects a datum from being VV'd or spawned through admin manipulation +#ifndef TESTING #define GENERAL_PROTECT_DATUM(Path)\ ##Path/can_vv_get(var_name){\ return FALSE;\ @@ -15,3 +16,6 @@ ##Path/Write(savefile/savefile){\ return;\ } +#else +#define GENERAL_PROTECT_DATUM(Path) +#endif diff --git a/code/__DEFINES/blackmarket.dm b/code/__DEFINES/blackmarket.dm index 5494c371db7b..5d74d183b8d2 100644 --- a/code/__DEFINES/blackmarket.dm +++ b/code/__DEFINES/blackmarket.dm @@ -7,4 +7,5 @@ #define SHIPPING_METHOD_TELEPORT "Teleport" // Throws the item from somewhere at the station. #define SHIPPING_METHOD_LAUNCH "Launch" - +/// item appears at your feet used by auctions +#define SHIPPING_METHOD_AT_FEET "Feet" diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index b2bdc2b99d11..a758506ced4d 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -146,6 +146,7 @@ GLOBAL_LIST_INIT(crafting_category_food, list( #define CAT_ENTERTAINMENT "Entertainment" #define CAT_TOOLS "Tools" #define CAT_CULT "Blood Cult" +#define CAT_GUNPARTS "Gun Parts" GLOBAL_LIST_INIT(crafting_category, list( CAT_WEAPON_RANGED, @@ -166,6 +167,7 @@ GLOBAL_LIST_INIT(crafting_category, list( CAT_ENTERTAINMENT, CAT_TOOLS, CAT_CULT, + CAT_GUNPARTS, )) //rcd modes diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index c692125e0e48..bdb79226e738 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -49,7 +49,8 @@ #define LOG_RADIO_EMOTE (1 << 20) #define LOG_SPEECH_INDICATORS (1 << 21) #define LOG_CLONING (1 << 22) -#define LOG_MECHCOMP (1 <<23) +#define LOG_MECHCOMP (1 << 23) +#define LOG_BLACKMARKET (1 << 24) //Individual logging panel pages #define INDIVIDUAL_GAME_LOG (LOG_GAME) @@ -86,8 +87,9 @@ #define LOG_ENTRY_KEY_ID "id" #define LOG_ENTRY_KEY_SCHEMA_VERSION "s-ver" -// Category for invalid/missing categories -#define LOG_CATEGORY_NOT_FOUND "invalid-category" +// Internal categories +#define LOG_CATEGORY_INTERNAL_CATEGORY_NOT_FOUND "internal-category-not-found" +#define LOG_CATEGORY_INTERNAL_ERROR "internal-error" // Misc categories #define LOG_CATEGORY_ATTACK "attack" @@ -114,6 +116,7 @@ #define LOG_CATEGORY_MUSIC "music" #define LOG_CATEGORY_META "currency" #define LOG_CATEGORY_ARTIFACT "artifact" +#define LOG_CATEGORY_BLACKMARKET "blackmarket" // Admin categories #define LOG_CATEGORY_ADMIN "admin" diff --git a/code/__DEFINES/overlays.dm b/code/__DEFINES/overlays.dm index b95a460168f1..7cf365dea99a 100644 --- a/code/__DEFINES/overlays.dm +++ b/code/__DEFINES/overlays.dm @@ -1,6 +1,6 @@ // A reasonable number of maximum overlays an object needs // If you think you need more, rethink it -#define MAX_ATOM_OVERLAYS 100 +#define MAX_ATOM_OVERLAYS 250 /// Checks if an atom has reached the overlay limit, and make a loud error if it does. #define VALIDATE_OVERLAY_LIMIT(changed_on) \ diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index cab4430a88df..24f6d3125a90 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -39,11 +39,8 @@ #endif // Handle 515 call() -> call_ext() changes -#if DM_VERSION >= 515 #define RUSTG_CALL call_ext -#else -#define RUSTG_CALL call -#endif + /// Gets the version of rust_g /proc/rustg_get_version() return RUSTG_CALL(RUST_G, "get_version")() @@ -110,9 +107,15 @@ #define rustg_dmi_strip_metadata(fname) RUSTG_CALL(RUST_G, "dmi_strip_metadata")(fname) #define rustg_dmi_create_png(path, width, height, data) RUSTG_CALL(RUST_G, "dmi_create_png")(path, width, height, data) #define rustg_dmi_resize_png(path, width, height, resizetype) RUSTG_CALL(RUST_G, "dmi_resize_png")(path, width, height, resizetype) +/** + * input: must be a path, not an /icon; you have to do your own handling if it is one, as icon objects can't be directly passed to rustg. + * + * output: json_encode'd list. json_decode to get a flat list with icon states in the order they're in inside the .dmi + */ +#define rustg_dmi_icon_states(fname) RUSTG_CALL(RUST_G, "dmi_icon_states")(fname) #define rustg_file_read(fname) RUSTG_CALL(RUST_G, "file_read")(fname) -#define rustg_file_exists(fname) RUSTG_CALL(RUST_G, "file_exists")(fname) +#define rustg_file_exists(fname) (RUSTG_CALL(RUST_G, "file_exists")(fname) == "true") #define rustg_file_write(text, fname) RUSTG_CALL(RUST_G, "file_write")(text, fname) #define rustg_file_append(text, fname) RUSTG_CALL(RUST_G, "file_append")(text, fname) #define rustg_file_get_line_count(fname) text2num(RUSTG_CALL(RUST_G, "file_get_line_count")(fname)) @@ -123,7 +126,13 @@ #define text2file(text, fname) rustg_file_append(text, "[fname]") #endif +/// Returns the git hash of the given revision, ex. "HEAD". #define rustg_git_revparse(rev) RUSTG_CALL(RUST_G, "rg_git_revparse")(rev) + +/** + * Returns the date of the given revision in the format YYYY-MM-DD. + * Returns null if the revision is invalid. + */ #define rustg_git_commit_date(rev) RUSTG_CALL(RUST_G, "rg_git_commit_date")(rev) #define RUSTG_HTTP_METHOD_GET "get" @@ -158,8 +167,9 @@ #define rustg_time_milliseconds(id) text2num(RUSTG_CALL(RUST_G, "time_milliseconds")(id)) #define rustg_time_reset(id) RUSTG_CALL(RUST_G, "time_reset")(id) +/// Returns the timestamp as a string /proc/rustg_unix_timestamp() - return text2num(RUSTG_CALL(RUST_G, "unix_timestamp")()) + return RUSTG_CALL(RUST_G, "unix_timestamp")() #define rustg_raw_read_toml_file(path) json_decode(RUSTG_CALL(RUST_G, "toml_file_to_json")(path) || "null") diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 037e29ed6d0c..eb663c3c693b 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -18,6 +18,7 @@ #define CHANNEL_Z 1008 #define CHANNEL_WALKMAN 1007 //monkestation edit #define CHANNEL_MASTER_VOLUME 1006 +#define CHANNEL_PRUDE 1007 ///Default range of a sound. #define SOUND_RANGE 17 @@ -34,7 +35,7 @@ //THIS SHOULD ALWAYS BE THE LOWEST ONE! //KEEP IT UPDATED -#define CHANNEL_HIGHEST_AVAILABLE 1006 //monkestation edit +#define CHANNEL_HIGHEST_AVAILABLE 1007 //monkestation edit #define MAX_INSTRUMENT_CHANNELS (128 * 6) diff --git a/code/__DEFINES/stamina.dm b/code/__DEFINES/stamina.dm index da253dd117d6..94c743c79b26 100644 --- a/code/__DEFINES/stamina.dm +++ b/code/__DEFINES/stamina.dm @@ -42,7 +42,7 @@ ///The amount of stamina at which point swinging is free. #define STAMINA_MAXIMUM_TO_SWING 100 ///The time a mob is stunned when stamina stunned -#define STAMINA_STUN_TIME 5 SECONDS +#define STAMINA_STUN_TIME 9 SECONDS ///The base value of a stamina stun chance #define STAMINA_SCALING_STUN_BASE 20 ///The maximum additional stun chance based on missing stamina diff --git a/code/__DEFINES/~monkestation/_patreon.dm b/code/__DEFINES/~monkestation/_patreon.dm index 45e6401c5a34..dbb72ea2d6b8 100644 --- a/code/__DEFINES/~monkestation/_patreon.dm +++ b/code/__DEFINES/~monkestation/_patreon.dm @@ -4,7 +4,7 @@ #define ASSISTANT_RANK "9641458" #define COMMAND_RANK "9641523" #define TRAITOR_RANK "9641531" //muh defines -#define NUKIE_RANK "9641543" +#define NUKIE_RANK "10901851" #define ACCESS_THANKS_RANK 1 #define ACCESS_ASSISTANT_RANK 2 diff --git a/code/__DEFINES/~monkestation/dcs/signals/signals_guns.dm b/code/__DEFINES/~monkestation/dcs/signals/signals_guns.dm new file mode 100644 index 000000000000..bc3f77a08e72 --- /dev/null +++ b/code/__DEFINES/~monkestation/dcs/signals/signals_guns.dm @@ -0,0 +1,5 @@ +#define COMSIG_ATTACHMENT_ATTACHED "comsig_attachment_attached" +#define COMSIG_ATTACHMENT_DETACHED "comsig_attachment_detached" +#define COMSIG_ATTACHMENT_ATTACH_ATTEMPT "comsig_attachment_attach_attempt" +#define COMSIG_GUN_RACKED "gun_racked" +#define COMSIG_ATTACHMENT_STAT_RESET "gun_stat_reset" diff --git a/code/__DEFINES/~monkestation/guns.dm b/code/__DEFINES/~monkestation/guns.dm new file mode 100644 index 000000000000..412300a93c13 --- /dev/null +++ b/code/__DEFINES/~monkestation/guns.dm @@ -0,0 +1,16 @@ +#define GUN_ATTACH_AK "ak" +#define GUN_ATTACH_AK_ST "ak_st" +#define GUN_ATTACH_MK_58 "mk58" +#define GUN_ATTACH_WINTERMUTE "wintermute" + +#define ATTACHMENT_TYPE_MAG "attach_mag" +#define ATTACHMENT_TYPE_STOCK "attach_stock" +#define ATTACHMENT_TYPE_GRIP "attach_grip" +#define ATTACHMENT_TYPE_BARREL "attach_barrel" +#define ATTACHMENT_TYPE_SIGHT "attach_sight" +#define ATTACHMENT_TYPE_UNDERBARREL "attach_underbarrel" +#define ATTACHMENT_TYPE_WELROD "attach_welrod" +#define ATTACHMENT_TYPE_FRAME "attach_frame" +#define ATTACHMENT_TYPE_KEYCHAIN "attach_keychain?" + +#define ATTACHMENT_COLORABLE (1<<0) diff --git a/code/__DEFINES/~monkestation/market.dm b/code/__DEFINES/~monkestation/market.dm new file mode 100644 index 000000000000..899af43fb164 --- /dev/null +++ b/code/__DEFINES/~monkestation/market.dm @@ -0,0 +1,2 @@ +#define MARKET_PROCESS (1<<0) +#define MARKET_AUCTION (1<<1) diff --git a/code/__DEFINES/~monkestation/projectiles.dm b/code/__DEFINES/~monkestation/projectiles.dm new file mode 100644 index 000000000000..438417dc1d94 --- /dev/null +++ b/code/__DEFINES/~monkestation/projectiles.dm @@ -0,0 +1,5 @@ +//Calibers for guns +///used in mk58 +#define CALIBER_435 "4.35" +///used in mk58 +#define CALIBER_235 "2.35" diff --git a/code/__HELPERS/_auxtools_api.dm b/code/__HELPERS/_auxtools_api.dm index 8dbd58f2eeda..0117ded4c519 100644 --- a/code/__HELPERS/_auxtools_api.dm +++ b/code/__HELPERS/_auxtools_api.dm @@ -10,7 +10,7 @@ GLOBAL_PROTECT(auxtools_initialized) }\ if (GLOB.auxtools_initialized[LIB] != AUXTOOLS_FULL_INIT) {\ if (fexists(LIB)) {\ - var/string = LIBCALL(LIB,"auxtools_init")();\ + var/string = call_ext(LIB,"auxtools_init")();\ if(findtext(string, "SUCCESS")) {\ GLOB.auxtools_initialized[LIB] = AUXTOOLS_FULL_INIT;\ } else {\ @@ -23,13 +23,13 @@ GLOBAL_PROTECT(auxtools_initialized) #define AUXTOOLS_SHUTDOWN(LIB)\ if (GLOB.auxtools_initialized[LIB] == AUXTOOLS_FULL_INIT && fexists(LIB)){\ - LIBCALL(LIB,"auxtools_shutdown")();\ + call_ext(LIB,"auxtools_shutdown")();\ GLOB.auxtools_initialized[LIB] = AUXTOOLS_PARTIAL_INIT;\ }\ #define AUXTOOLS_FULL_SHUTDOWN(LIB)\ if (GLOB.auxtools_initialized[LIB] && fexists(LIB)){\ - LIBCALL(LIB,"auxtools_full_shutdown")();\ + call_ext(LIB,"auxtools_full_shutdown")();\ GLOB.auxtools_initialized[LIB] = FALSE;\ } diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index 26e80415c6aa..05f099b7284f 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -142,6 +142,8 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) log_shuttle(log_text) if(LOG_MECHCOMP) log_mechcomp(log_text) + if(LOG_BLACKMARKET) + log_blackmarket(log_text) if(LOG_SPEECH_INDICATORS) log_speech_indicators(log_text) else @@ -263,3 +265,6 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) /proc/log_mechcomp(text, list/data) logger.Log(LOG_CATEGORY_MECHCOMP, text, data) + +/proc/log_blackmarket(text, list/data) + logger.Log(LOG_CATEGORY_BLACKMARKET, text, data) diff --git a/code/__HELPERS/nameof.dm b/code/__HELPERS/nameof.dm index 7cd5777f4652..5a2fd60e7100 100644 --- a/code/__HELPERS/nameof.dm +++ b/code/__HELPERS/nameof.dm @@ -8,8 +8,4 @@ /** * NAMEOF that actually works in static definitions because src::type requires src to be defined */ -#if DM_VERSION >= 515 #define NAMEOF_STATIC(datum, X) (nameof(type::##X)) -#else -#define NAMEOF_STATIC(datum, X) (#X || ##datum.##X) -#endif diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm index cf84b77b7472..e2dcd29c8189 100644 --- a/code/__byond_version_compat.dm +++ b/code/__byond_version_compat.dm @@ -1,52 +1,21 @@ // This file contains defines allowing targeting byond versions newer than the supported //Update this whenever you need to take advantage of more recent byond features -#define MIN_COMPILER_VERSION 514 -#define MIN_COMPILER_BUILD 1556 +#define MIN_COMPILER_VERSION 515 +#define MIN_COMPILER_BUILD 1609 #if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) //Don't forget to update this part #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update. -#error You need version 514.1556 or higher +#error You need version 515.1609 or higher #endif -#if (DM_VERSION == 514 && DM_BUILD > 1575 && DM_BUILD <= 1577) -#error Your version of BYOND currently has a crashing issue that will prevent you from running Dream Daemon test servers. -#error We require developers to test their content, so an inability to test means we cannot allow the compile. -#error Please consider downgrading to 514.1575 or lower. -#endif // Keep savefile compatibilty at minimum supported level -#if DM_VERSION >= 515 /savefile/byond_version = MIN_COMPILER_VERSION -#endif - -// 515 split call for external libraries into call_ext -#if DM_VERSION < 515 -#define LIBCALL call -#else -#define LIBCALL call_ext -#endif // So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof() // For the record: GLOBAL_VERB_REF would be useless as verbs can't be global. -#if DM_VERSION < 515 - -/// Call by name proc references, checks if the proc exists on either this type or as a global proc. -#define PROC_REF(X) (.proc/##X) -/// Call by name verb references, checks if the verb exists on either this type or as a global verb. -#define VERB_REF(X) (.verb/##X) - -/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc -#define TYPE_PROC_REF(TYPE, X) (##TYPE.proc/##X) -/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb -#define TYPE_VERB_REF(TYPE, X) (##TYPE.verb/##X) - -/// Call by name proc reference, checks if the proc is an existing global proc -#define GLOBAL_PROC_REF(X) (/proc/##X) - -#else - /// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (nameof(.proc/##X)) /// Call by name verb references, checks if the verb exists on either this type or as a global verb. @@ -60,4 +29,11 @@ /// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) -#endif +/// fcopy will crash on 515 linux if given a non-existant file, instead of returning 0 like on 514 linux or 515 windows +/// var case matches documentation for fcopy. +/world/proc/__fcopy(Src, Dst) + if (istext(Src) && !fexists(Src)) + return 0 + return fcopy(Src, Dst) + +#define fcopy(Src, Dst) world.__fcopy(Src, Dst) diff --git a/code/_experiments.dm b/code/_experiments.dm index dfb7ec0a1672..ef2240406ed2 100644 --- a/code/_experiments.dm +++ b/code/_experiments.dm @@ -11,24 +11,15 @@ #if DM_VERSION < 515 -// You can't X-macro custom names :( -#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE -#warn EXPERIMENT_515_QDEL_HARD_REFERENCE is only available on 515+ -#undef EXPERIMENT_515_QDEL_HARD_REFERENCE -#endif - -#ifdef EXPERIMENT_515_DONT_CACHE_REF -#warn EXPERIMENT_515_DONT_CACHE_REF is only available on 515+ -#undef EXPERIMENT_515_DONT_CACHE_REF -#endif - + // You can't X-macro custom names :( + #ifdef EXPERIMENT_MY_COOL_FEATURE + #warn EXPERIMENT_MY_COOL_FEATURE is only available on 515+ + #undef EXPERIMENT_MY_COOL_FEATURE + #endif #elif defined(UNIT_TESTS) - -#define EXPERIMENT_515_QDEL_HARD_REFERENCE -#define EXPERIMENT_515_DONT_CACHE_REF - + #define EXPERIMENT_MY_COOL_FEATURE #endif #if DM_VERSION >= 516 -#error "Remove all 515 experiments" + #error "Remove all 515 experiments" #endif diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index dd9b41aacc36..c593a8e7744e 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -14,7 +14,14 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) GLOB = src var/datum/controller/exclude_these = new - gvars_datum_in_built_vars = exclude_these.vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order)) + // I know this is dumb but the nested vars list hangs a ref to the datum. This fixes that + var/list/controller_vars = exclude_these.vars.Copy() + controller_vars["vars"] = null + gvars_datum_in_built_vars = controller_vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order)) + +#if DM_VERSION >= 515 && DM_BUILD > 1620 + #warn datum.vars hanging a ref should now be fixed, there should be no reason to remove the vars list from our controller's vars list anymore +#endif QDEL_IN(exclude_these, 0) //signal logging isn't ready Initialize() diff --git a/code/controllers/subsystem/blackmarket.dm b/code/controllers/subsystem/blackmarket.dm index 357fa0df2915..997794f5901e 100644 --- a/code/controllers/subsystem/blackmarket.dm +++ b/code/controllers/subsystem/blackmarket.dm @@ -7,7 +7,8 @@ SUBSYSTEM_DEF(blackmarket) var/shipping_method_descriptions = list( SHIPPING_METHOD_LAUNCH="Launches the item at the station from space, cheap but you might not receive your item at all.", SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that receives items outside the station and then teleports them to the location of the uplink.", - SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though." + SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though.", + SHIPPING_METHOD_AT_FEET="Teleports the item to your feet." ) /// List of all existing markets. @@ -18,7 +19,7 @@ SUBSYSTEM_DEF(blackmarket) var/list/queued_purchases = list() /datum/controller/subsystem/blackmarket/Initialize() - for(var/market in subtypesof(/datum/market)) + for(var/market in subtypesof(/datum/market) - /datum/market/auction - /datum/market/restock) //monkestation edit - MODULAR_GUNS markets[market] += new market for(var/item in subtypesof(/datum/market_item)) @@ -35,6 +36,12 @@ SUBSYSTEM_DEF(blackmarket) return SS_INIT_SUCCESS /datum/controller/subsystem/blackmarket/fire(resumed) + for(var/market in markets) //monkestation edit - MODULAR_GUNS + var/datum/market/listed_market = markets[market] + if(!(listed_market.market_flags & MARKET_PROCESS)) + continue + listed_market.try_process() + while(length(queued_purchases)) var/datum/market_purchase/purchase = queued_purchases[1] queued_purchases.Cut(1,2) @@ -95,6 +102,14 @@ SUBSYSTEM_DEF(blackmarket) queued_purchases -= purchase qdel(purchase) + if(SHIPPING_METHOD_AT_FEET) + var/turf/targetturf = get_turf(purchase.uplink) + if (!targetturf) + continue + + fake_teleport(purchase.entry.spawn_item(), targetturf) + queued_purchases -= purchase + qdel(purchase) if(MC_TICK_CHECK) break diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index ae50c123cb0a..c4d81da7a0e0 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -139,13 +139,6 @@ SUBSYSTEM_DEF(garbage) pass_counts[i] = 0 fail_counts[i] = 0 -#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE -// 1 from the hard reference in the queue, and 1 from the variable used before this -#define IS_DELETED(datum, _) (refcount(##datum) == 2) -#else -#define IS_DELETED(datum, gcd_at_time) (isnull(##datum) || ##datum.gc_destroyed != gcd_at_time) -#endif - /datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_FILTER) if (level == GC_QUEUE_FILTER) delslasttick = 0 @@ -177,17 +170,11 @@ SUBSYSTEM_DEF(garbage) break // Everything else is newer, skip them count++ -#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE var/datum/D = L[GC_QUEUE_ITEM_REF] -#else - var/GCd_at_time = L[GC_QUEUE_ITEM_GCD_DESTROYED] - - var/refID = L[GC_QUEUE_ITEM_REF] - var/datum/D - D = locate(refID) -#endif + // 1 from the hard reference in the queue, and 1 from the variable used before this + // If that's all we've got, send er off + if (refcount(D) == 2) - if (IS_DELETED(D, GCd_at_time)) // So if something else coincidently gets the same ref, it's not deleted by mistake ++gcedlasttick ++totalgcs pass_counts[level]++ @@ -222,9 +209,9 @@ SUBSYSTEM_DEF(garbage) var/datum/qdel_item/I = items[type] var/message = "## TESTING: GC: -- [text_ref(D)] | [type] was unable to be GC'd --" -#if DM_VERSION >= 515 + message = "[message] (ref count of [refcount(D)])" -#endif + log_world(message) #ifdef TESTING @@ -261,8 +248,6 @@ SUBSYSTEM_DEF(garbage) queue.Cut(1,count+1) count = 0 -#undef IS_DELETED - /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) if (isnull(D)) return @@ -271,17 +256,11 @@ SUBSYSTEM_DEF(garbage) return var/queue_time = world.time -#ifdef EXPERIMENT_515_QDEL_HARD_REFERENCE - var/refid = D -#else - var/refid = text_ref(D) -#endif if (D.gc_destroyed <= 0) D.gc_destroyed = queue_time - - var/list/queue = queues[level] - queue[++queue.len] = list(queue_time, refid, D.gc_destroyed) // not += for byond reasons + var/list/queue = queues[level] + queue[++queue.len] = list(queue_time, D, D.gc_destroyed) // not += for byond reasons //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 510aacea673b..0a63e31edc9c 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -70,6 +70,9 @@ multiple modular subtrees with behaviors /datum/ai_controller/Destroy(force, ...) set_ai_status(AI_STATUS_OFF) UnpossessPawn(FALSE) + set_movement_target(type, null) + if(ai_movement.moving_controllers[src]) + ai_movement.stop_moving_towards(src) return ..() ///Sets the current movement target, with an optional param to override the movement behavior @@ -118,6 +121,7 @@ multiple modular subtrees with behaviors reset_ai_status() RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) + RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted)) /// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere /datum/ai_controller/proc/reset_ai_status() @@ -152,7 +156,7 @@ multiple modular subtrees with behaviors if(isnull(pawn)) return // instantiated without an applicable pawn, fine - UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE)) + UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) pawn.ai_controller = null @@ -227,6 +231,8 @@ multiple modular subtrees with behaviors ///Determines whether the AI can currently make a new plan /datum/ai_controller/proc/able_to_plan() . = TRUE + if(QDELETED(pawn)) + return FALSE for(var/datum/ai_behavior/current_behavior as anything in current_behaviors) if(!(current_behavior.behavior_flags & AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION)) //We have a behavior that blocks planning . = FALSE @@ -331,6 +337,14 @@ multiple modular subtrees with behaviors set_ai_status(AI_STATUS_ON) //Can't do anything while player is connected RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) +// Turn the controller off the controller if the pawn has been qdeleted +/datum/ai_controller/proc/on_pawn_qdeleted() + SIGNAL_HANDLER + set_ai_status(AI_STATUS_OFF) + set_movement_target(type, null) + if(ai_movement.moving_controllers[src]) + ai_movement.stop_moving_towards(src) + /// Use this proc to define how your controller defines what access the pawn has for the sake of pathfinding. Return the access list you want to use /datum/ai_controller/proc/get_access() return diff --git a/code/datums/ai/babies/babies_behaviors.dm b/code/datums/ai/babies/babies_behaviors.dm index daaa3b407b75..4b56d0706956 100644 --- a/code/datums/ai/babies/babies_behaviors.dm +++ b/code/datums/ai/babies/babies_behaviors.dm @@ -75,4 +75,6 @@ if(!succeeded) return var/mob/living/living_pawn = controller.pawn + if(QDELETED(living_pawn)) // pawn can be null at this point + return living_pawn.istate = initial(living_pawn.istate) diff --git a/code/datums/ai/bane/bane_behaviors.dm b/code/datums/ai/bane/bane_behaviors.dm index aff24ac12e1d..4914968a03bb 100644 --- a/code/datums/ai/bane/bane_behaviors.dm +++ b/code/datums/ai/bane/bane_behaviors.dm @@ -2,5 +2,7 @@ if(succeeded) var/list/bane_quotes = strings("bane.json", "bane") var/mob/living/bane = controller.pawn + if(QDELETED(bane)) // pawn can be null at this point + return ..() bane.say(pick(bane_quotes)) return ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm index bb9010660257..c8c18072a4aa 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm @@ -25,6 +25,8 @@ . = ..() var/obj/structure/flora/target_tree = controller.blackboard[target_key] var/mob/living/basic/living_pawn = controller.pawn + if(QDELETED(living_pawn)) // pawn can be null at this point + return SEND_SIGNAL(living_pawn, COMSIG_LIVING_CLIMB_TREE, target_tree) finish_action(controller, TRUE, target_key) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm index d0fb7e3e8c70..655b335d3b63 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm @@ -4,11 +4,11 @@ . = ..() var/mob/living/living_pawn = controller.pawn - var/atom/movable/buckled_too = living_pawn.buckled + var/atom/movable/buckled_to = living_pawn.buckled - if(isnull(buckled_too)) + if(isnull(buckled_to)) finish_action(controller, FALSE) return - buckled_too.unbuckle_mob(living_pawn) + buckled_to.unbuckle_mob(living_pawn) finish_action(controller, TRUE) diff --git a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm index 584fb984839f..c7153b0c12f7 100644 --- a/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm +++ b/code/datums/ai/basic_mobs/pet_commands/pet_use_targeted_ability.dm @@ -16,7 +16,7 @@ finish_action(controller, FALSE, ability_key, target_key) return var/mob/pawn = controller.pawn - if (ability.InterceptClickOn(pawn, null, target)) + if(QDELETED(pawn) || ability.InterceptClickOn(pawn, null, target)) finish_action(controller, TRUE, ability_key, target_key) /datum/ai_behavior/pet_use_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key) diff --git a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm index 8e46e54a65f1..3aed57fb35c2 100644 --- a/code/datums/ai/basic_mobs/pet_commands/play_dead.dm +++ b/code/datums/ai/basic_mobs/pet_commands/play_dead.dm @@ -18,7 +18,7 @@ /datum/ai_behavior/play_dead/finish_action(datum/ai_controller/controller, succeeded) . = ..() var/mob/living/basic/basic_pawn = controller.pawn - if(!istype(basic_pawn) || basic_pawn.stat) // imagine actually dying while playing dead. hell, imagine being the kid waiting for your pup to get back up :( + if(QDELETED(basic_pawn) || basic_pawn.stat) // imagine actually dying while playing dead. hell, imagine being the kid waiting for your pup to get back up :( return basic_pawn.visible_message(span_notice("[basic_pawn] miraculously springs back to life!")) REMOVE_TRAIT(basic_pawn, TRAIT_FAKEDEATH, "basic_death") diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index 7e383d304afd..9a4cba2da6c5 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -67,6 +67,8 @@ /datum/ai_behavior/break_spine/finish_action(datum/ai_controller/controller, succeeded, target_key) if(succeeded) var/mob/living/bane = controller.pawn + if(QDELETED(bane)) // pawn can be null at this point + return ..() bane.stop_pulling() controller.clear_blackboard_key(target_key) return ..() @@ -287,8 +289,6 @@ . = ..() controller.clear_blackboard_key(BB_FOLLOW_TARGET) - - /datum/ai_behavior/perform_emote /datum/ai_behavior/perform_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote) diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index e2a2a4ae1f75..77aa49dd6c55 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -166,8 +166,10 @@ /datum/ai_behavior/monkey_attack_mob/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() var/mob/living/living_pawn = controller.pawn - SSmove_manager.stop_looping(living_pawn) controller.clear_blackboard_key(target_key) + if(QDELETED(living_pawn)) // pawn can be null at this point + return + SSmove_manager.stop_looping(living_pawn) /// attack using a held weapon otherwise bite the enemy, then if we are angry there is a chance we might calm down a little /datum/ai_behavior/monkey_attack_mob/proc/monkey_attack(datum/ai_controller/controller, mob/living/target, seconds_per_tick, disarm) @@ -222,6 +224,12 @@ // note they might immediately reduce threat and drop from the list. // this is fine, we're just giving them a love tap then leaving them alone. // unless they fight back, then we retaliate + + // Some mobs delete on death. If the target is no longer alive, go back to idle + if(QDELETED(target)) + finish_action(controller, TRUE) + return + if(isnull(controller.blackboard[BB_MONKEY_ENEMIES][target])) controller.set_blackboard_key_assoc(BB_MONKEY_ENEMIES, target, 1) @@ -300,7 +308,7 @@ var/mob/living/living_pawn = controller.pawn for(var/mob/living/nearby_monkey in view(living_pawn, MONKEY_ENEMY_VISION)) - if(!HAS_AI_CONTROLLER_TYPE(nearby_monkey, /datum/ai_controller/monkey)) + if(QDELETED(nearby_monkey) || !HAS_AI_CONTROLLER_TYPE(nearby_monkey, /datum/ai_controller/monkey)) continue if(!SPT_PROB(MONKEY_RECRUIT_PROB, seconds_per_tick)) continue diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index fdd82c0d3bd7..fc7e7a02a7d5 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -5,6 +5,7 @@ have ways of interacting with a specific mob and control it. ///OOK OOK OOK /datum/ai_controller/monkey + ai_movement = /datum/ai_movement/basic_avoidance movement_delay = 0.4 SECONDS planning_subtrees = list( /datum/ai_planning_subtree/generic_resist, @@ -146,11 +147,15 @@ have ways of interacting with a specific mob and control it. return TRUE ///Reactive events to being hit -/datum/ai_controller/monkey/proc/retaliate(mob/living/L) - if(HAS_TRAIT(L, TRAIT_MONKEYFRIEND)) - REMOVE_TRAIT(L, TRAIT_MONKEYFRIEND, SPECIES_TRAIT) - addtimer(CALLBACK(GLOBAL_PROC, /proc/monkeyfriend_check, L), 60 SECONDS) - add_blackboard_key_assoc(BB_MONKEY_ENEMIES, L, MONKEY_HATRED_AMOUNT) +/datum/ai_controller/monkey/proc/retaliate(mob/living/living_mob) + // just to be safe + if(QDELETED(living_mob)) + return + + add_blackboard_key_assoc(BB_MONKEY_ENEMIES, living_mob, MONKEY_HATRED_AMOUNT) + if(HAS_TRAIT(living_mob, TRAIT_MONKEYFRIEND)) + REMOVE_TRAIT(living_mob, TRAIT_MONKEYFRIEND, SPECIES_TRAIT) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(monkeyfriend_check), living_mob), 60 SECONDS) /proc/monkeyfriend_check(mob/living/user) var/obj/item/clothing/suit/costume/monkeysuit/S diff --git a/code/datums/ai/robot_customer/robot_customer_behaviors.dm b/code/datums/ai/robot_customer/robot_customer_behaviors.dm index e370af6f5c1f..735b795e6066 100644 --- a/code/datums/ai/robot_customer/robot_customer_behaviors.dm +++ b/code/datums/ai/robot_customer/robot_customer_behaviors.dm @@ -103,7 +103,7 @@ var/mob/living/greytider = controller.blackboard[BB_CUSTOMER_CURRENT_TARGET] //usually if we stop waiting, it's because we're done with the venue. but here we're either beating some dude up //or are being qdeleted and don't want runtime errors, so don't switch to leaving - if(greytider || QDELETED(src)) + if(greytider || QDELETED(src) || QDELETED(customer_pawn)) return controller.set_blackboard_key(BB_CUSTOMER_LEAVING, TRUE) customer_pawn.update_icon() //They might have a special leaving accesoiry (french flag) diff --git a/code/datums/callback.dm b/code/datums/callback.dm index a51639d0b9b1..8efd3a43a391 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -89,12 +89,6 @@ if (!object) return -#if DM_VERSION <= 514 - if(istext(object) && object != GLOBAL_PROC) - to_chat(usr, "[object] may be an external library. Calling external libraries is disallowed.", confidential = TRUE) - return -#endif - var/list/calling_arguments = arguments if (length(args)) if (length(arguments)) @@ -132,12 +126,6 @@ if (!object) return -#if DM_VERSION <= 514 - if(istext(object) && object != GLOBAL_PROC) - to_chat(usr, "[object] may be an external library. Calling external libraries is disallowed.", confidential = TRUE) - return -#endif - var/list/calling_arguments = arguments if (length(args)) if (length(arguments)) diff --git a/code/datums/components/customizable_reagent_holder.dm b/code/datums/components/customizable_reagent_holder.dm index 96e36ca8d8a4..4d7d54787f38 100644 --- a/code/datums/components/customizable_reagent_holder.dm +++ b/code/datums/components/customizable_reagent_holder.dm @@ -154,7 +154,7 @@ if(job && job_xp) if(attacker.client?.prefs) - add_jobxp_chance_delayed_check(attacker.client, job_xp, job, 60, FALSE) + add_jobxp_chance_delayed_check(attacker.client, job_xp, job, 40, FALSE) handle_reagents(ingredient) add_ingredient(ingredient) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 9b5c91328148..ec0154c5ffe8 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -40,13 +40,6 @@ /// Datum level flags var/datum_flags = NONE -#ifndef EXPERIMENT_515_DONT_CACHE_REF - /// A cached version of our \ref - /// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings) - /// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled - var/cached_ref -#endif - /// A weak reference to another datum var/datum/weakref/weak_reference diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 06e2c1e18d65..c3562aa59873 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -37,6 +37,8 @@ else if(!originmastercommit) msg += "No commit information" + msg += "Running rust-g version [rustg_get_version()]" + return msg.Join("\n") /datum/getrev/proc/GetTestMergeInfo(header = TRUE) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index e8b4b6f9c7f0..b7c3b7a2f69f 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -752,7 +752,10 @@ . += "It contains [round(reagents.total_volume, 0.01)] units of various reagents[user_sees_reagents ? ":" : "."]" if(user_sees_reagents) //Show each individual reagent for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) - . += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + var/reagent_name = current_reagent.name + if(istype(current_reagent, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + reagent_name = "Ammonia?" + . += "• [round(current_reagent.volume, 0.01)] units of [reagent_name]" if(reagents.is_reacting) . += span_warning("It is currently reacting!") . += span_notice("The solution's pH is [round(reagents.ph, 0.01)] and has a temperature of [reagents.chem_temp]K.") diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm index 9c5455c1edd1..5344cddf283d 100644 --- a/code/game/objects/items/devices/portable_chem_mixer.dm +++ b/code/game/objects/items/devices/portable_chem_mixer.dm @@ -188,7 +188,10 @@ var/beakerContents[0] if(beaker) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume, "pH" = R.ph))) // list in a list because Byond merges the first list... + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + beakerContents.Add(list(list("name" = chem_name, "id" = ckey(R.name), "volume" = R.volume, "pH" = R.ph))) // list in a list because Byond merges the first list... data["beakerCurrentpH"] = round(beaker.reagents.ph, 0.01) data["beakerContents"] = beakerContents diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 2e5f404b5849..4d0b8b2ce6a5 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -189,6 +189,8 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) return /mob/proc/set_machine(obj/O) + if(QDELETED(src) || QDELETED(O)) + return if(machine) unset_machine() machine = O diff --git a/code/game/sound.dm b/code/game/sound.dm index b14a9ee2155b..f2b701b0da6f 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -24,6 +24,7 @@ GLOBAL_LIST_INIT(proxy_sound_channels, list( CHANNEL_INSTRUMENTS, CHANNEL_INSTRUMENTS_ROBOT, CHANNEL_MOB_SOUNDS, + CHANNEL_PRUDE, )) @@ -149,6 +150,9 @@ GLOBAL_LIST_INIT(proxy_sound_channels, list( if("[CHANNEL_MASTER_VOLUME]" in client?.prefs?.channel_volume) sound_to_use.volume *= client.prefs.channel_volume["[CHANNEL_MASTER_VOLUME]"] * 0.01 + if((mixer_channel == CHANNEL_PRUDE) && client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + sound_to_use.volume *= 0 + if(vary) if(frequency) sound_to_use.frequency = frequency diff --git a/code/game/world.dm b/code/game/world.dm index 45c63e3d3772..33e8e51764ed 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -341,7 +341,7 @@ GLOBAL_VAR(restart_counter) AUXTOOLS_FULL_SHUTDOWN(AUXLUA) var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (debug_server) - LIBCALL(debug_server, "auxtools_shutdown")() + call_ext(debug_server, "auxtools_shutdown")() /world/Del() auxcleanup() @@ -470,14 +470,14 @@ GLOBAL_VAR(restart_counter) else CRASH("Unsupported platform: [system_type]") - var/init_result = LIBCALL(library, "init")("block") + var/init_result = call_ext(library, "init")("block") if (init_result != "0") CRASH("Error initializing byond-tracy: [init_result]") /world/proc/init_debugger() var/dll = GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (dll) - LIBCALL(dll, "auxtools_init")() + call_ext(dll, "auxtools_init")() enable_debugging() /world/Profile(command, type, format) diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index a5b2af68c772..6be224cdd86f 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -26,9 +26,7 @@ var/starting_time = world.time -#if DM_VERSION >= 515 log_reftracker("Refcount for [type]: [refcount(src)]") -#endif //Time to search the whole game for our ref DoSearchVar(GLOB, "GLOB", search_time = starting_time) //globals diff --git a/code/modules/antagonists/pirate/pirate_event.dm b/code/modules/antagonists/pirate/pirate_event.dm index 73372814aeb2..66edd83dc672 100644 --- a/code/modules/antagonists/pirate/pirate_event.dm +++ b/code/modules/antagonists/pirate/pirate_event.dm @@ -9,7 +9,7 @@ description = "The crew will either pay up, or face a pirate assault." admin_setup = list(/datum/event_admin_setup/listed_options/pirates) map_flags = EVENT_SPACE_ONLY - track = EVENT_TRACK_MAJOR + track = EVENT_TRACK_ROLESET tags = list(TAG_COMBAT, TAG_COMMUNAL) checks_antag_cap = TRUE diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 290e9616f98f..09dd406fefab 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -470,7 +470,7 @@ ui = new(user, src, "Cryo", name) ui.open() -/obj/machinery/atmospherics/components/unary/cryo_cell/ui_data() +/obj/machinery/atmospherics/components/unary/cryo_cell/ui_data(mob/user) var/list/data = list() data["isOperating"] = on data["hasOccupant"] = occupant ? TRUE : FALSE @@ -512,7 +512,10 @@ var/beakerContents = list() if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents += list(list("name" = R.name, "volume" = R.volume)) + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + beakerContents += list(list("name" = chem_name, "volume" = R.volume)) data["beakerContents"] = beakerContents return data diff --git a/code/modules/cargo/markets/_market.dm b/code/modules/cargo/markets/_market.dm index 3c264289cd2b..9d1426e83f84 100644 --- a/code/modules/cargo/markets/_market.dm +++ b/code/modules/cargo/markets/_market.dm @@ -10,6 +10,8 @@ var/list/available_items = list() /// Item categories available from this market, only items which are in these categories can be gotten from this market. Automatically assigned, so don't manually adjust. var/list/categories = list() + /// flags we want to add to markets + var/market_flags = NONE /// Adds item to the available items and add it's category if it is not in categories yet. /datum/market/proc/add_item(datum/market_item/item) @@ -26,6 +28,13 @@ available_items[item.category] += item return TRUE +/datum/market/proc/try_process() + return + +///called before purchase override if you want to potentially stop purchases //monkestation edit - MODULAR_GUNS +/datum/market/proc/pre_purchase(item, category, method, obj/item/market_uplink/uplink, user) + purchase(item, category, method, uplink, user) + /// Handles buying the item, this is mainly for future use and moving the code away from the uplink. /datum/market/proc/purchase(item, category, method, obj/item/market_uplink/uplink, user) if(!istype(uplink) || !(method in shipping)) @@ -48,6 +57,7 @@ if(I.buy(uplink, user, method)) uplink.current_user.adjust_money(-price, "Other: Third Party Transaction") + logger.Log(LOG_CATEGORY_BLACKMARKET, "[user] has just bought the [I] for [price] in the [name]") if(ismob(user)) var/mob/m_user = user m_user.playsound_local(get_turf(m_user), 'sound/machines/twobeep_high.ogg', 50, TRUE) diff --git a/code/modules/cargo/markets/market_item.dm b/code/modules/cargo/markets/market_item.dm index 867facf015b9..cd4279ef40c3 100644 --- a/code/modules/cargo/markets/market_item.dm +++ b/code/modules/cargo/markets/market_item.dm @@ -68,6 +68,8 @@ /// Shipping method used to buy this item. var/method + +//needs to be here /datum/market_purchase/New(_entry, _uplink, _method) entry = _entry if(!ispath(entry.item)) diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm index 19c1a049a1be..4095078da5e7 100644 --- a/code/modules/cargo/markets/market_uplink.dm +++ b/code/modules/cargo/markets/market_uplink.dm @@ -16,7 +16,9 @@ ///Reference to the currently logged in user's bank account. var/datum/bank_account/current_user /// List of typepaths for "/datum/market"s that this uplink can access. - var/list/accessible_markets = list(/datum/market/blackmarket) + var/list/accessible_markets = list(/datum/market/blackmarket, /datum/market/auction/guns, /datum/market/restock/guns_galore) + ///our current_bid + var/current_bid = 0 /obj/item/market_uplink/Initialize(mapload) . = ..() @@ -66,16 +68,41 @@ data["items"] = list() data["viewing_category"] = viewing_category data["viewing_market"] = viewing_market + data["current_bid"] = current_bid if(viewing_category && market) - if(market.available_items[viewing_category]) - for(var/datum/market_item/I in market.available_items[viewing_category]) - data["items"] += list(list( - "id" = I.type, - "name" = I.name, - "cost" = I.price, - "amount" = I.stock, - "desc" = I.desc || I.name + if(market.market_flags & MARKET_AUCTION) + var/datum/market/auction/market_auction = market + data["auction"] = TRUE + for(var/datum/market_item/auction/item in market_auction.queued_items) + data["queued_items"] += list(list( + "time_until_auction" = market_auction.queued_items[item] - world.time, + "name" = item.name, + "id" = item.type, + "starting_cost" = item.price, )) + data["bidders"] = list() + if(market_auction.current_auction) + data["current_item"] = list( + "name" = market_auction.current_auction?.name, + "id" = market_auction.current_auction?.type, + "desc" = market_auction.current_auction?.desc || market_auction?.current_auction.name, + "cost" = market_auction.current_auction?.price, + "top_bidder" = market_auction.current_auction?.top_bidder + ) + data["bidders"] = market_auction.current_auction?.bidders + + data["time_left"] = COOLDOWN_TIMELEFT(market_auction, current_auction_time) + else + if(market.available_items[viewing_category]) + for(var/datum/market_item/I in market.available_items[viewing_category]) + data["auction"] = FALSE + data["items"] += list(list( + "id" = I.type, + "name" = I.name, + "cost" = I.price, + "amount" = I.stock, + "desc" = I.desc || I.name, + )) return data /obj/item/market_uplink/ui_static_data(mob/user) @@ -138,10 +165,29 @@ buying = FALSE return var/datum/market/market = SSblackmarket.markets[viewing_market] - market.purchase(selected_item, viewing_category, params["method"], src, usr) + market.pre_purchase(selected_item, viewing_category, params["method"], src, usr, current_bid) // monkestation edit - MODULAR_GUNS buying = FALSE selected_item = null + if("set_bid") + if(isnull(params["bid"])) + return + current_bid = params["bid"] + if("bid") + var/datum/market/auction/market = SSblackmarket.markets[viewing_market] + if(!istype(market)) + return + if(!market.current_auction) + return + selected_item = market.current_auction.type + if(isnull(selected_item)) + return + market.pre_purchase(selected_item, viewing_category, params["method"], src, usr, current_bid) + if("reroll") + var/datum/market/auction/market = SSblackmarket.markets[viewing_market] + if(!istype(market)) + return + market.reroll(src, usr) /obj/item/market_uplink/blackmarket name = "\improper Black Market Uplink" @@ -149,7 +195,7 @@ icon = 'icons/obj/blackmarket.dmi' icon_state = "uplink" //The original black market uplink - accessible_markets = list(/datum/market/blackmarket) + accessible_markets = list(/datum/market/blackmarket, /datum/market/auction/guns, /datum/market/restock/guns_galore) /datum/crafting_recipe/blackmarket_uplink diff --git a/code/modules/clothing/outfits/vv_outfit.dm b/code/modules/clothing/outfits/vv_outfit.dm index 1740094fe3d2..ec4596341155 100644 --- a/code/modules/clothing/outfits/vv_outfit.dm +++ b/code/modules/clothing/outfits/vv_outfit.dm @@ -48,9 +48,6 @@ //Temporary/Internal stuff, do not copy these. var/static/list/ignored_vars = list( NAMEOF(item, animate_movement), -#ifndef EXPERIMENT_515_DONT_CACHE_REF - NAMEOF(item, cached_ref), -#endif NAMEOF(item, datum_flags), NAMEOF(item, fingerprintslast), NAMEOF(item, layer), diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 48e3f583e07b..09f232c2149d 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -51,7 +51,7 @@ var/calculated_weight = 0 var/tags = list() /// Tags of the event /// List of the shared occurence types. - var/static/list/shared_occurences = list() + var/list/shared_occurences = list() /// Whether a roundstart event can happen post roundstart. Very important for events which override job assignments. var/can_run_post_roundstart = TRUE /// If set then the type or list of types of storytellers we are restricted to being trigged by diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm index 04f73e2ffa7c..0215f9dc1a20 100644 --- a/code/modules/food_and_drinks/machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm @@ -66,7 +66,10 @@ if(beaker) dat += "BEAKER CONTENT
" for(var/datum/reagent/R in beaker.reagents.reagent_list) - dat += "[R.name]: [R.volume]u
" + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + dat += "[chem_name]: [R.volume]u
" dat += "Refill from beaker
" dat += "
" dat += "VAT CONTENT
" diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 8a7cdd1b2e14..ab0280e7fecd 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -277,7 +277,7 @@ product_count = 10 + log(1.02) * (getYield() - 1) if(user.client) - add_jobxp_chance(user.client, 1, JOB_BOTANIST, 50) + add_jobxp_chance(user.client, 1, JOB_BOTANIST, 20) while(t_amount < product_count) if(prob(25)) diff --git a/code/modules/logging/categories/log_category_internal.dm b/code/modules/logging/categories/log_category_internal.dm new file mode 100644 index 000000000000..d0b363e63655 --- /dev/null +++ b/code/modules/logging/categories/log_category_internal.dm @@ -0,0 +1,6 @@ +/datum/log_category/internal + category = LOG_CATEGORY_INTERNAL_ERROR + +/datum/log_category/internal_unknown_category + category = LOG_CATEGORY_INTERNAL_CATEGORY_NOT_FOUND + master_category = /datum/log_category/internal diff --git a/code/modules/logging/categories/log_category_monke.dm b/code/modules/logging/categories/log_category_monke.dm index 6dcf38cb93f9..659f3efbe70a 100644 --- a/code/modules/logging/categories/log_category_monke.dm +++ b/code/modules/logging/categories/log_category_monke.dm @@ -29,3 +29,10 @@ config_flag = /datum/config_entry/flag/artifact /datum/config_entry/flag/artifact + +/datum/log_category/blackmarket + category = LOG_CATEGORY_BLACKMARKET + master_category = /datum/log_category/economy + config_flag = /datum/config_entry/flag/blackmarket + +/datum/config_entry/flag/blackmarket diff --git a/code/modules/logging/log_category.dm b/code/modules/logging/log_category.dm index 467c0aa58b13..359f9d47f249 100644 --- a/code/modules/logging/log_category.dm +++ b/code/modules/logging/log_category.dm @@ -16,6 +16,9 @@ /// Whether or not this log should not be publically visible var/secret = FALSE + /// The list of header information for this category. Used for log file re-initialization + var/list/category_header + /// Whether the readable version of the log message is formatted internally instead of by rustg var/internal_formatting = TRUE @@ -27,10 +30,6 @@ GENERAL_PROTECT_DATUM(/datum/log_category) -/// Backup log category to catch attempts to log to a category that doesn't exist -/datum/log_category/backup_category_not_found - category = LOG_CATEGORY_NOT_FOUND - /// Add an entry to this category. It is very important that any data you provide doesn't hold references to anything! /datum/log_category/proc/create_entry(message, list/data, list/semver_store) var/datum/log_entry/entry = new( diff --git a/code/modules/logging/log_entry.dm b/code/modules/logging/log_entry.dm index 75b809e5297f..df87f9330987 100644 --- a/code/modules/logging/log_entry.dm +++ b/code/modules/logging/log_entry.dm @@ -85,19 +85,33 @@ GENERAL_PROTECT_DATUM(/datum/log_entry) #undef MANUAL_JSON_ENTRY +#define CHECK_AND_TRY_FILE_ERROR_RECOVERY(file) \ + var/static/in_error_recovery = FALSE; \ + if(!fexists(##file)) { \ + if(in_error_recovery) { \ + in_error_recovery = FALSE; \ + CRASH("Failed to error recover log file: [file]"); \ + }; \ + in_error_recovery = TRUE; \ + logger.Log(LOG_CATEGORY_INTERNAL_ERROR, "attempting to perform file error recovery: [file]"); \ + logger.init_category_file(logger.log_categories[category]); \ + call(src, __PROC__)(arglist(args)); \ + return; \ + }; \ + in_error_recovery = FALSE; + /// Writes the log entry to a file. /datum/log_entry/proc/write_entry_to_file(file) - if(!fexists(file)) - CRASH("Attempted to log to an uninitialized file: [file]") + CHECK_AND_TRY_FILE_ERROR_RECOVERY(file) WRITE_LOG_NO_FORMAT(file, "[to_json_text()]\n") /// Writes the log entry to a file as a human-readable string. /datum/log_entry/proc/write_readable_entry_to_file(file, format_internally = TRUE) - if(!fexists(file)) - CRASH("Attempted to log to an uninitialized file: [file]") - + CHECK_AND_TRY_FILE_ERROR_RECOVERY(file) // If it's being formatted internally we need to manually add a newline if(format_internally) WRITE_LOG_NO_FORMAT(file, "[to_readable_text(format = TRUE)]\n") else WRITE_LOG(file, "[to_readable_text(format = FALSE)]") + +#undef CHECK_AND_TRY_FILE_ERROR_RECOVERY diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index 204079cc90c1..c9b94b40c4e5 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -206,6 +206,42 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) return category_tree +/// Log entry header used to mark a file is being reset +#define LOG_CATEGORY_RESET_FILE_MARKER "{\"LOG FILE RESET -- THIS IS AN ERROR\"}" +#define LOG_CATEGORY_RESET_FILE_MARKER_READABLE "LOG FILE RESET -- THIS IS AN ERROR" +/// Gets a recovery file for the given path. Caches the last known recovery path for each path. +/datum/log_holder/proc/get_recovery_file_for(path) + var/static/cache + if(isnull(cache)) + cache = list() + + var/count = cache[path] || 0 + while(fexists("[path].rec[count]")) + count++ + cache[path] = count + + return "[path].rec[count]" + +/// Sets up the given category's file and header. +/datum/log_holder/proc/init_category_file(datum/log_category/category) + var/file_path = category.get_output_file(null) + if(fexists(file_path)) // already exists? implant a reset marker + rustg_file_append(LOG_CATEGORY_RESET_FILE_MARKER, file_path) + fcopy(file_path, get_recovery_file_for(file_path)) + rustg_file_write("[json_encode(category.category_header)]\n", file_path) + + if(!human_readable_enabled) + return + + file_path = category.get_output_file(null, "log") + if(fexists(file_path)) + rustg_file_append(LOG_CATEGORY_RESET_FILE_MARKER_READABLE, file_path) + fcopy(file_path, get_recovery_file_for(file_path)) + rustg_file_write("\[[human_readable_timestamp()]\] Starting up round ID [round_id].\n - -------------------------\n", file_path) + +#undef LOG_CATEGORY_RESET_FILE_MARKER +#undef LOG_CATEGORY_RESET_FILE_MARKER_READABLE + /// Initializes the given log category and populates the list of contained categories based on the sub category list /datum/log_holder/proc/init_log_category(datum/log_category/category_type, list/datum/log_category/sub_categories) var/datum/log_category/category_instance = new category_type @@ -239,9 +275,8 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) LOG_HEADER_CATEGORY = category_instance.category, ) - rustg_file_write("[json_encode(category_header)]\n", category_instance.get_output_file(null)) - if(human_readable_enabled) - rustg_file_write("\[[human_readable_timestamp()]\] Starting up round ID [round_id].\n - -------------------------\n", category_instance.get_output_file(null, "log")) + category_instance.category_header = category_header + init_category_file(category_instance, category_header) /datum/log_holder/proc/unix_timestamp_string() // pending change to rust-g return RUSTG_CALL(RUST_G, "unix_timestamp")() @@ -261,8 +296,7 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) /datum/log_holder/proc/Log(category, message, list/data) // This is Log because log is a byond internal proc if(shutdown) - stack_trace("Performing logging after shutdown! This might not be functional in the future!") - // but for right now it's fine + return // do not include the message because these go into the runtime log and we might be secret! if(!istext(message)) @@ -270,7 +304,7 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) stack_trace("Logging with a non-text message") if(!category) - category = LOG_CATEGORY_NOT_FOUND + category = LOG_CATEGORY_INTERNAL_CATEGORY_NOT_FOUND stack_trace("Logging with a null or empty category") if(data && !islist(data)) @@ -286,7 +320,7 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) var/datum/log_category/log_category = log_categories[category] if(!log_category) - Log(LOG_CATEGORY_NOT_FOUND, message, data) + Log(LOG_CATEGORY_INTERNAL_CATEGORY_NOT_FOUND, message, data) CRASH("Attempted to log to a category that doesn't exist! [category]") var/list/semver_store = null diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm index fe209387e008..0012aff294d4 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm @@ -25,11 +25,11 @@ /datum/ai_behavior/move_to_cardinal/brimdemon/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() - if (!succeeded) + if(!succeeded) return var/mob/living/target = controller.blackboard[target_key] var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETED_ACTION] - if(!ability?.IsAvailable()) + if(QDELETED(target) || QDELETED(controller.pawn) || !ability?.IsAvailable()) return ability.InterceptClickOn(caller = controller.pawn, target = target) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm index ea0b9a710117..987e50774c3f 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm @@ -30,6 +30,8 @@ /datum/ai_behavior/travel_towards/and_drop/finish_action(datum/ai_controller/controller, succeeded, target_key) . = ..() var/mob/living/living_mob = controller.pawn + if(QDELETED(living_mob)) // pawn can be null at this point + return var/obj/drop_item = locate(/obj/item) in (living_mob.contents - typecache_filter_list(living_mob.contents, controller.blackboard[BB_IGNORE_ITEMS])) drop_item?.forceMove(get_turf(living_mob)) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm index 1bb5c6fc960a..ccc3ef92f6ea 100644 --- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm @@ -8,10 +8,10 @@ /datum/ai_planning_subtree/perch_on_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/living_pawn = controller.pawn - var/atom/buckled_too = living_pawn.buckled + var/atom/buckled_to = living_pawn.buckled //do we have a current target or is chance to unbuckle has passed? then unbuckle! - if(buckled_too) + if(buckled_to) if((SPT_PROB(unperch_chance, seconds_per_tick) || controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))) controller.queue_behavior(/datum/ai_behavior/unbuckle_mob) return diff --git a/code/modules/mob/living/basic/pets/parrot/poly.dm b/code/modules/mob/living/basic/pets/parrot/poly.dm index db5f9141a5c6..9deaff7a10b6 100644 --- a/code/modules/mob/living/basic/pets/parrot/poly.dm +++ b/code/modules/mob/living/basic/pets/parrot/poly.dm @@ -168,11 +168,7 @@ file_data["longestdeathstreak"] = longest_deathstreak var/formatted_data -#if DM_VERSION >= 515 formatted_data = json_encode(file_data, JSON_PRETTY_PRINT) -#else - formatted_data = json_encode(file_data) -#endif rustg_file_write(formatted_data, file_path) memory_saved = TRUE diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 9e4905874347..dc6ee3d3dabb 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -227,7 +227,14 @@ monkestation edit end */ //Butt-Based Farts /datum/emote/living/carbon/human/fart/run_emote(mob/user, params, type_override, intentional) if(issilicon(user)) - user.visible_message("[user] lets out a synthesized fart!", "You let out a synthesized fart!") + var/list/ignored_mobs = list() + for(var/mob/anything in GLOB.player_list) + if(!anything.client) + continue + if(!anything.client.prefs.read_preference(/datum/preference/toggle/prude_mode)) + continue + ignored_mobs |= anything + user.visible_message("[user] lets out a synthesized fart!", "You let out a synthesized fart!", ignored_mobs = ignored_mobs) playsound(user, pick( 'monkestation/sound/effects/robot_farts/rbf1.ogg', 'monkestation/sound/effects/robot_farts/rbf2.ogg', @@ -247,7 +254,7 @@ monkestation edit end */ 'monkestation/sound/effects/robot_farts/rbf16.ogg', 'monkestation/sound/effects/robot_farts/rbf17.ogg', 'monkestation/sound/effects/robot_farts/rbf18.ogg', - ), 50, TRUE) + ), 50, TRUE, mixer_channel = CHANNEL_PRUDE) return . = ..() if(user.stat == CONSCIOUS) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index cc1c82f13b85..22872424a846 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -30,6 +30,7 @@ else if(ckey) stack_trace("Mob without client but with associated ckey has been deleted.") + unset_machine() remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index e8816bb2e0f4..53743b9985ca 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -289,6 +289,7 @@ playsound(src, lock_back_sound, lock_back_sound_volume, lock_back_sound_vary) else playsound(src, rack_sound, rack_sound_volume, rack_sound_vary) + SEND_SIGNAL(src, COMSIG_GUN_RACKED, user) update_appearance() ///Drops the bolt from a locked position diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 5e938c499539..b4198caeafd1 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -13,6 +13,8 @@ wound_falloff_tile = -5 embed_falloff_tile = -3 + speed = 0.4 //twice as fast + /obj/projectile/bullet/smite name = "divine retribution" damage = 10 diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 519195fff3c3..cba0167a996f 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -213,7 +213,10 @@ var/beakerCurrentVolume = 0 if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = round(R.volume, 0.01), "pH" = R.ph, "purity" = R.purity))) // list in a list because Byond merges the first list... + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + beakerContents.Add(list(list("name" = chem_name, "volume" = round(R.volume, 0.01), "pH" = R.ph, "purity" = R.purity))) // list in a list because Byond merges the first list... beakerCurrentVolume += R.volume data["beakerContents"] = beakerContents diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 20adbd0e6958..98c8e9e9adc4 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -238,7 +238,10 @@ var/beaker_contents[0] if(beaker) for(var/datum/reagent/R in beaker.reagents.reagent_list) - beaker_contents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = round(R.volume, 0.01)))) // list in a list because Byond merges the first list... + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + beaker_contents.Add(list(list("name" = chem_name, "id" = ckey(R.name), "volume" = round(R.volume, 0.01)))) // list in a list because Byond merges the first list... data["beakerContents"] = beaker_contents var/buffer_contents[0] diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index 160e0aa17888..47116515f124 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -129,7 +129,10 @@ var/TankContents[0] var/TankCurrentVolume = 0 for(var/datum/reagent/R in reagents.reagent_list) - TankContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + var/chem_name = R.name + if(istype(R, /datum/reagent/ammonia/urine) && user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + chem_name = "Ammonia?" + TankContents.Add(list(list("name" = chem_name, "volume" = R.volume))) // list in a list because Byond merges the first list... TankCurrentVolume += R.volume data["TankContents"] = TankContents data["isTankLoaded"] = reagents.total_volume ? TRUE : FALSE diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm index 666201a32256..aeea43faa6d8 100644 --- a/code/modules/tgs/v3210/api.dm +++ b/code/modules/tgs/v3210/api.dm @@ -99,11 +99,9 @@ if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL)) TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.") return - #if DM_VERSION >= 515 - call_ext(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval - #else - call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval - #endif + + call_ext(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retvalVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval + return TRUE /datum/tgs_api/v3210/OnTopic(T) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 3a8c6b5485b6..652e1e530054 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -150,7 +150,6 @@ #include "mob_spawn.dm" #include "modsuit.dm" #include "modular_map_loader.dm" -#include "monkey_business.dm" #include "mouse_bite_cable.dm" #include "mutant_hands_consistency.dm" #include "mutant_organs.dm" diff --git a/code/modules/unit_tests/cardboard_cutouts.dm b/code/modules/unit_tests/cardboard_cutouts.dm index f706f8c95b69..ce7066de1ca9 100644 --- a/code/modules/unit_tests/cardboard_cutouts.dm +++ b/code/modules/unit_tests/cardboard_cutouts.dm @@ -11,11 +11,9 @@ nukie_cutout.push_over() test_screenshot("nukie_cutout_pushed", getFlatIcon(nukie_cutout)) -#if DM_VERSION >= 515 // This is the only reason we're testing xenomorphs. // Making a custom subtype with direct_icon is hacky. ASSERT(!isnull(/datum/cardboard_cutout/xenomorph_maid::direct_icon)) -#endif var/obj/item/cardboard_cutout/xenomorph/xenomorph_cutout = new test_screenshot("xenomorph_cutout", getFlatIcon(xenomorph_cutout)) diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm index bcfebef4693e..0a9b5b8a99ff 100644 --- a/code/modules/unit_tests/create_and_destroy.dm +++ b/code/modules/unit_tests/create_and_destroy.dm @@ -1,125 +1,12 @@ ///Delete one of every type, sleep a while, then check to see if anything has gone fucky /datum/unit_test/create_and_destroy - //You absolutely must run last + //You absolutely must run after (almost) everything else priority = TEST_CREATE_AND_DESTROY GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) /datum/unit_test/create_and_destroy/Run() //We'll spawn everything here var/turf/spawn_at = run_loc_floor_bottom_left - var/list/ignore = list( - //Never meant to be created, errors out the ass for mobcode reasons - /mob/living/carbon, - //Nother template type, doesn't like being created with no seed - /obj/item/food/grown, - //And another - /obj/item/slimecross/recurring, - //This should be obvious - /obj/machinery/doomsday_device, - //Yet more templates - /obj/machinery/restaurant_portal, - //Template type - /obj/effect/mob_spawn, - //Template type - /obj/structure/holosign/robot_seat, - //Singleton - /mob/dview, - //Template type - /obj/item/bodypart, - //This is meant to fail extremely loud every single time it occurs in any environment in any context, and it falsely alarms when this unit test iterates it. Let's not spawn it in. - /obj/merge_conflict_marker, - //briefcase launchpads erroring - /obj/machinery/launchpad/briefcase, - //Both are abstract types meant to scream bloody murder if spawned in raw - /obj/item/organ/external, - /obj/item/organ/external/wings, - /obj/effect/spawner/random_engines, - /obj/effect/spawner/random_bar, - ///this instant starts a timer, and if its being instantly deleted it can cause issues - /obj/machinery/atm, - /datum/hotspot, - /obj/machinery/ocean_elevator, - /atom/movable/outdoor_effect, - /turf/closed/mineral/random/regrowth, - ) - //Say it with me now, type template - ignore += typesof(/obj/effect/mapping_helpers) - //This turf existing is an error in and of itself - ignore += typesof(/turf/baseturf_skipover) - ignore += typesof(/turf/baseturf_bottom) - //This demands a borg, so we'll let if off easy - ignore += typesof(/obj/item/modular_computer/pda/silicon) - //This one demands a computer, ditto - ignore += typesof(/obj/item/modular_computer/processor) - //Very finiky, blacklisting to make things easier - ignore += typesof(/obj/item/poster/wanted) - //This expects a seed, we can't pass it - ignore += typesof(/obj/item/food/grown) - //Needs clients / mobs to observe it to exist. Also includes hallucinations. - ignore += typesof(/obj/effect/client_image_holder) - //Same to above. Needs a client / mob / hallucination to observe it to exist. - ignore += typesof(/obj/projectile/hallucination) - ignore += typesof(/obj/item/hallucinated) - //Can't pass in a thing to glow - ignore += typesof(/obj/effect/abstract/eye_lighting) - //We don't have a pod - ignore += typesof(/obj/effect/pod_landingzone_effect) - ignore += typesof(/obj/effect/pod_landingzone) - //We have a baseturf limit of 10, adding more than 10 baseturf helpers will kill CI, so here's a future edge case to fix. - ignore += typesof(/obj/effect/baseturf_helper) - //No tauma to pass in - ignore += typesof(/mob/camera/imaginary_friend) - //No pod to gondola - ignore += typesof(/mob/living/simple_animal/pet/gondola/gondolapod) - //No heart to give - ignore += typesof(/obj/structure/ethereal_crystal) - //No linked console - ignore += typesof(/mob/camera/ai_eye/remote/base_construction) - //See above - ignore += typesof(/mob/camera/ai_eye/remote/shuttle_docker) - //Hangs a ref post invoke async, which we don't support. Could put a qdeleted check but it feels hacky - ignore += typesof(/obj/effect/anomaly/grav/high) - //See above - ignore += typesof(/obj/effect/timestop) - //Invoke async in init, skippppp - ignore += typesof(/mob/living/silicon/robot/model) - //This lad also sleeps - ignore += typesof(/obj/item/hilbertshotel) - //this boi spawns turf changing stuff, and it stacks and causes pain. Let's just not - ignore += typesof(/obj/effect/sliding_puzzle) - //Stacks baseturfs, can't be tested here - ignore += typesof(/obj/effect/temp_visual/lava_warning) - //Stacks baseturfs, can't be tested here - ignore += typesof(/obj/effect/landmark/ctf) - //Our system doesn't support it without warning spam from unregister calls on things that never registered - ignore += typesof(/obj/docking_port) - //Asks for a shuttle that may not exist, let's leave it alone - ignore += typesof(/obj/item/pinpointer/shuttle) - //This spawns beams as a part of init, which can sleep past an async proc. This hangs a ref, and fucks us. It's only a problem here because the beam sleeps with CHECK_TICK - ignore += typesof(/obj/structure/alien/resin/flower_bud) - //Needs a linked mecha - ignore += typesof(/obj/effect/skyfall_landingzone) - //Expects a mob to holderize, we have nothing to give - ignore += typesof(/obj/item/clothing/head/mob_holder) - //Needs cards passed into the initilazation args - ignore += typesof(/obj/item/toy/cards/cardhand) - //Needs a holodeck area linked to it which is not guarenteed to exist and technically is supposed to have a 1:1 relationship with computer anyway. - ignore += typesof(/obj/machinery/computer/holodeck) - //runtimes if not paired with a landmark - ignore += typesof(/obj/structure/industrial_lift) - // Runtimes if the associated machinery does not exist, but not the base type - ignore += subtypesof(/obj/machinery/airlock_controller) - // Always ought to have an associated escape menu. Any references it could possibly hold would need one regardless. - ignore += subtypesof(/atom/movable/screen/escape_menu) - ///we generate mobs in these and create destroy does this in null space - ignore += typesof(/obj/item/loot_table_maker) - ///we need to use json_decode to run randoms properly - ignore += typesof(/obj/item/device/cassette_tape) - ignore += typesof(/datum/cassette/cassette_tape) - ///we also dont want weathers or weather events as they will hold refs to alot of stuff as they shouldn't be deleted - ignore += typesof(/datum/weather_event) - ignore += typesof(/datum/particle_weather) - ignore += typesof(/mob/living/basic/aquatic) var/list/cached_contents = spawn_at.contents.Copy() var/original_turf_type = spawn_at.type @@ -127,7 +14,7 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) var/original_baseturf_count = length(original_baseturfs) GLOB.running_create_and_destroy = TRUE - for(var/type_path in typesof(/atom/movable, /turf) - ignore) //No areas please + for(var/type_path in typesof(/atom/movable, /turf) - uncreatables) //No areas please if(ispath(type_path, /turf)) spawn_at.ChangeTurf(type_path) //We change it back to prevent baseturfs stacking and hitting the limit @@ -154,40 +41,48 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) qdel(to_kill) GLOB.running_create_and_destroy = FALSE - //Hell code, we're bound to have ended the round somehow so let's stop if from ending while we work - SSticker.delay_end = TRUE // Drastically lower the amount of time it takes to GC, since we don't have clients that can hold it up. SSgarbage.collection_timeout[GC_QUEUE_CHECK] = 10 SECONDS - //Prevent the garbage subsystem from harddeling anything, if only to save time - SSgarbage.collection_timeout[GC_QUEUE_HARDDELETE] = 10000 HOURS //Clear it, just in case cached_contents.Cut() + var/list/queues_we_care_about = list() + // All of em, I want hard deletes too, since we rely on the debug info from them + for(var/i in 1 to GC_QUEUE_HARDDELETE) + queues_we_care_about += i + //Now that we've qdel'd everything, let's sleep until the gc has processed all the shit we care about // + 2 seconds to ensure that everything gets in the queue. - var/time_needed = SSgarbage.collection_timeout[GC_QUEUE_CHECK] + 2 SECONDS + var/time_needed = 2 SECONDS + for(var/index in queues_we_care_about) + time_needed += SSgarbage.collection_timeout[index] var/start_time = world.time + var/real_start_time = REALTIMEOFDAY var/garbage_queue_processed = FALSE sleep(time_needed) while(!garbage_queue_processed) - var/list/queue_to_check = SSgarbage.queues[GC_QUEUE_CHECK] - //How the hell did you manage to empty this? Good job! - if(!length(queue_to_check)) - garbage_queue_processed = TRUE - break + var/oldest_packet_creation = INFINITY + for(var/index in queues_we_care_about) + var/list/queue_to_check = SSgarbage.queues[index] + if(!length(queue_to_check)) + continue + + var/list/oldest_packet = queue_to_check[1] + //Pull out the time we inserted at + var/qdeld_at = oldest_packet[GC_QUEUE_ITEM_GCD_DESTROYED] + + oldest_packet_creation = min(qdeld_at, oldest_packet_creation) - var/list/oldest_packet = queue_to_check[1] - //Pull out the time we deld at - var/qdeld_at = oldest_packet[1] //If we've found a packet that got del'd later then we finished, then all our shit has been processed - if(qdeld_at > start_time) + //That said, if there are any pending hard deletes you may NOT sleep, we gotta handle that shit + if(oldest_packet_creation > start_time && !length(SSgarbage.queues[GC_QUEUE_HARDDELETE])) garbage_queue_processed = TRUE break - if(world.time > start_time + time_needed + 30 MINUTES) //If this gets us gitbanned I'm going to laugh so hard + if(REALTIMEOFDAY > real_start_time + time_needed + 50 MINUTES) //If this gets us gitbanned I'm going to laugh so hard TEST_FAIL("Something has gone horribly wrong, the garbage queue has been processing for well over 30 minutes. What the hell did you do") break @@ -199,8 +94,6 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) //Alright, time to see if anything messed up var/list/cache_for_sonic_speed = SSgarbage.items for(var/path in cache_for_sonic_speed) - if(path in ignore) - continue var/datum/qdel_item/item = cache_for_sonic_speed[path] if(item.failures) TEST_FAIL("[item.name] hard deleted [item.failures] times out of a total del count of [item.qdels]") @@ -215,11 +108,9 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) if(fails & BAD_INIT_NO_HINT) TEST_FAIL("[path] didn't return an Initialize hint") if(fails & BAD_INIT_QDEL_BEFORE) - TEST_FAIL("[path] qdel'd in New()") + TEST_FAIL("[path] qdel'd before we could call Initialize()") if(fails & BAD_INIT_SLEPT) TEST_FAIL("[path] slept during Initialize()") - SSticker.delay_end = FALSE //This shouldn't be needed, but let's be polite SSgarbage.collection_timeout[GC_QUEUE_CHECK] = GC_CHECK_QUEUE - SSgarbage.collection_timeout[GC_QUEUE_HARDDELETE] = GC_DEL_QUEUE diff --git a/code/modules/unit_tests/find_reference_sanity.dm b/code/modules/unit_tests/find_reference_sanity.dm index 8bd2a14dbf5f..575ec3269106 100644 --- a/code/modules/unit_tests/find_reference_sanity.dm +++ b/code/modules/unit_tests/find_reference_sanity.dm @@ -26,11 +26,8 @@ var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder) SSgarbage.should_save_refs = TRUE - //Sanity check - #if DM_VERSION >= 515 var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 3, "Should be: test references: 0 + baseline references: 3 (victim var,loc,allocated list)") - #endif victim.DoSearchVar(testbed, "Sanity Check", search_time = 1) //We increment search time to get around an optimization TEST_ASSERT(!victim.found_refs.len, "The ref-tracking tool found a ref where none existed") SSgarbage.should_save_refs = FALSE @@ -45,10 +42,8 @@ testbed.test_list += victim testbed.test_assoc_list["baseline"] = victim - #if DM_VERSION >= 515 var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 6, "Should be: test references: 3 + baseline references: 3 (victim var,loc,allocated list)") - #endif victim.DoSearchVar(testbed, "First Run", search_time = 2) TEST_ASSERT(victim.found_refs["test"], "The ref-tracking tool failed to find a regular value") diff --git a/code/modules/unit_tests/monkey_business.dm b/code/modules/unit_tests/monkey_business.dm index 20bfffe6a482..80044a0486d9 100644 --- a/code/modules/unit_tests/monkey_business.dm +++ b/code/modules/unit_tests/monkey_business.dm @@ -14,7 +14,8 @@ /datum/unit_test/monkey_business/Run() for(var/monkey_id in 1 to length(GLOB.the_station_areas)) - var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(GLOB.the_station_areas[monkey_id])) + var/area/monkey_zone = GLOB.areas_by_type[GLOB.the_station_areas[monkey_id]] + var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(monkey_zone)) monkey.set_species(/datum/species/monkey) monkey.set_name("Monkey [monkey_id]") if(monkey_id % monkey_angry_nth == 0) // BLOOD FOR THE BLOOD GODS diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 7e1bb80c0731..914e9953dbdf 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -50,6 +50,9 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) var/static/datum/space_level/reservation + /// List of atoms that we don't want to ever initialize in an agnostic context, like for Create and Destroy. Stored on the base datum for usability in other relevant tests that need this data. + var/static/list/uncreatables = null + /proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b) return initial(a.priority) - initial(b.priority) @@ -58,6 +61,9 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) var/datum/map_template/unit_tests/template = new reservation = template.load_new_z() + if (isnull(uncreatables)) + uncreatables = build_list_of_uncreatables() + allocated = new run_loc_floor_bottom_left = get_turf(locate(/obj/effect/landmark/unit_test_bottom_left) in GLOB.landmarks_list) run_loc_floor_top_right = get_turf(locate(/obj/effect/landmark/unit_test_top_right) in GLOB.landmarks_list) @@ -196,6 +202,126 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) qdel(test) +/// Builds (and returns) a list of atoms that we shouldn't initialize in generic testing, like Create and Destroy. +/// It is appreciated to add the reason why the atom shouldn't be initialized if you add it to this list. +/datum/unit_test/proc/build_list_of_uncreatables() + RETURN_TYPE(/list) + var/list/ignore = list( + //Never meant to be created, errors out the ass for mobcode reasons + /mob/living/carbon, + //Nother template type, doesn't like being created with no seed + /obj/item/food/grown, + //And another + /obj/item/slimecross/recurring, + //This should be obvious + /obj/machinery/doomsday_device, + //Yet more templates + /obj/machinery/restaurant_portal, + //Template type + /obj/effect/mob_spawn, + //Template type + /obj/structure/holosign/robot_seat, + //Singleton + /mob/dview, + //Template type + /obj/item/bodypart, + //This is meant to fail extremely loud every single time it occurs in any environment in any context, and it falsely alarms when this unit test iterates it. Let's not spawn it in. + /obj/merge_conflict_marker, + //briefcase launchpads erroring + /obj/machinery/launchpad/briefcase, + //Both are abstract types meant to scream bloody murder if spawned in raw + /obj/item/organ/external, + /obj/item/organ/external/wings, + /obj/effect/spawner/random_engines, + /obj/effect/spawner/random_bar, + ///this instant starts a timer, and if its being instantly deleted it can cause issues + /obj/machinery/atm, + /datum/hotspot, + /obj/machinery/ocean_elevator, + /atom/movable/outdoor_effect, + /turf/closed/mineral/random/regrowth, + ) + //Say it with me now, type template + ignore += typesof(/obj/effect/mapping_helpers) + //This turf existing is an error in and of itself + ignore += typesof(/turf/baseturf_skipover) + ignore += typesof(/turf/baseturf_bottom) + //This demands a borg, so we'll let if off easy + ignore += typesof(/obj/item/modular_computer/pda/silicon) + //This one demands a computer, ditto + ignore += typesof(/obj/item/modular_computer/processor) + //Very finiky, blacklisting to make things easier + ignore += typesof(/obj/item/poster/wanted) + //This expects a seed, we can't pass it + ignore += typesof(/obj/item/food/grown) + //Needs clients / mobs to observe it to exist. Also includes hallucinations. + ignore += typesof(/obj/effect/client_image_holder) + //Same to above. Needs a client / mob / hallucination to observe it to exist. + ignore += typesof(/obj/projectile/hallucination) + ignore += typesof(/obj/item/hallucinated) + //Can't pass in a thing to glow + ignore += typesof(/obj/effect/abstract/eye_lighting) + //We don't have a pod + ignore += typesof(/obj/effect/pod_landingzone_effect) + ignore += typesof(/obj/effect/pod_landingzone) + //We have a baseturf limit of 10, adding more than 10 baseturf helpers will kill CI, so here's a future edge case to fix. + ignore += typesof(/obj/effect/baseturf_helper) + //No tauma to pass in + ignore += typesof(/mob/camera/imaginary_friend) + //No pod to gondola + ignore += typesof(/mob/living/simple_animal/pet/gondola/gondolapod) + //No heart to give + ignore += typesof(/obj/structure/ethereal_crystal) + //No linked console + ignore += typesof(/mob/camera/ai_eye/remote/base_construction) + //See above + ignore += typesof(/mob/camera/ai_eye/remote/shuttle_docker) + //Hangs a ref post invoke async, which we don't support. Could put a qdeleted check but it feels hacky + ignore += typesof(/obj/effect/anomaly/grav/high) + //See above + ignore += typesof(/obj/effect/timestop) + //Invoke async in init, skippppp + ignore += typesof(/mob/living/silicon/robot/model) + //This lad also sleeps + ignore += typesof(/obj/item/hilbertshotel) + //this boi spawns turf changing stuff, and it stacks and causes pain. Let's just not + ignore += typesof(/obj/effect/sliding_puzzle) + //Stacks baseturfs, can't be tested here + ignore += typesof(/obj/effect/temp_visual/lava_warning) + //Stacks baseturfs, can't be tested here + ignore += typesof(/obj/effect/landmark/ctf) + //Our system doesn't support it without warning spam from unregister calls on things that never registered + ignore += typesof(/obj/docking_port) + //Asks for a shuttle that may not exist, let's leave it alone + ignore += typesof(/obj/item/pinpointer/shuttle) + //This spawns beams as a part of init, which can sleep past an async proc. This hangs a ref, and fucks us. It's only a problem here because the beam sleeps with CHECK_TICK + ignore += typesof(/obj/structure/alien/resin/flower_bud) + //Needs a linked mecha + ignore += typesof(/obj/effect/skyfall_landingzone) + //Expects a mob to holderize, we have nothing to give + ignore += typesof(/obj/item/clothing/head/mob_holder) + //Needs cards passed into the initilazation args + ignore += typesof(/obj/item/toy/cards/cardhand) + //Needs a holodeck area linked to it which is not guarenteed to exist and technically is supposed to have a 1:1 relationship with computer anyway. + ignore += typesof(/obj/machinery/computer/holodeck) + //runtimes if not paired with a landmark + ignore += typesof(/obj/structure/industrial_lift) + // Runtimes if the associated machinery does not exist, but not the base type + ignore += subtypesof(/obj/machinery/airlock_controller) + // Always ought to have an associated escape menu. Any references it could possibly hold would need one regardless. + ignore += subtypesof(/atom/movable/screen/escape_menu) + ///we generate mobs in these and create destroy does this in null space + ignore += typesof(/obj/item/loot_table_maker) + ///we need to use json_decode to run randoms properly + ignore += typesof(/obj/item/device/cassette_tape) + ignore += typesof(/datum/cassette/cassette_tape) + ///we also dont want weathers or weather events as they will hold refs to alot of stuff as they shouldn't be deleted + ignore += typesof(/datum/weather_event) + ignore += typesof(/datum/particle_weather) + ignore += typesof(/mob/living/basic/aquatic) + + return ignore + /proc/RunUnitTests() CHECK_TICK diff --git a/dependencies.sh b/dependencies.sh index b24b85d55b23..0d6fe6b8fd60 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -4,18 +4,18 @@ #Final authority on what's required to fully build the project # byond version -export BYOND_MAJOR=514 -export BYOND_MINOR=1588 +export BYOND_MAJOR=515 +export BYOND_MINOR=1610 #rust_g git tag -export RUST_G_VERSION=1.2.0 +export RUST_G_VERSION=3.1.0 #node version export NODE_VERSION=14 export NODE_VERSION_PRECISE=14.16.1 # SpacemanDMM git tag -export SPACEMAN_DMM_VERSION=suite-1.7.3 +export SPACEMAN_DMM_VERSION=suite-1.8 # Python version for mapmerge and other tools export PYTHON_VERSION=3.9.0 diff --git a/monkestation/code/game/machinery/power/ptl.dm b/monkestation/code/game/machinery/power/ptl.dm index 66e535cc161e..5625b4830f0c 100644 --- a/monkestation/code/game/machinery/power/ptl.dm +++ b/monkestation/code/game/machinery/power/ptl.dm @@ -215,7 +215,7 @@ if("outputTW") power_format_multi_output = 1 TW if("outputPW") - power_format_multi = 1 PW + power_format_multi_output = 1 PW /obj/machinery/power/transmission_laser/process() @@ -229,7 +229,7 @@ var/last_fire = firing if(terminal && input_attempt) - input_pulling = min(terminal.surplus() , input_number * power_format_multi) + input_pulling = min(input_available , input_number * power_format_multi) if(inputting) if(input_pulling > 0) @@ -278,6 +278,8 @@ var/generated_cash = (2 * mw_power * PROCESS_CAP) / (2 * mw_power + PROCESS_CAP * A1_CURVE) generated_cash += (4 * mw_power * MINIMUM_BAR) / (4 * mw_power + MINIMUM_BAR) generated_cash = round(generated_cash) + if(generated_cash < 0) + return total_earnings += generated_cash generated_cash += unsent_earnings @@ -343,6 +345,7 @@ name = "" icon = 'goon/icons/obj/power.dmi' icon_state = "ptl_beam" + anchored = TRUE ///used to deal with atoms stepping on us while firing var/obj/machinery/power/transmission_laser/host diff --git a/monkestation/code/game/sound.dm b/monkestation/code/game/sound.dm index 072ece63bd35..b93bc6b9f967 100644 --- a/monkestation/code/game/sound.dm +++ b/monkestation/code/game/sound.dm @@ -111,3 +111,5 @@ return "Robot Instruments" //you caused this DONGLE if(CHANNEL_MOB_SOUNDS) return "Mob Sounds" + if(CHANNEL_PRUDE) + return "Prude Sounds" diff --git a/monkestation/code/modules/antagonists/slasher/abilities/incorporealize.dm b/monkestation/code/modules/antagonists/slasher/abilities/incorporealize.dm index 0170db617b8e..4b1b4c34796c 100644 --- a/monkestation/code/modules/antagonists/slasher/abilities/incorporealize.dm +++ b/monkestation/code/modules/antagonists/slasher/abilities/incorporealize.dm @@ -40,6 +40,8 @@ return for(var/mob/living/watcher in viewers(9, target)) + if(watcher == target) + continue if(!watcher.mind) //only mobs with minds stop you from jaunting continue if(isdead(watcher)) diff --git a/monkestation/code/modules/client/preferences/prude.dm b/monkestation/code/modules/client/preferences/prude.dm new file mode 100644 index 000000000000..4795914191ff --- /dev/null +++ b/monkestation/code/modules/client/preferences/prude.dm @@ -0,0 +1,5 @@ +/datum/preference/toggle/prude_mode + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + savefile_key = "prude_mode" + savefile_identifier = PREFERENCE_PLAYER + default_value = FALSE diff --git a/monkestation/code/modules/liquids/liquid_effect.dm b/monkestation/code/modules/liquids/liquid_effect.dm index 1d2ce54fca38..201d95fae7b3 100644 --- a/monkestation/code/modules/liquids/liquid_effect.dm +++ b/monkestation/code/modules/liquids/liquid_effect.dm @@ -268,6 +268,8 @@ for(var/datum/reagent/reagent_type as anything in liquid_group.reagents.reagent_list) var/reagent_name = initial(reagent_type.name) + if(istype(reagent_type, /datum/reagent/ammonia/urine) && examiner.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + reagent_name = "Ammonia" var/volume = round(reagent_type.volume / length(liquid_group.members), 0.01) examine_list += "• [volume] units of [reagent_name]" diff --git a/monkestation/code/modules/mob/living/carbon/human/emotes.dm b/monkestation/code/modules/mob/living/carbon/human/emotes.dm index b2a8642169c5..3b41962c83ca 100644 --- a/monkestation/code/modules/mob/living/carbon/human/emotes.dm +++ b/monkestation/code/modules/mob/living/carbon/human/emotes.dm @@ -33,7 +33,7 @@ dyn_explosion(Location, 1, 0) return - playsound(ass_holder, "monkestation/sound/effects/superfart.ogg", 100, FALSE, pressure_affected = FALSE) + playsound(ass_holder, "monkestation/sound/effects/superfart.ogg", 100, FALSE, pressure_affected = FALSE, mixer_channel = CHANNEL_PRUDE) spawn(8) Location = get_turf(user) switch(rand(1000)) diff --git a/monkestation/code/modules/modular_guns/__base_attachment.dm b/monkestation/code/modules/modular_guns/__base_attachment.dm new file mode 100644 index 000000000000..a8b44ab8587e --- /dev/null +++ b/monkestation/code/modules/modular_guns/__base_attachment.dm @@ -0,0 +1,56 @@ +/obj/item/attachment + name = "generic attachment" + desc = "Weird how this got here huh." + w_class = WEIGHT_CLASS_SMALL + icon = 'monkestation/code/modules/modular_guns/icons/ak.dmi' + icon_state = "stock_wood" + //here lies some variables we can tweak for each part + + ///divisor to spread 1 is normal 0.5 is twice as unstable 2 is twice as stable + var/stability = 1 + ///fire multiplier + var/fire_multipler = 1 + ///noise multiplier multiplies the noise the gun makes + var/noise_multiplier = 1 + ///misfire multiplier + var/misfire_multiplier = 1 + /// how much more cumbersome this is to use + var/ease_of_use = 1 + ///what gun type we can attach to + var/attachment_rail = GUN_ATTACH_AK + ///what type of attachement are we ie what slot do we go in + var/attachment_type + ///the icon_state our attachment adds + var/attachment_icon_state = "stock_wood" + ///the icon of our attachment + var/attachment_icon = 'monkestation/code/modules/modular_guns/icons/ak.dmi' + ///do we modify layer at all? + var/layer_modifier = 0 + ///how much we offset in y and x + var/offset_y = 0 + var/offset_x = 0 + ///special flags like colorable + var/attachment_flags = NONE + ///the color of our attachment in hex + var/attachment_color + +/obj/item/attachment/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + SEND_SIGNAL(target, COMSIG_ATTACHMENT_ATTACH_ATTEMPT, user, target, src) + +/obj/item/attachment/proc/unique_attachment_effects(obj/item/gun/modular) + return + +/obj/item/attachment/proc/unique_attachment_effects_removal(obj/item/gun/modular) + return + +/obj/item/attachment/proc/unique_attachment_effects_per_reset(obj/item/gun/modular) + +/obj/item/attachment/AltClick(mob/user) + . = ..() + if(attachment_flags & ATTACHMENT_COLORABLE) + var/new_choice = input(user,"","Choose Color",attachment_color) as color + if(new_choice == null) + return + attachment_color = new_choice + color = new_choice diff --git a/monkestation/code/modules/modular_guns/__base_modular_gun.dm b/monkestation/code/modules/modular_guns/__base_modular_gun.dm new file mode 100644 index 000000000000..32836ffad8e2 --- /dev/null +++ b/monkestation/code/modules/modular_guns/__base_modular_gun.dm @@ -0,0 +1,15 @@ +/obj/item/gun/ballistic/modular + name = "generic receiver" + desc = "some assembly required" + w_class = WEIGHT_CLASS_SMALL // smuggle me + spread = 100 // this is horrible unassembled + mag_display = FALSE // needs some shitcode ig cause we have multiple types + spawnwithmagazine = FALSE + pinless = TRUE //for now until we do other shit + + var/mag_icon_state = "mag_32.25 Caseless" + +/obj/item/gun/ballistic/modular/update_overlays() + . = ..() + if(mag_icon_state && magazine) + . += mutable_appearance(icon, mag_icon_state, layer, offset_spokesman = src) diff --git a/monkestation/code/modules/modular_guns/__modular_gun_signals.dm b/monkestation/code/modules/modular_guns/__modular_gun_signals.dm new file mode 100644 index 000000000000..b1ff6ca25ecd --- /dev/null +++ b/monkestation/code/modules/modular_guns/__modular_gun_signals.dm @@ -0,0 +1,3 @@ +#define COMSIG_ATTACHMENT_ATTACHED "comsig_attachment_attached" +#define COMSIG_ATTACHMENT_DETACHED "comsig_attachment_detached" +#define COMSIG_ATTACHMENT_ATTACH_ATTEMPT "comsig_attachment_attach_attempt" diff --git a/monkestation/code/modules/modular_guns/attachment_datums/__base_attachment_datum.dm b/monkestation/code/modules/modular_guns/attachment_datums/__base_attachment_datum.dm new file mode 100644 index 000000000000..c5c3fe46dc47 --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/__base_attachment_datum.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler + /// what tool is needed to add or remove + var/tool_required + /// what slot this is for + var/attachment_slot + /// the attachment stored + var/obj/item/attachment/stored + ///are we required to fire? + var/required_to_fire = TRUE diff --git a/monkestation/code/modules/modular_guns/attachment_datums/barrels.dm b/monkestation/code/modules/modular_guns/attachment_datums/barrels.dm new file mode 100644 index 000000000000..bdcfdb330fec --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/barrels.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler/barrel + attachment_slot = ATTACHMENT_TYPE_BARREL + required_to_fire = FALSE + +/datum/attachment_handler/barrel/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/barrel/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/frames.dm b/monkestation/code/modules/modular_guns/attachment_datums/frames.dm new file mode 100644 index 000000000000..a9259bf9386e --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/frames.dm @@ -0,0 +1,8 @@ +/datum/attachment_handler/frame + attachment_slot = ATTACHMENT_TYPE_FRAME + +/datum/attachment_handler/frame/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/frame/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/grip.dm b/monkestation/code/modules/modular_guns/attachment_datums/grip.dm new file mode 100644 index 000000000000..5edd52553f5e --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/grip.dm @@ -0,0 +1,8 @@ +/datum/attachment_handler/grip + attachment_slot = ATTACHMENT_TYPE_GRIP + +/datum/attachment_handler/grip/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/grip/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/keychains.dm b/monkestation/code/modules/modular_guns/attachment_datums/keychains.dm new file mode 100644 index 000000000000..534a270c4e2a --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/keychains.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler/keychain + attachment_slot = ATTACHMENT_TYPE_KEYCHAIN + required_to_fire = FALSE + +/datum/attachment_handler/keychain/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/keychain/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/magazine.dm b/monkestation/code/modules/modular_guns/attachment_datums/magazine.dm new file mode 100644 index 000000000000..d6542892345f --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/magazine.dm @@ -0,0 +1,8 @@ +/datum/attachment_handler/magazine + attachment_slot = ATTACHMENT_TYPE_MAG + +/datum/attachment_handler/magazine/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/magazine/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/sight.dm b/monkestation/code/modules/modular_guns/attachment_datums/sight.dm new file mode 100644 index 000000000000..2b395461d597 --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/sight.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler/sight + attachment_slot = ATTACHMENT_TYPE_SIGHT + required_to_fire = FALSE + +/datum/attachment_handler/sight/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/sight/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/stock.dm b/monkestation/code/modules/modular_guns/attachment_datums/stock.dm new file mode 100644 index 000000000000..349d15927f0d --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/stock.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler/stock + attachment_slot = ATTACHMENT_TYPE_STOCK + required_to_fire = FALSE + +/datum/attachment_handler/stock/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/stock/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/underbarrel.dm b/monkestation/code/modules/modular_guns/attachment_datums/underbarrel.dm new file mode 100644 index 000000000000..11eaa9ca92e2 --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/underbarrel.dm @@ -0,0 +1,9 @@ +/datum/attachment_handler/underbarrel + attachment_slot = ATTACHMENT_TYPE_UNDERBARREL + required_to_fire = FALSE + +/datum/attachment_handler/underbarrel/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/underbarrel/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/attachment_datums/welrod.dm b/monkestation/code/modules/modular_guns/attachment_datums/welrod.dm new file mode 100644 index 000000000000..fc82d2c25000 --- /dev/null +++ b/monkestation/code/modules/modular_guns/attachment_datums/welrod.dm @@ -0,0 +1,8 @@ +/datum/attachment_handler/welrod + attachment_slot = ATTACHMENT_TYPE_WELROD + +/datum/attachment_handler/welrod/screw + tool_required = TOOL_SCREWDRIVER + +/datum/attachment_handler/welrod/wrench + tool_required = TOOL_WRENCH diff --git a/monkestation/code/modules/modular_guns/ballistics/frames/ak.dm b/monkestation/code/modules/modular_guns/ballistics/frames/ak.dm new file mode 100644 index 000000000000..07bde0d9105e --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/frames/ak.dm @@ -0,0 +1,25 @@ +/obj/item/gun/ballistic/modular/ak + icon = 'monkestation/code/modules/modular_guns/icons/ak.dmi' + icon_state = "frame" + +/obj/item/gun/ballistic/modular/ak/Initialize(mapload) + . = ..() + AddComponent(/datum/component/weapon_attachments,\ + attachment_type = GUN_ATTACH_AK, \ + hand_slots = list( + new /datum/attachment_handler/magazine, + new /datum/attachment_handler/grip, + new /datum/attachment_handler/stock, + ), \ + ) + AddComponent(/datum/component/gun_stat_holder,\ + stability = 55 ,\ + loudness = 90 ,\ + firing_speed = 12 ,\ + ease_of_use = 100 ,\ + ) + AddComponent(/datum/component/gun_jammable,\ + jam_time = 5 SECONDS, \ + jamming_prob = 5, \ + ) + diff --git a/monkestation/code/modules/modular_guns/ballistics/frames/ak_st.dm b/monkestation/code/modules/modular_guns/ballistics/frames/ak_st.dm new file mode 100644 index 000000000000..2d3e5b8f5e32 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/frames/ak_st.dm @@ -0,0 +1,25 @@ +/obj/item/gun/ballistic/modular/ak_st + icon = 'monkestation/code/modules/modular_guns/icons/ak.dmi' + icon_state = "frame-st" + +/obj/item/gun/ballistic/modular/ak_st/Initialize(mapload) + . = ..() + AddComponent(/datum/component/weapon_attachments,\ + attachment_type = GUN_ATTACH_AK_ST, \ + hand_slots = list( + new /datum/attachment_handler/magazine, + new /datum/attachment_handler/grip, + new /datum/attachment_handler/stock, + ), \ + ) + AddComponent(/datum/component/gun_stat_holder,\ + stability = 55 ,\ + loudness = 90 ,\ + firing_speed = 12 ,\ + ease_of_use = 86 ,\ + ) + AddComponent(/datum/component/gun_jammable,\ + jam_time = 5 SECONDS, \ + jamming_prob = 5, \ + ) + diff --git a/monkestation/code/modules/modular_guns/ballistics/frames/mk58.dm b/monkestation/code/modules/modular_guns/ballistics/frames/mk58.dm new file mode 100644 index 000000000000..3689bf28685d --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/frames/mk58.dm @@ -0,0 +1,34 @@ +/obj/item/gun/ballistic/modular/mk_58 + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + icon_state = "frame" + +/obj/item/gun/ballistic/modular/mk_58/Initialize(mapload) + . = ..() + AddComponent(/datum/component/weapon_attachments,\ + attachment_type = GUN_ATTACH_MK_58, \ + hand_slots = list( + new /datum/attachment_handler/magazine, + new /datum/attachment_handler/grip, + new /datum/attachment_handler/stock, + new /datum/attachment_handler/underbarrel, + new /datum/attachment_handler/welrod, + new /datum/attachment_handler/barrel, + new /datum/attachment_handler/keychain, + new /datum/attachment_handler/sight, + ), \ + tool_slots = list( + new /datum/attachment_handler/frame/screw, + ), \ + ) + AddComponent(/datum/component/gun_stat_holder,\ + stability = 98 ,\ + loudness = 45 ,\ + firing_speed = 3 ,\ + ease_of_use = 65 ,\ + ) + + AddComponent(/datum/component/gun_jammable,\ + jam_time = 5 SECONDS, \ + jamming_prob = 3, \ + ) + diff --git a/monkestation/code/modules/modular_guns/ballistics/frames/wintermute.dm b/monkestation/code/modules/modular_guns/ballistics/frames/wintermute.dm new file mode 100644 index 000000000000..27d2b47e4181 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/frames/wintermute.dm @@ -0,0 +1,26 @@ +/obj/item/gun/ballistic/modular/wintermute + icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + icon_state = "frame" + +/obj/item/gun/ballistic/modular/wintermute/Initialize(mapload) + . = ..() + AddComponent(/datum/component/weapon_attachments,\ + attachment_type = GUN_ATTACH_WINTERMUTE, \ + hand_slots = list( + new /datum/attachment_handler/magazine, + new /datum/attachment_handler/grip, + new /datum/attachment_handler/stock, + ), \ + ) + AddComponent(/datum/component/gun_stat_holder,\ + stability = 98 ,\ + loudness = 45 ,\ + firing_speed = 3 ,\ + ease_of_use = 65 ,\ + ) + + AddComponent(/datum/component/gun_jammable,\ + jam_time = 5 SECONDS, \ + jamming_prob = 3, \ + ) + diff --git a/monkestation/code/modules/modular_guns/ballistics/frames/wintermute_sl.dm b/monkestation/code/modules/modular_guns/ballistics/frames/wintermute_sl.dm new file mode 100644 index 000000000000..ee0f1cb5857f --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/frames/wintermute_sl.dm @@ -0,0 +1,26 @@ +/obj/item/gun/ballistic/modular/wintermute_sl + icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + icon_state = "frame-sl" + +/obj/item/gun/ballistic/modular/wintermute_sl/Initialize(mapload) + . = ..() + AddComponent(/datum/component/weapon_attachments,\ + attachment_type = GUN_ATTACH_WINTERMUTE, \ + hand_slots = list( + new /datum/attachment_handler/magazine, + new /datum/attachment_handler/grip, + new /datum/attachment_handler/stock, + ), \ + ) + AddComponent(/datum/component/gun_stat_holder,\ + stability = 98 ,\ + loudness = 45 ,\ + firing_speed = 15 ,\ + ease_of_use = 65 ,\ + ) + + AddComponent(/datum/component/gun_jammable,\ + jam_time = 5 SECONDS, \ + jamming_prob = 7, \ + ) + diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/barrel/_base_barrels.dm b/monkestation/code/modules/modular_guns/ballistics/parts/barrel/_base_barrels.dm new file mode 100644 index 000000000000..7760bb7f182e --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/barrel/_base_barrels.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/barrel + name = "generic barrel" + + attachment_type = ATTACHMENT_TYPE_BARREL diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/barrel/mk58/standard_barrels.dm b/monkestation/code/modules/modular_guns/ballistics/parts/barrel/mk58/standard_barrels.dm new file mode 100644 index 000000000000..73d05b9891d5 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/barrel/mk58/standard_barrels.dm @@ -0,0 +1,22 @@ +/obj/item/attachment/barrel/mk58 + name = "mk58 barrel" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "suppressor" + attachment_icon_state = "suppressor" + +/obj/item/attachment/barrel/mk58/suppressor + name = "mk58 suppressor" + offset_x = 15 + + ease_of_use = 0.95 + fire_multipler = 0.85 + +/obj/item/attachment/barrel/mk58/suppressor/unique_attachment_effects(obj/item/gun/modular) + modular.suppressed = TRUE + modular.w_class = WEIGHT_CLASS_BULKY + +/obj/item/attachment/barrel/mk58/suppressor/unique_attachment_effects_removal(obj/item/gun/modular) + modular.suppressed = FALSE + modular.w_class = initial(modular.w_class) diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/frames/_base_frame.dm b/monkestation/code/modules/modular_guns/ballistics/parts/frames/_base_frame.dm new file mode 100644 index 000000000000..f504b52ad9b1 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/frames/_base_frame.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/frame + name = "generic frame" + + attachment_type = ATTACHMENT_TYPE_FRAME diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/makeshift.dm new file mode 100644 index 000000000000..9913b23c6078 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/makeshift.dm @@ -0,0 +1,7 @@ +/obj/item/attachment/frame/mk_58/makeshift + icon_state = "frame_makeshift" + attachment_icon_state = "frame_makeshift" + + stability = 0.75 + ease_of_use = 0.9 + misfire_multiplier = 1.1 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/standard_frames.dm b/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/standard_frames.dm new file mode 100644 index 000000000000..53cf10510501 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/frames/mk58/standard_frames.dm @@ -0,0 +1,39 @@ +/obj/item/attachment/frame/mk_58 + name = "mk58 frame" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "frame_gray" + +/obj/item/attachment/frame/mk_58/black + icon_state = "frame_black" + attachment_icon_state = "frame_black" + + stability = 1.1 + ease_of_use = 1.4 + misfire_multiplier = 0.6 + +/obj/item/attachment/frame/mk_58/gray + icon_state = "frame_gray" + attachment_icon_state = "frame_gray" + + stability = 1.1 + ease_of_use = 1.4 + misfire_multiplier = 0.6 + +/obj/item/attachment/frame/mk_58/tan + icon_state = "frame_tan" + attachment_icon_state = "frame_tan" + + stability = 1.1 + ease_of_use = 1.4 + misfire_multiplier = 0.6 + +/obj/item/attachment/frame/mk_58/colorable + icon_state = "frame_colorable" + attachment_icon_state = "frame_colorable" + attachment_flags = ATTACHMENT_COLORABLE + + stability = 1.1 + ease_of_use = 1.4 + misfire_multiplier = 0.6 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/_base_grips.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/_base_grips.dm new file mode 100644 index 000000000000..6b2c3d3ddd99 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/_base_grips.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/grip + name = "generic grip" + + attachment_type = ATTACHMENT_TYPE_GRIP diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/makeshift.dm new file mode 100644 index 000000000000..4953ca3fb10a --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/grip/ak_st/makeshift + icon_state = "grip_makeshift-st" + attachment_icon_state = "grip_makeshift-st" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/standard_grips.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/standard_grips.dm new file mode 100644 index 000000000000..ecae55708736 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak-st/standard_grips.dm @@ -0,0 +1,23 @@ +/obj/item/attachment/grip/ak_st + name = "ak grip" + attachment_rail = GUN_ATTACH_AK_ST + +/obj/item/attachment/grip/ak_st/wood + icon_state = "grip_wood-st" + attachment_icon_state = "grip_wood-st" + +/obj/item/attachment/grip/ak_st/excelsior + icon_state = "grip_excelsior-st" + attachment_icon_state = "grip_excelsior-st" + +/obj/item/attachment/grip/ak_st/black + icon_state = "grip_black-st" + attachment_icon_state = "grip_black-st" + +/obj/item/attachment/grip/ak_st/rubber + icon_state = "grip_rubber-st" + attachment_icon_state = "grip_rubber-st" + +/obj/item/attachment/grip/ak_st/serbian + icon_state = "grip_serbian-st" + attachment_icon_state = "grip_serbian-st" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/makeshift.dm new file mode 100644 index 000000000000..8f1a1a80c501 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/grip/ak/makeshift + icon_state = "grip_makeshift" + attachment_icon_state = "grip_makeshift" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/standard_grips.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/standard_grips.dm new file mode 100644 index 000000000000..01512fcb7fb4 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/ak/standard_grips.dm @@ -0,0 +1,23 @@ +/obj/item/attachment/grip/ak + name = "ak grip" + attachment_rail = GUN_ATTACH_AK + +/obj/item/attachment/grip/ak/wood + icon_state = "grip_wood" + attachment_icon_state = "grip_wood" + +/obj/item/attachment/grip/ak/excelsior + icon_state = "grip_excelsior" + attachment_icon_state = "grip_excelsior" + +/obj/item/attachment/grip/ak/black + icon_state = "grip_black" + attachment_icon_state = "grip_black" + +/obj/item/attachment/grip/ak/rubber + icon_state = "grip_rubber" + attachment_icon_state = "grip_rubber" + +/obj/item/attachment/grip/ak/serbian + icon_state = "grip_serbian" + attachment_icon_state = "grip_serbian" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/makeshift.dm new file mode 100644 index 000000000000..1290fc287c63 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/makeshift.dm @@ -0,0 +1,8 @@ +/obj/item/attachment/grip/mk_58/makeshift + icon_state = "grip_makeshift" + attachment_icon_state = "grip_makeshift" + + misfire_multiplier = 1.3 + stability = 0.76 + fire_multipler = 0.85 + ease_of_use = 0.7 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/standard_grips.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/standard_grips.dm new file mode 100644 index 000000000000..817aa2488095 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/mk58/standard_grips.dm @@ -0,0 +1,42 @@ +/obj/item/attachment/grip/mk_58 + name = "mk58 grip" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + icon_state = "grip_excelsior" + attachment_rail = GUN_ATTACH_MK_58 + +/obj/item/attachment/grip/mk_58/excelsior + icon_state = "grip_excelsior" + attachment_icon_state = "grip_excelsior" + + stability = 1.4 + ease_of_use = 1.1 + +/obj/item/attachment/grip/mk_58/black + icon_state = "grip_black" + attachment_icon_state = "grip_black" + + stability = 1.4 + ease_of_use = 1.1 + +/obj/item/attachment/grip/mk_58/rubber + icon_state = "grip_rubber" + attachment_icon_state = "grip_rubber" + + stability = 1.4 + ease_of_use = 1.1 + +/obj/item/attachment/grip/mk_58/serbian + icon_state = "grip_serbian" + attachment_icon_state = "grip_serbian" + + stability = 1.4 + ease_of_use = 1.1 + +/obj/item/attachment/grip/mk_58/colorable + icon_state = "grip_colorable" + attachment_icon_state = "grip_colorable" + attachment_flags = ATTACHMENT_COLORABLE + + stability = 1.4 + ease_of_use = 1.1 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/makeshift.dm new file mode 100644 index 000000000000..a4650b14ad21 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/grip/wintermute/makeshift + icon_state = "grip_makeshift" + attachment_icon_state = "grip_makeshift" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/standard_grips.dm b/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/standard_grips.dm new file mode 100644 index 000000000000..6e0d7609bd64 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/grips/wintermute/standard_grips.dm @@ -0,0 +1,25 @@ +/obj/item/attachment/grip/wintermute + name = "wintermute grip" + icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_rail = GUN_ATTACH_WINTERMUTE + +/obj/item/attachment/grip/wintermute/wood + icon_state = "grip_wood" + attachment_icon_state = "grip_wood" + +/obj/item/attachment/grip/wintermute/excelsior + icon_state = "grip_excelsior" + attachment_icon_state = "grip_excelsior" + +/obj/item/attachment/grip/wintermute/black + icon_state = "grip_black" + attachment_icon_state = "grip_black" + +/obj/item/attachment/grip/wintermute/rubber + icon_state = "grip_rubber" + attachment_icon_state = "grip_rubber" + +/obj/item/attachment/grip/wintermute/serbian + icon_state = "grip_serbian" + attachment_icon_state = "grip_serbian" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/keychains/_base_keychains.dm b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/_base_keychains.dm new file mode 100644 index 000000000000..ee4d9382c637 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/_base_keychains.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/keychain + name = "generic keychain" + + attachment_type = ATTACHMENT_TYPE_KEYCHAIN diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/keychains/mk58/standard_keychains.dm b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/mk58/standard_keychains.dm new file mode 100644 index 000000000000..ab1f95ba2335 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/mk58/standard_keychains.dm @@ -0,0 +1,13 @@ +/obj/item/attachment/keychain/mk_58 + name = "mk58 grip" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + icon_state = "keychain_cirno" + attachment_rail = GUN_ATTACH_MK_58 + offset_y = -6 + +/obj/item/attachment/keychain/mk_58/cirno + name = "cirno keychain" + + icon_state = "keychain_cirno" + attachment_icon_state = "keychain_cirno" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/keychains/readme.md b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/readme.md new file mode 100644 index 000000000000..9acd387526cd --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/keychains/readme.md @@ -0,0 +1 @@ +God is dead and this folder is proof of it. diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/mags/_base_mag.dm b/monkestation/code/modules/modular_guns/ballistics/parts/mags/_base_mag.dm new file mode 100644 index 000000000000..1c609f2e7c30 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/mags/_base_mag.dm @@ -0,0 +1,9 @@ +/obj/item/attachment/mag + name = "generic mag" + + attachment_type = ATTACHMENT_TYPE_MAG + var/mag_type = /obj/item/ammo_box/magazine/m10mm + +/obj/item/attachment/mag/unique_attachment_effects(obj/item/gun/ballistic/modular/modular) + modular.mag_type = mag_type + modular.mag_icon_state = icon_state diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak-st/standard_mags.dm b/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak-st/standard_mags.dm new file mode 100644 index 000000000000..322c078b9e1e --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak-st/standard_mags.dm @@ -0,0 +1,57 @@ +/obj/item/attachment/mag/ak_st + name = "ak mag" + attachment_rail = GUN_ATTACH_AK_ST + +/obj/item/attachment/mag/ak_st/mag_32 + name = "ak mag 32.25 Caseless" + + icon_state = "mag_32.25 Caseless-st" + attachment_icon_state = "well_clrifle-st" + +/obj/item/attachment/mag/ak_st/mag_128_30 + name = "ak mag 128.30" + + icon_state = "mag_128.30-st" + attachment_icon_state = "well_srifle-st" + +/obj/item/attachment/mag/ak_st/mag_128_20 + name = "ak mag 128.20" + + icon_state = "mag_128.20-st" + attachment_icon_state = "well_srifle-st" + +/obj/item/attachment/mag/ak_st/mag_16_30 + name = "ak mag 16.30" + + icon_state = "mag_16.30-st" + attachment_icon_state = "" + +/obj/item/attachment/mag/ak_st/mag_256_20 + name = "ak mag 256.20" + + icon_state = "mag_256.20-st" + attachment_icon_state = "well_clrifle-st" + +/obj/item/attachment/mag/ak_st/mag_16_20 + name = "ak mag 16.20" + + icon_state = "mag_16.30-st" + attachment_icon_state = "well_clrifle-st" + +/obj/item/attachment/mag/ak_st/mag_8_35 + name = "ak mag 8.35" + + icon_state = "mag_8.35-st" + attachment_icon_state = "well_pistol-st" + +/obj/item/attachment/mag/ak_st/mag_128_shotgun + name = "ak mag 128 Shotgun Shell" + + icon_state = "mag_128Shotgun Shell-st" + attachment_icon_state = "well_shotgun-st" + +/obj/item/attachment/mag/ak_st/mag_16_shotgun + name = "ak mag 16 Shotgun Shell" + + icon_state = "mag_16Shotgun Shell-st" + attachment_icon_state = "well_shotgun-st" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak/standard_mags.dm b/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak/standard_mags.dm new file mode 100644 index 000000000000..f5fe4aa6dbb4 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/mags/ak/standard_mags.dm @@ -0,0 +1,63 @@ +/obj/item/attachment/mag/ak + name = "ak mag" + attachment_rail = GUN_ATTACH_AK + +/obj/item/attachment/mag/ak/mag_32 + name = "ak mag 32.25 Caseless" + + icon_state = "mag_32.25 Caseless" + attachment_icon_state = "well_clrifle" + +/obj/item/attachment/mag/ak/mag_128_30 + name = "ak mag 128.30" + + icon_state = "mag_128.30" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/ak/mag_128_20 + name = "ak mag 128.20" + + icon_state = "mag_128.20" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/ak/mag_16_30 + name = "ak mag 16.30" + + icon_state = "mag_16.30" + attachment_icon_state = "" + +/obj/item/attachment/mag/ak/mag_256_20 + name = "ak mag 256.20" + + icon_state = "mag_256.20" + attachment_icon_state = "well_clrifle" + +/obj/item/attachment/mag/ak/mag_16_20 + name = "ak mag 16.20" + + icon_state = "mag_16.30" + attachment_icon_state = "well_clrifle" + +/obj/item/attachment/mag/ak/mag_8_35 + name = "ak mag 8.35" + + icon_state = "mag_8.35" + attachment_icon_state = "well_pistol" + +/obj/item/attachment/mag/ak/mag_8_40_magnum + name = "ak mag 8.40 magnum" + + icon_state = "mag_8.40 magnum" + attachment_icon_state = "well_magnum" + +/obj/item/attachment/mag/ak/mag_128_shotgun + name = "ak mag 128 Shotgun Shell" + + icon_state = "mag_128Shotgun Shell" + attachment_icon_state = "well_shotgun" + +/obj/item/attachment/mag/ak/mag_16_shotgun + name = "ak mag 16 Shotgun Shell" + + icon_state = "mag_16Shotgun Shell" + attachment_icon_state = "well_shotgun" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/mags/mk58/standard_mags.dm b/monkestation/code/modules/modular_guns/ballistics/parts/mags/mk58/standard_mags.dm new file mode 100644 index 000000000000..21d472e1a356 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/mags/mk58/standard_mags.dm @@ -0,0 +1,28 @@ +/obj/item/attachment/mag/mk58 + name = "mk58 mag" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "mag_4.35" + +/obj/item/attachment/mag/mk58/m10mm + name = "mk58 10mm mag" + + icon_state = "mag_4.35" + attachment_icon_state = "well_pistol" + mag_type = /obj/item/ammo_box/magazine/m10mm + + fire_multipler = 1.2 + stability = 1.1 + noise_multiplier = 0.85 + +/obj/item/attachment/mag/mk58/m50 + name = "mk58 .50ae mag" + + icon_state = "mag_2.35" + attachment_icon_state = "well_pistol" + mag_type = /obj/item/ammo_box/magazine/m50 + + fire_multipler = 0.5 + noise_multiplier = 1.3 + stability = 0.95 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/mags/wintermute/standard_mags.dm b/monkestation/code/modules/modular_guns/ballistics/parts/mags/wintermute/standard_mags.dm new file mode 100644 index 000000000000..581724531e7b --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/mags/wintermute/standard_mags.dm @@ -0,0 +1,53 @@ +/obj/item/attachment/mag/wintermute + name = "wintermute mag" + icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_rail = GUN_ATTACH_WINTERMUTE + +/obj/item/attachment/mag/wintermute/mag_835 + name = "wintermute mag 8.35" + + icon_state = "mag_8.35" + attachment_icon_state = "well_lrifle" + +/obj/item/attachment/mag/wintermute/mag_1630 + name = "wintermute mag 16.30" + + icon_state = "mag_16.30" + attachment_icon_state = "well_lrifle" + +/obj/item/attachment/mag/wintermute/mag_128_30 + name = "wintermute mag 128.30" + + icon_state = "mag_128.30" + attachment_icon_state = "well_lrifle" + +/obj/item/attachment/mag/wintermute/mag_16_20 + name = "wintermute mag 16.20" + + icon_state = "mag_16.20" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/wintermute/mag_256_20 + name = "wintermute mag 256.20" + + icon_state = "mag_256.20" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/wintermute/mag_16_20 + name = "ak mag 16.20" + + icon_state = "mag_16.30" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/wintermute/mag_128_20 + name = "wintermute mag 128.20" + + icon_state = "mag_128.20" + attachment_icon_state = "well_srifle" + +/obj/item/attachment/mag/wintermute/mag_8_40_magnum + name = "wintermute mag 8.40 magnum" + + icon_state = "mag_8.40" + attachment_icon_state = "well_magnum" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/sights/_base_sights.dm b/monkestation/code/modules/modular_guns/ballistics/parts/sights/_base_sights.dm new file mode 100644 index 000000000000..f64484017425 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/sights/_base_sights.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/sight + name = "generic sight" + + attachment_type = ATTACHMENT_TYPE_SIGHT diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/sights/mk58/standard_sights.dm b/monkestation/code/modules/modular_guns/ballistics/parts/sights/mk58/standard_sights.dm new file mode 100644 index 000000000000..e4b9dfaf65b2 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/sights/mk58/standard_sights.dm @@ -0,0 +1,31 @@ +/obj/item/attachment/sight/mk_58 + name = "mk58 sight" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "sight_reddot" + + +/obj/item/attachment/sight/mk_58/reddot + icon_state = "sight_reddot" + attachment_icon_state = "sight_reddot" + + stability = 1.1 + +/obj/item/attachment/sight/mk_58/reflex + icon_state = "sight_reflex" + attachment_icon_state = "sight_reflex" + + stability = 1.1 + +/obj/item/attachment/sight/mk_58/iff + icon_state = "sight_iff" + attachment_icon_state = "sight_iff" + + stability = 1.1 + +/obj/item/attachment/sight/mk_58/sniper + icon_state = "sight_sniper" + attachment_icon_state = "sight_sniper" + + stability = 1.1 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/_base_stock.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/_base_stock.dm new file mode 100644 index 000000000000..1cd428aebdf5 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/_base_stock.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/stock + name = "generic stock" + + attachment_type = ATTACHMENT_TYPE_STOCK diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/makeshift.dm new file mode 100644 index 000000000000..653d7d06113f --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/stock/ak/makeshift + icon_state = "stock_makeshift-st" + attachment_icon_state = "stock_makeshift-st" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/standard_stocks.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/standard_stocks.dm new file mode 100644 index 000000000000..4897c9071e75 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak-st/standard_stocks.dm @@ -0,0 +1,19 @@ +/obj/item/attachment/stock/ak_st + name = "ak stock" + attachment_rail = GUN_ATTACH_AK_ST + +/obj/item/attachment/stock/ak_st/wood + icon_state = "stock_wood-st" + attachment_icon_state = "stock_wood-st" + +/obj/item/attachment/stock/ak_st/excelsior + icon_state = "stock_excelsior-st" + attachment_icon_state = "stock_excelsior-st" + +/obj/item/attachment/stock/ak_st/black + icon_state = "stock_black-st" + attachment_icon_state = "stock_black-st" + +/obj/item/attachment/stock/ak_st/serbian + icon_state = "stock_serbian-st" + attachment_icon_state = "stock_serbian-st" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/makeshift.dm new file mode 100644 index 000000000000..6e8d994db2ee --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/stock/ak/makeshift + icon_state = "stock_makeshift" + attachment_icon_state = "stock_makeshift" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/standard_stocks.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/standard_stocks.dm new file mode 100644 index 000000000000..6cd49390f93b --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/ak/standard_stocks.dm @@ -0,0 +1,19 @@ +/obj/item/attachment/stock/ak + name = "ak stock" + attachment_rail = GUN_ATTACH_AK + +/obj/item/attachment/stock/ak/wood + icon_state = "stock_wood" + attachment_icon_state = "stock_wood" + +/obj/item/attachment/stock/ak/excelsior + icon_state = "stock_excelsior" + attachment_icon_state = "stock_excelsior" + +/obj/item/attachment/stock/ak/black + icon_state = "stock_black" + attachment_icon_state = "stock_black" + +/obj/item/attachment/stock/ak/serbian + icon_state = "stock_serbian" + attachment_icon_state = "stock_serbian" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/mk_58/standard_stocks.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/mk_58/standard_stocks.dm new file mode 100644 index 000000000000..b2b19d2331e0 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/mk_58/standard_stocks.dm @@ -0,0 +1,38 @@ +/obj/item/attachment/stock/mk58 + name = "mk58 stock" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + offset_x = -16 + +/obj/item/attachment/stock/mk58/rifle + icon_state = "stock_rifle" + attachment_icon_state = "stock_rifle" + +/obj/item/attachment/stock/mk58/smg + icon_state = "stock_smg" + attachment_icon_state = "stock_smg" + +/obj/item/attachment/stock/mk58/smgcompact + icon_state = "stock_smgcompact" + attachment_icon_state = "stock_smgcompact" + +/obj/item/attachment/stock/mk58/brace + icon_state = "stock_brace" + attachment_icon_state = "stock_brace" + +/obj/item/attachment/stock/mk58/ou + icon_state = "stock_ou" + attachment_icon_state = "stock_ou" + +/obj/item/attachment/stock/mk58/wood + icon_state = "stock_wood" + attachment_icon_state = "stock_wood" + +/obj/item/attachment/stock/mk58/metal + icon_state = "stock_metal" + attachment_icon_state = "stock_metal" + +/obj/item/attachment/stock/mk58/l42 + icon_state = "stock_l42" + attachment_icon_state = "stock_l42" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/makeshift.dm new file mode 100644 index 000000000000..d9f6c986b906 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/makeshift.dm @@ -0,0 +1,3 @@ +/obj/item/attachment/stock/wintermute/makeshift + icon_state = "stock_makeshift" + attachment_icon_state = "stock_makeshift" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/standard_stocks.dm b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/standard_stocks.dm new file mode 100644 index 000000000000..f48cee19a5aa --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/stocks/wintermute/standard_stocks.dm @@ -0,0 +1,21 @@ +/obj/item/attachment/stock/wintermute + name = "wintermute stock" + icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/wintermute.dmi' + attachment_rail = GUN_ATTACH_WINTERMUTE + +/obj/item/attachment/stock/wintermute/wood + icon_state = "stock_wood" + attachment_icon_state = "stock_wood" + +/obj/item/attachment/stock/wintermute/excelsior + icon_state = "stock_excelsior" + attachment_icon_state = "stock_excelsior" + +/obj/item/attachment/stock/wintermute/black + icon_state = "stock_black" + attachment_icon_state = "stock_black" + +/obj/item/attachment/stock/wintermute/serbian + icon_state = "stock_serbian" + attachment_icon_state = "stock_serbian" diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/_base_underbarrel.dm b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/_base_underbarrel.dm new file mode 100644 index 000000000000..9a87235944e6 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/_base_underbarrel.dm @@ -0,0 +1,4 @@ +/obj/item/attachment/underbarrel + name = "generic underbarrel" + + attachment_type = ATTACHMENT_TYPE_UNDERBARREL diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/_base_flashlight.dm b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/_base_flashlight.dm new file mode 100644 index 000000000000..f0201b97c663 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/_base_flashlight.dm @@ -0,0 +1,54 @@ +/obj/item/attachment/underbarrel/flashlight + name = "generic flashlight" + ///the flashlight we store + var/obj/item/flashlight/seclite/light_object + /// A weakref to the item action we add with the light. + var/datum/weakref/toggle_action_ref + /// are we toggled on? + var/toggled = FALSE + +/obj/item/attachment/underbarrel/flashlight/unique_attachment_effects(obj/item/gun/modular) + RegisterSignal(modular, COMSIG_ITEM_UI_ACTION_CLICK, PROC_REF(on_action_click)) + + light_object = new /obj/item/flashlight/seclite(modular) + + light_object.set_light_flags(light_object.light_flags | LIGHT_ATTACHED) + // We may already exist within in our parent's contents... But if we don't move it over now + if(light_object.loc != modular) + light_object.forceMove(modular) + + // We already have an action for the light for some reason? Clean it up + if(toggle_action_ref?.resolve()) + stack_trace("[type] - add_light had an existing toggle action when add_light was called.") + QDEL_NULL(toggle_action_ref) + + var/datum/action/item_action/toggle_seclight/toggle_action = modular.add_item_action(/datum/action/item_action/toggle_seclight) + toggle_action_ref = WEAKREF(toggle_action) + modular.update_item_action_buttons() + +/// Signal proc for [COMSIG_ITEM_UI_ACTION_CLICK] that toggles our light on and off if our action button is clicked. +/obj/item/attachment/underbarrel/flashlight/proc/on_action_click(obj/item/source, mob/user, datum/action) + SIGNAL_HANDLER + + // This isn't OUR action specifically, we don't care. + if(!IS_WEAKREF_OF(action, toggle_action_ref)) + return + + // Toggle light fails = no light attached = shouldn't be possible + if(!toggle_light(user)) + CRASH("[type] - on_action_click somehow both HAD AN ACTION and also HAD A TRIGGERABLE ACTION, without having an attached light.") + + return COMPONENT_ACTION_HANDLED + +/obj/item/attachment/underbarrel/flashlight/proc/toggle_light(mob/user) + if(!light_object) + return FALSE + + light_object.on = !light_object.on + light_object.update_brightness() + if(user) + user.balloon_alert(user, "[light_object.name] toggled [light_object.on ? "on":"off"]") + + playsound(light_object, 'sound/weapons/empty.ogg', 100, TRUE) + toggled = !toggled + return TRUE diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/mk58.dm b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/mk58.dm new file mode 100644 index 000000000000..d2832b9fea3e --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/flashlight/mk58.dm @@ -0,0 +1,10 @@ +/obj/item/attachment/underbarrel/flashlight/mk58 + name = "mk58 flashlight" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "light" + attachment_icon_state = "light" + + ease_of_use = 0.8 + stability = 0.95 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/makeshift.dm b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/makeshift.dm new file mode 100644 index 000000000000..177d858293b0 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/makeshift.dm @@ -0,0 +1,23 @@ +//also yes yes I know it goes at the back of a pistol +/obj/item/attachment/underbarrel/mk_58/makeshift/illegal_switch + name = "illegal mk58 switch" + desc = "You are certainly going to jail for this one." + + icon_state = "makeshift_switch" + attachment_icon_state = "makeshift_switch" + + ease_of_use = 0.1 //lol + noise_multiplier = 1.4 + stability = 0.01 + misfire_multiplier = 9 + +/obj/item/attachment/underbarrel/mk_58/makeshift/illegal_switch/unique_attachment_effects_per_reset(obj/item/gun/modular) + modular.burst_size = 9 + modular.fire_delay = 1 + modular.w_class = WEIGHT_CLASS_BULKY + + +/obj/item/attachment/underbarrel/mk_58/makeshift/illegal_switch/unique_attachment_effects_removal(obj/item/gun/modular) + modular.burst_size = initial(modular.burst_size) + modular.fire_delay = initial(modular.fire_delay) + modular.w_class = WEIGHT_CLASS_NORMAL diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/standard_underbarrel.dm b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/standard_underbarrel.dm new file mode 100644 index 000000000000..97e26e5f5427 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/underbarrel/mk58/standard_underbarrel.dm @@ -0,0 +1,20 @@ +/obj/item/attachment/underbarrel/mk_58 + name = "mk58 underbarrel" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + icon_state = "frame_gray" + + +/obj/item/attachment/underbarrel/mk_58/bayonet + icon_state = "bayonet" + attachment_icon_state = "bayonet" + offset_x = 2 + + stability = 0.95 + +/obj/item/attachment/underbarrel/mk_58/grenade + icon_state = "grenade-m203" + attachment_icon_state = "grenade-m203" + + stability = 0.9 diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/welrod/_base_welrod.dm b/monkestation/code/modules/modular_guns/ballistics/parts/welrod/_base_welrod.dm new file mode 100644 index 000000000000..44094cad30bb --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/welrod/_base_welrod.dm @@ -0,0 +1,5 @@ +/obj/item/attachment/welrod + name = "generic welrod" + layer_modifier = -0.1 + + attachment_type = ATTACHMENT_TYPE_WELROD diff --git a/monkestation/code/modules/modular_guns/ballistics/parts/welrod/mk58/standard_welrod.dm b/monkestation/code/modules/modular_guns/ballistics/parts/welrod/mk58/standard_welrod.dm new file mode 100644 index 000000000000..0b6f899da734 --- /dev/null +++ b/monkestation/code/modules/modular_guns/ballistics/parts/welrod/mk58/standard_welrod.dm @@ -0,0 +1,8 @@ +/obj/item/attachment/welrod/mk_58 + name = "mk58 welrod" + icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' + attachment_rail = GUN_ATTACH_MK_58 + + icon_state = "well_pistol-fullpiece" + attachment_icon_state = "well_pistol-fullpiece" + attachment_icon = 'monkestation/code/modules/modular_guns/icons/mk58.dmi' diff --git a/monkestation/code/modules/modular_guns/blackmarket/auction.dm b/monkestation/code/modules/modular_guns/blackmarket/auction.dm new file mode 100644 index 000000000000..d3dfcef1cb30 --- /dev/null +++ b/monkestation/code/modules/modular_guns/blackmarket/auction.dm @@ -0,0 +1,166 @@ +#define AUCTION_TIME 3 MINUTES + +/datum/market/auction + name = "Black Market Auction" + market_flags = (MARKET_PROCESS | MARKET_AUCTION) + categories = list("Auction") + ///list of all items and when they start in world time + var/list/queued_items = list() + ///how many items we have in a queue at once + var/queue_length = 3 + ///our current auction + var/datum/market_item/auction/current_auction + ///how much time is left of our auction checked with COOLDOWN_TIME_LEFT + COOLDOWN_DECLARE(current_auction_time) + +/datum/market/auction/add_item(datum/market_item/auction/item) + if(!prob(initial(item.availability_prob))) + return FALSE + + if(ispath(item)) + item = new item() + + if(!istype(item)) + return FALSE + + if(!length(available_items)) + available_items = list() + categories |= "Auction" + + available_items += item + available_items[item] = item.auction_weight + return TRUE + +/datum/market/auction/try_process() + if(!length(queued_items)) + var/datum/market_item/auction/first_item = pick_weight(available_items) + var/datum/market_item/auction/created_item = new first_item.type + queued_items += created_item + queued_items[created_item] = world.time + rand(1.5 MINUTES, 3 MINUTES) + AUCTION_TIME + + if(length(queued_items) < queue_length) // we are missing a new auction + var/datum/market_item/auction/listed_item = pick_weight(available_items) + var/datum/market_item/auction/new_item = new listed_item.type + var/initial_time = queued_items[queued_items[length(queued_items)]] + queued_items += new_item + queued_items[new_item] = initial_time + rand(1.5 MINUTES, 3 MINUTES) + AUCTION_TIME + + if(COOLDOWN_FINISHED(src, current_auction_time) && current_auction) + grab_purchase_info(current_auction, current_auction.category, SHIPPING_METHOD_AT_FEET) + current_auction = null + + if(world.time >= queued_items[queued_items[1]]) + current_auction = queued_items[1] + queued_items[queued_items[1]] = 0 + queued_items -= current_auction + COOLDOWN_START(src, current_auction_time, AUCTION_TIME) + + +/datum/market/auction/proc/reroll(obj/item/market_uplink/uplink, user) + var/balance = uplink?.current_user.account_balance + if(balance < 350) + to_chat(user, span_warning("You don't have enough credits in [uplink] to reroll the auction block.")) + return FALSE + uplink.current_user.adjust_money(-350, "Other: Third Party Transaction") + queued_items = list() + logger.Log(LOG_CATEGORY_BLACKMARKET, "[user] has rerolled the [name]") + +/datum/market/auction/pre_purchase(item, category, method, obj/item/market_uplink/uplink, user, bid_amount) + if(item != current_auction.type) + return FALSE + + if(current_auction.user == user) + to_chat(user, span_warning("You are currently the top bidder on [current_auction] already!")) + return FALSE + + var/price = current_auction.price + + if(price >= bid_amount) + to_chat(user, span_warning("You need to bid more than the current bid amount!")) + return FALSE + + if(!uplink.current_user)///There is no ID card on the user, or the ID card has no account + to_chat(user, span_warning("The uplink sparks, as it can't identify an ID card with a bank account on you.")) + return FALSE + var/balance = uplink?.current_user.account_balance + + // I can't get the price of the item and shipping in a clean way to the UI, so I have to do this. + if(balance < bid_amount) + to_chat(user, span_warning("You don't have enough credits in [uplink] to bid on [current_auction].")) + return FALSE + + if(current_auction.user) + var/old_bidder = "Anonymous Creature" + if(ishuman(current_auction.user)) + var/mob/living/carbon/human/human = current_auction.user + old_bidder = "Anonymous [human.dna.species.name]" + current_auction.bidders += list(list( + "name" = old_bidder, + "amount" = current_auction.current_price, + )) + + logger.Log(LOG_CATEGORY_BLACKMARKET, "[user] has just bid [bid_amount] on [current_auction.item] in the [name]") + current_auction.uplink = uplink + current_auction.user = user + if(ishuman(user)) + var/mob/living/carbon/human/human = user + current_auction.top_bidder = "Anonymous [human.dna.species.name]" + else + current_auction.top_bidder = "Anonymous Creature" + current_auction.current_price = bid_amount + current_auction.price = bid_amount + + +/// Handles buying the item, this is mainly for future use and moving the code away from the uplink. +/datum/market/auction/purchase(item, category, method, obj/item/market_uplink/uplink, user) + if(!istype(uplink)) + return FALSE + + for(var/datum/market_item/I in available_items) + if(I.type != item) + continue + var/price = I.price + + if(!uplink.current_user)///There is no ID card on the user, or the ID card has no account + to_chat(user, span_warning("The uplink sparks, as it can't identify an ID card with a bank account on you.")) + return FALSE + var/balance = uplink?.current_user.account_balance + + // I can't get the price of the item and shipping in a clean way to the UI, so I have to do this. + if(balance < price) + to_chat(user, span_warning("You don't have enough credits in [uplink] for [I] with [method] shipping.")) + return FALSE + + if(I.buy(uplink, user, method)) + uplink.current_user.adjust_money(-price, "Other: Third Party Transaction") + logger.Log(LOG_CATEGORY_BLACKMARKET, "[user] has just bought the [current_auction.item] for [price] in the [name]") + if(ismob(user)) + var/mob/m_user = user + m_user.playsound_local(get_turf(m_user), 'sound/machines/twobeep_high.ogg', 50, TRUE) + return TRUE + return FALSE + + +/datum/market/auction/proc/grab_purchase_info(datum/market_item/auction/item, category, method) + purchase(item.type, category, method, item.uplink, item.user) + if(item.user) + message_admins("[item.user] has won the auction for [item]") + + +/datum/market/auction/guns + name = "Back Alley Guns" + +/datum/market_item/auction + markets = list(/datum/market/auction) + ///the user whos currently bid on it + var/mob/user + ///the current price we have + var/current_price = 0 + ///the highest bidding uplink + var/obj/item/market_uplink/uplink + ///list of mob names with prices used to show previous prices + var/list/bidders = list() + ///the name of our top bidder as a string + var/top_bidder + ///the weight this item has to appear high = more likely to be picked + var/auction_weight = 10 diff --git a/monkestation/code/modules/modular_guns/blackmarket/auction_items/gun_parts.dm b/monkestation/code/modules/modular_guns/blackmarket/auction_items/gun_parts.dm new file mode 100644 index 000000000000..13124fe93289 --- /dev/null +++ b/monkestation/code/modules/modular_guns/blackmarket/auction_items/gun_parts.dm @@ -0,0 +1,32 @@ +/datum/market_item/auction/gun_part + markets = list(/datum/market/auction/guns) + stock_max = 1 + availability_prob = 100 + category = "Gun Part" + auction_weight = 5 + +/datum/market_item/auction/gun_part/mk58 + name = "MK 58 Reciever" + desc = "An illegal mk 58 reciever for all your gun needs." + item = /obj/item/gun/ballistic/modular/mk_58 + + price_min = CARGO_CRATE_VALUE * 2.5 + price_max = CARGO_CRATE_VALUE * 5 + +/datum/market_item/auction/gun_part/cirno + name = "MK 58 Cirno keychain" + desc = "Cirno in keychain form" + item = /obj/item/attachment/keychain/mk_58/cirno + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 3 + auction_weight = 3 + +/datum/market_item/auction/gun_part/mk58_suppressor + name = "MK 58 Suppressor" + desc = "Super Illegal." + item = /obj/item/attachment/barrel/mk58/suppressor + + price_min = CARGO_CRATE_VALUE * 2.5 + price_max = CARGO_CRATE_VALUE * 7 + auction_weight = 3 diff --git a/monkestation/code/modules/modular_guns/blackmarket/auction_items/restock_gun_parts.dm b/monkestation/code/modules/modular_guns/blackmarket/auction_items/restock_gun_parts.dm new file mode 100644 index 000000000000..4c1762879023 --- /dev/null +++ b/monkestation/code/modules/modular_guns/blackmarket/auction_items/restock_gun_parts.dm @@ -0,0 +1,49 @@ +/datum/market_item/ammo + category = "Ammo" + markets = list(/datum/market/restock/guns_galore) + +/datum/market_item/ammo/m10mm_ammo_box + name = "10mm Ammo Box" + desc = "A 10mm Ammo Box." + item = /obj/item/ammo_box/c10mm + + price_min = CARGO_CRATE_VALUE * 1.5 + price_max = CARGO_CRATE_VALUE * 2.75 + stock_max = 3 + availability_prob = 70 + +/datum/market_item/ammo/m10mm_mag + name = "10mm Mag" + desc = "A 10mm Mag." + item = /obj/item/ammo_box/magazine/m10mm + + price_min = CARGO_CRATE_VALUE * 3.4 + price_max = CARGO_CRATE_VALUE * 4 + stock_max = 3 + availability_prob = 90 + +/datum/market_item/ammo/m50ae_ammo_box + name = ".50ae Ammo Box" + desc = "A .50ae Ammo Box." + item = /obj/item/ammo_box/c50 + + price_min = CARGO_CRATE_VALUE * 1.5 + price_max = CARGO_CRATE_VALUE * 2.75 + stock_max = 3 + availability_prob = 70 + +/obj/item/ammo_box/c50 + name = "ammo box (.50ae)" + icon_state = "10mmbox" + ammo_type = /obj/item/ammo_casing/a50ae + max_ammo = 15 + +/datum/market_item/ammo/m50_mag + name = ".50ae Mag" + desc = "A .50ae Mag." + item = /obj/item/ammo_box/magazine/m50 + + price_min = CARGO_CRATE_VALUE * 3.4 + price_max = CARGO_CRATE_VALUE * 4 + stock_max = 3 + availability_prob = 90 diff --git a/monkestation/code/modules/modular_guns/blackmarket/restock_market.dm b/monkestation/code/modules/modular_guns/blackmarket/restock_market.dm new file mode 100644 index 000000000000..966391686ab3 --- /dev/null +++ b/monkestation/code/modules/modular_guns/blackmarket/restock_market.dm @@ -0,0 +1,40 @@ +/datum/market/restock + market_flags = (MARKET_PROCESS) + ///our current restock timer + COOLDOWN_DECLARE(restock_timer) + ///how long each restock interval is + var/restock_interval = 5 MINUTES + ///list of all market_item_types + var/list/viable_items = list() + +/datum/market/restock/try_process() + if(COOLDOWN_FINISHED(src, restock_timer)) + restock_market() + COOLDOWN_START(src, restock_timer, restock_interval) + + +/datum/market/restock/add_item(datum/market_item/item) + viable_items |= item.type + . = ..() + +/datum/market/restock/proc/restock_market() + for(var/category in categories) + for(var/datum/market_item/item as anything in available_items[category]) + available_items[category] -= item + qdel(item) + + available_items = list() + categories = list() + for(var/item in viable_items) + var/datum/market_item/I = new item() + if(!I.item) + continue + for(var/M in I.markets) + if(M != type) + continue + add_item(item) + qdel(I) + +/datum/market/restock/guns_galore + name = "Guns Galore" + shipping = list(SHIPPING_METHOD_AT_FEET=0) diff --git a/monkestation/code/modules/modular_guns/components/attachments.dm b/monkestation/code/modules/modular_guns/components/attachments.dm new file mode 100644 index 000000000000..97cc96225f3f --- /dev/null +++ b/monkestation/code/modules/modular_guns/components/attachments.dm @@ -0,0 +1,161 @@ +/* This is a helper component to use where we can specify an empty list of slots and when interacted with +by an item that can attach seemlessly attaches, split into tool detach and hand detach tool detach takes +GROUP, TOOL, ITEM for reading whereas hand is just GROUP, ITEM. Prioritizes hand slots first +*/ + + +/datum/component/weapon_attachments + /// list of all the slots we have that can be tool detached + var/list/tool_slots = list( + + ) + /// list of all the slots we have that can be hand detached + var/list/hand_slots = list( + + ) + /// only attachments with this type can be sloted into this + var/attachment_type = GUN_ATTACH_AK + +/datum/component/weapon_attachments/Initialize(attachment_type = GUN_ATTACH_AK, hand_slots = list(), tool_slots = list()) + . = ..() + src.attachment_type = attachment_type + src.hand_slots = hand_slots + src.tool_slots = tool_slots + +/datum/component/weapon_attachments/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATTACHMENT_ATTACH_ATTEMPT, PROC_REF(attempt_attach)) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(update_attached_overlays)) + RegisterSignal(parent, COMSIG_GUN_TRY_FIRE, PROC_REF(check_can_fire)) + RegisterSignal(parent, COMSIG_ATTACHMENT_STAT_RESET, PROC_REF(apply_per_reset_uniques)) + RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(check_removal)) + +/datum/component/weapon_attachments/proc/check_can_fire(obj/item/gun/ballistic/source, mob/living/user, atom/target, flag, params) + SIGNAL_HANDLER + + for(var/datum/attachment_handler/listed as anything in (hand_slots + tool_slots)) + if(!listed.required_to_fire) + continue + if(!listed.stored) + user.balloon_alert(user, "Missing Essential Attachments!") + return COMPONENT_CANCEL_GUN_FIRE + +/datum/component/weapon_attachments/proc/attempt_attach(obj/item/gun/source, mob/living/user, atom/target, obj/item/attachment/attacher) + if(attacher.attachment_rail != attachment_type) + to_chat(user, span_notice("The [attacher] does not fit on the [target].")) + return + + var/found = FALSE + for(var/datum/attachment_handler/listed as anything in (hand_slots + tool_slots)) + if((listed.attachment_slot == attacher.attachment_type) && !listed.stored) + found = TRUE + break + + if(!found) + to_chat(user, span_notice("You can't seem to fit the [attacher] onto the [target]")) + return + + + for(var/datum/attachment_handler/listed as anything in hand_slots) + if((listed.attachment_slot != attacher.attachment_type) || listed.stored) + continue + attach_to(attacher, listed) + + for(var/datum/attachment_handler/listed as anything in tool_slots) + if((listed.attachment_slot != attacher.attachment_type) || listed.stored) + continue + if(!(listed.tool_required in get_surrounding_tools(user))) + to_chat(user, span_notice("You need a [listed.tool_required] in order to attach [attacher]")) + continue + if(!do_after(user, 1.5 SECONDS, parent)) + continue + attach_to(attacher, listed) + +/datum/component/weapon_attachments/proc/attach_to(obj/item/attachment/attacher, datum/attachment_handler/slot) + attacher.forceMove(parent) + slot.stored = attacher + SEND_SIGNAL(parent, COMSIG_ATTACHMENT_ATTACHED, attacher) + + var/obj/item/item = parent + item.update_appearance() + attacher.unique_attachment_effects(parent) + +/datum/component/weapon_attachments/proc/update_attached_overlays(atom/parent_atom, list/overlays) + SIGNAL_HANDLER + var/obj/item/item = parent + for(var/datum/attachment_handler/listed as anything in (hand_slots + tool_slots)) + if(!listed.stored) + continue + if(listed.stored.attachment_flags & ATTACHMENT_COLORABLE && !listed.stored.attachment_color) + continue + var/mutable_appearance/gun_attachment = mutable_appearance(listed.stored.attachment_icon, listed.stored.attachment_icon_state, item.layer + listed.stored.layer_modifier, offset_spokesman = parent) + gun_attachment.pixel_x += listed.stored.offset_x + gun_attachment.pixel_y += listed.stored.offset_y + gun_attachment.color = listed.stored.attachment_color + + overlays += gun_attachment + +/datum/component/weapon_attachments/proc/apply_per_reset_uniques(obj/item/gun/source) + SIGNAL_HANDLER + for(var/datum/attachment_handler/listed as anything in (hand_slots + tool_slots)) + if(!listed.stored) + continue + listed.stored.unique_attachment_effects_per_reset(parent) + + +/datum/component/weapon_attachments/proc/check_removal(datum/source, obj/item/I, mob/living/user) + var/list/removeable_attachments = list() + if(I.tool_behaviour == TOOL_WRENCH) + for(var/datum/attachment_handler/listed as anything in hand_slots) + if(!listed.stored) + continue + removeable_attachments += listed.stored + + for(var/datum/attachment_handler/listed as anything in tool_slots) + if(I.tool_behaviour != listed.tool_required) + continue + removeable_attachments += listed.stored + + if(!length(removeable_attachments)) + return + try_removal(removeable_attachments, I, user) + +/datum/component/weapon_attachments/proc/try_removal(list/removable, obj/item/I, mob/living/user) + var/obj/item/item = parent + var/obj/item/choice = tgui_input_list(user, "Choose an attachment to remove.", item.name, removable) + if(!choice) + return + if(!do_after(user, 1.5 SECONDS, item)) + return + + for(var/datum/attachment_handler/listed as anything in (hand_slots + tool_slots)) + if(!listed.stored) + continue + if(choice != listed.stored) + continue + listed.stored = null + choice.forceMove(get_turf(user)) + user.balloon_alert(user, "Successfully removed [choice.name].") + + SEND_SIGNAL(parent, COMSIG_ATTACHMENT_DETACHED, choice) + +///this is literally all to handle tools around us for shit + + +/datum/component/weapon_attachments/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1) + . = list() + + if(!isturf(a.loc)) + return + + for(var/atom/movable/AM in range(radius_range, a)) + if((AM.flags_1 & HOLOGRAM_1) || (blacklist && (AM.type in blacklist))) + continue + . += AM + +/datum/component/weapon_attachments/proc/get_surrounding_tools(atom/a, list/blacklist=null) + . = list() + for(var/obj/object in get_environment(a, blacklist)) + if(isitem(object)) + var/obj/item/item = object + if(item.tool_behaviour) + . += item.tool_behaviour diff --git a/monkestation/code/modules/modular_guns/components/ghetto.dm b/monkestation/code/modules/modular_guns/components/ghetto.dm new file mode 100644 index 000000000000..ec40b070e967 --- /dev/null +++ b/monkestation/code/modules/modular_guns/components/ghetto.dm @@ -0,0 +1,21 @@ +/* This component is added to guns when they are made using rubber bands and cardboard +it will cause bad shit to happen sometimes on fire modified by attachments used +*/ + +/datum/component/makeshift_guns + ///our misfire chance + var/misfire_chance + ///our explosion chance + var/explosion_chance + ///our disassemble chance + var/disassemble_chance + /// a datum for unique effects + var/datum/makeshift_effect/linked_effect + +/datum/component/makeshift_guns/RegisterWithParent() + RegisterSignal(parent, COMSIG_GUN_TRY_FIRE, PROC_REF(attempt_makeshift)) + + +/datum/component/makeshift_guns/proc/attempt_makeshift(obj/item/gun/source, mob/living/user, atom/target, flag, params) + SIGNAL_HANDLER + return NONE diff --git a/monkestation/code/modules/modular_guns/components/gun_jammable.dm b/monkestation/code/modules/modular_guns/components/gun_jammable.dm new file mode 100644 index 000000000000..333f7bfc452a --- /dev/null +++ b/monkestation/code/modules/modular_guns/components/gun_jammable.dm @@ -0,0 +1,58 @@ +/* this component is what handles gun jamming +*/ + +/datum/component/gun_jammable + var/obj/item/weapon/gun/ballistic/owner_gun + ///jamming probability + var/jamming_prob + //the time in deci seconds until we can jam again + var/jam_time + //are we jammed + var/jammed = FALSE + ///the time we spend unjamming + var/jam_use_time = 1 SECONDS + ///our gun jamming cd to prevent spam jammings + COOLDOWN_DECLARE(jam_cooldown) + + +/datum/component/gun_jammable/Initialize(jamming_prob = 5, jam_time = 1 SECONDS, jam_use_time = 1 SECONDS) + . = ..() + src.jamming_prob = jamming_prob + src.jam_time = jam_time + src.jam_use_time = jam_use_time + +/datum/component/gun_jammable/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATTACHMENT_ATTACHED, PROC_REF(handle_stat_gain)) + RegisterSignal(parent, COMSIG_ATTACHMENT_DETACHED, PROC_REF(handle_stat_loss)) + RegisterSignal(parent, COMSIG_GUN_TRY_FIRE, PROC_REF(handle_jam_attempt)) + RegisterSignal(parent, COMSIG_GUN_RACKED, PROC_REF(try_clear_jam)) + +/datum/component/gun_jammable/proc/handle_jam_attempt(obj/item/gun/ballistic/source, mob/living/user, atom/target, flag, params) + SIGNAL_HANDLER + + if(jammed) + user.balloon_alert(user, "Gun is jammed!") + playsound(source, source.dry_fire_sound, 30, TRUE) + return COMPONENT_CANCEL_GUN_FIRE + + if(jamming_prob && prob(jamming_prob) && COOLDOWN_FINISHED(src, jam_cooldown)) + jammed = TRUE + user.balloon_alert(user, "Gun has jammed!") + playsound(source, source.dry_fire_sound, 30, TRUE) + return COMPONENT_CANCEL_GUN_FIRE + +/datum/component/gun_jammable/proc/try_clear_jam(obj/item/gun/ballistic/source, mob/user) + if(jammed && do_after(user, jam_use_time, parent)) + COOLDOWN_START(src, jam_cooldown, jam_time) + user.balloon_alert(user, "Gun jam has been cleared!") + jammed = FALSE + +/datum/component/gun_jammable/proc/handle_stat_gain(atom/source, obj/item/attachment/attached) + SIGNAL_HANDLER + jamming_prob *= attached.misfire_multiplier + jam_use_time /= attached.ease_of_use + +/datum/component/gun_jammable/proc/handle_stat_loss(atom/source, obj/item/attachment/attached) + SIGNAL_HANDLER + jamming_prob /= attached.misfire_multiplier + jam_use_time *= attached.ease_of_use diff --git a/monkestation/code/modules/modular_guns/components/gun_stat_modifiers.dm b/monkestation/code/modules/modular_guns/components/gun_stat_modifiers.dm new file mode 100644 index 000000000000..e7ad6e902ae0 --- /dev/null +++ b/monkestation/code/modules/modular_guns/components/gun_stat_modifiers.dm @@ -0,0 +1,70 @@ +/* this proc handles storage and modification of stats on guns +for instance a stock decreases accuracy its modification is stored here +gun is damaged, we can reduce its fire rate here, feels cleaner than calling procs +on the parent of other components. +*/ + +/datum/component/gun_stat_holder + var/obj/item/gun/ballistic/owner_weapon + /// our guns stability, affects recoil and spread + var/stability + /// our guns loudness, affects gun sounds + var/loudness + /// our firing speed + var/firing_speed + /// our guns total wear and tear + var/usage_damage + /// our guns handlability + var/ease_of_use + +/datum/component/gun_stat_holder/Initialize(stability, loudness, firing_speed, usage_damage, jamming_potential, ease_of_use) + . = ..() + owner_weapon = parent + src.stability = stability + src.loudness = loudness + src.usage_damage = usage_damage + src.firing_speed = firing_speed + src.ease_of_use = ease_of_use + +/datum/component/gun_stat_holder/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATTACHMENT_ATTACHED, PROC_REF(handle_stat_gain)) + RegisterSignal(parent, COMSIG_ATTACHMENT_DETACHED, PROC_REF(handle_stat_loss)) + +/datum/component/gun_stat_holder/proc/handle_stat_gain(atom/source, obj/item/attachment/attached) + stability *= attached.stability + firing_speed *= attached.fire_multipler + loudness *= attached.noise_multiplier + ease_of_use *= attached.ease_of_use + redistribute_stats() + +/datum/component/gun_stat_holder/proc/handle_stat_loss(atom/source, obj/item/attachment/attached) + stability /= attached.stability + firing_speed /= attached.fire_multipler + loudness /= attached.noise_multiplier + ease_of_use /= attached.ease_of_use + attached.unique_attachment_effects_removal(parent) + redistribute_stats() + +///this is a shitcode handler until i convert all guns to the stat_holder_system +/datum/component/gun_stat_holder/proc/redistribute_stats() + reset_stats_to_base(parent) + var/obj/item/gun/gun = parent + + gun.spread = max(gun.spread - stability, 0) + gun.recoil +=(max(100 - stability, 0) * 0.01) + + gun.suppressed_volume *= (loudness * 0.01) + gun.fire_sound_volume *= (loudness * 0.01) + + gun.fire_delay *= (firing_speed * 0.01) + + ///we do this at the end and addon using unique shit + SEND_SIGNAL(gun, COMSIG_ATTACHMENT_STAT_RESET) + + +/datum/component/gun_stat_holder/proc/reset_stats_to_base(obj/item/gun/gun) + gun.spread = initial(gun.spread) + gun.suppressed_volume = initial(gun.suppressed_volume) + gun.recoil = initial(gun.recoil) + gun.fire_sound_volume = initial(gun.fire_sound_volume) + gun.fire_delay = initial(gun.fire_delay) diff --git a/monkestation/code/modules/modular_guns/crafting/part_recipes.dm b/monkestation/code/modules/modular_guns/crafting/part_recipes.dm new file mode 100644 index 000000000000..4e90d0de3073 --- /dev/null +++ b/monkestation/code/modules/modular_guns/crafting/part_recipes.dm @@ -0,0 +1,105 @@ +/datum/crafting_recipe/wood_mk58_stock + name = "Wooden MK58 Stock" + tool_paths = list(/obj/item/hatchet) + result = /obj/item/attachment/stock/mk58/wood + reqs = list( + /obj/item/stack/sheet/mineral/wood = 8, + /obj/item/stack/sticky_tape = 1, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/metal_mk58_stock + name = "Wooden MK58 Stock" + tool_behaviors = list(TOOL_WELDER) + result = /obj/item/attachment/stock/mk58/metal + reqs = list( + /obj/item/stack/sheet/mineral/titanium = 8, + /obj/item/stack/sticky_tape = 1, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_frame_makeshift + name = "Makeshift MK58 Frame" + result = /obj/item/attachment/frame/mk_58/makeshift + reqs = list( + /obj/item/stack/sheet/cardboard = 10, + /obj/item/stack/sticky_tape = 2, + /obj/item/stack/sheet/iron = 2, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_welrod + name = "MK58 Welrod" + tool_behaviors = list(TOOL_WELDER) + result = /obj/item/attachment/welrod/mk_58 + reqs = list( + /obj/item/stack/sheet/iron = 6, + ) + time = 7.5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_grip_makeshift + name = "Makeshift MK58 Grip" + result = /obj/item/attachment/grip/mk_58/makeshift + reqs = list( + /obj/item/stack/sheet/cardboard = 8, + /obj/item/stack/sticky_tape = 2, + /obj/item/stack/sheet/iron = 2, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_grip_colorable + name = "Colorable MK58 Grip" + tool_behaviors = list(TOOL_WELDER) + result = /obj/item/attachment/grip/mk_58/colorable + reqs = list( + /obj/item/stack/sheet/plastic = 12, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_frame_colorable + name = "Colorable MK58 Frame" + tool_behaviors = list(TOOL_WELDER) + result = /obj/item/attachment/frame/mk_58/colorable + reqs = list( + /obj/item/stack/sheet/plastic = 6, + /obj/item/stack/sheet/iron = 12, + ) + time = 5 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_m10mm_mag + name = "MK58 10mm Magslot" + tool_behaviors = list(TOOL_WELDER, TOOL_WRENCH) + result = /obj/item/attachment/mag/mk58/m10mm + reqs = list( + /obj/item/stack/sheet/iron = 5, + ) + time = 4 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_m50_mag + name = "MK58 .50ae Magslot" + tool_behaviors = list(TOOL_WELDER, TOOL_WRENCH) + result = /obj/item/attachment/mag/mk58/m50 + reqs = list( + /obj/item/stack/sheet/iron = 5, + ) + time = 4 SECONDS + category = CAT_GUNPARTS + +/datum/crafting_recipe/mk58_flashlight + name = "MK58 Flashlight Attachment" + tool_behaviors = list(TOOL_WELDER) + result = /obj/item/attachment/mag/mk58/m50 + reqs = list( + /obj/item/stack/sheet/iron = 2, + /obj/item/flashlight/seclite = 1, + ) + time = 4 SECONDS + category = CAT_GUNPARTS diff --git a/monkestation/code/modules/modular_guns/icons/ak.dmi b/monkestation/code/modules/modular_guns/icons/ak.dmi new file mode 100644 index 000000000000..aa04e303a97a Binary files /dev/null and b/monkestation/code/modules/modular_guns/icons/ak.dmi differ diff --git a/monkestation/code/modules/modular_guns/icons/mk58.dmi b/monkestation/code/modules/modular_guns/icons/mk58.dmi new file mode 100644 index 000000000000..c170a8b9e41d Binary files /dev/null and b/monkestation/code/modules/modular_guns/icons/mk58.dmi differ diff --git a/monkestation/code/modules/modular_guns/icons/wintermute.dmi b/monkestation/code/modules/modular_guns/icons/wintermute.dmi new file mode 100644 index 000000000000..34e4c6362b63 Binary files /dev/null and b/monkestation/code/modules/modular_guns/icons/wintermute.dmi differ diff --git a/monkestation/code/modules/modular_guns/makeshift_effects/__base_effect.dm b/monkestation/code/modules/modular_guns/makeshift_effects/__base_effect.dm new file mode 100644 index 000000000000..73cd40b17aff --- /dev/null +++ b/monkestation/code/modules/modular_guns/makeshift_effects/__base_effect.dm @@ -0,0 +1,14 @@ +/datum/makeshift_effect + var/effect_name = "Generic Makeshift Mishap" + var/effect_desc = "Causes a puff of smoke at the guns location." + + var/trigger_chance = 25 + +/datum/makeshift_effect/proc/attempt_trigger(atom/target) + if(prob(trigger_chance)) + do_smoke(range = 1, holder = target, location = get_turf(target), smoke_type = /obj/effect/particle_effect/fluid/smoke/quick) + return TRUE + return FALSE + +/obj/effect/particle_effect/fluid/smoke/quick + lifetime = 1.5 SECONDS diff --git a/monkestation/code/modules/modular_guns/readme.md b/monkestation/code/modules/modular_guns/readme.md new file mode 100644 index 000000000000..67c1ab0fc17f --- /dev/null +++ b/monkestation/code/modules/modular_guns/readme.md @@ -0,0 +1,38 @@ +## Title: + + +MODULE ID: MODULAR_WEAPONRY + +### Description: + +This adds a modular weaponry system and framework to ss13, it also acts as a test to see exactly how much +I can use components in lieu of adding shitty subtypes of subtypes + + + +### TG Proc/File Changes: + + - code\controllers\subsystem\blackmarket.dm + - code\modules\cargo\markets\market_uplink.dm + - code\modules\cargo\markets\_market.dm + +### Defines: + + +### Master file additions + +- N/A + + +### Included files that are not contained in this module: + +- N/A + + +### Credits: + + + +Made by Dwasint + +Original sprites from Eris diff --git a/monkestation/code/modules/pissing/bladder.dm b/monkestation/code/modules/pissing/bladder.dm index b221ab6122fc..74c05c2c37ff 100644 --- a/monkestation/code/modules/pissing/bladder.dm +++ b/monkestation/code/modules/pissing/bladder.dm @@ -79,6 +79,14 @@ valid_urinal = TRUE break + var/list/ignored_mobs = list() + for(var/mob/anything in GLOB.player_list) + if(!anything.client) + continue + if(!anything.client.prefs.read_preference(/datum/preference/toggle/prude_mode)) + continue + ignored_mobs |= anything + var/obj/item/reagent_containers/held_container if(owner.held_items[owner.active_hand_index] != null) var/obj/item/listed_item = owner.held_items[owner.active_hand_index] @@ -90,14 +98,14 @@ return if(valid_toilet) - owner.visible_message(span_notice("[owner] pisses into the toilet.")) + owner.visible_message(span_notice("[owner] pisses into the toilet."), ignored_mobs = ignored_mobs) return if(valid_urinal) - owner.visible_message(span_notice("[owner] carefully pisses into the urinal not spilling a drop.")) + owner.visible_message(span_notice("[owner] carefully pisses into the urinal not spilling a drop."), ignored_mobs = ignored_mobs) return - owner.visible_message(span_warning("[owner] pisses all over the floor!")) + owner.visible_message(span_warning("[owner] pisses all over the floor!"), ignored_mobs = ignored_mobs) stored_piss -= per_piss_usage diff --git a/monkestation/code/modules/pissing/emote.dm b/monkestation/code/modules/pissing/emote.dm index c4e7b8a80fd3..fbefc9922a6c 100644 --- a/monkestation/code/modules/pissing/emote.dm +++ b/monkestation/code/modules/pissing/emote.dm @@ -6,6 +6,7 @@ if(!user.get_organ_slot(ORGAN_SLOT_BLADDER) || !ishuman(user)) to_chat(user, "You don't have a bladder!") return - + if(user.client?.prefs.read_preference(/datum/preference/toggle/prude_mode)) + return var/obj/item/organ/internal/bladder/bladder = user.get_organ_slot(ORGAN_SLOT_BLADDER) bladder.urinate() diff --git a/monkestation/code/modules/storytellers/converted_events/_base_event.dm b/monkestation/code/modules/storytellers/converted_events/_base_event.dm index 3ea7df0c473a..9a375f0b7886 100644 --- a/monkestation/code/modules/storytellers/converted_events/_base_event.dm +++ b/monkestation/code/modules/storytellers/converted_events/_base_event.dm @@ -96,13 +96,6 @@ job_check += length(SSjob.assigned_players_by_job[enemy_job.type]) enemy_players += SSjob.assigned_players_by_job[enemy_job.type] - for(var/mob/enemy_mob in GLOB.alive_player_list) - if(enemy_mob.stat == DEAD) - continue // Dead players cannot count as opponents - if(enemy_mob.mind && (enemy_mob.mind.assigned_role.title in enemy_roles)) - job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it - enemy_players += enemy_mob - if(job_check >= required_enemies) return return_players ? enemy_players : TRUE return return_players ? enemy_players : FALSE @@ -212,7 +205,7 @@ if(!antag_mind.current) continue candidates += antag_mind.current -// SSgamemode.roundstart_antag_minds -= antag_mind //commented out for debugging in case something breaks + SSgamemode.roundstart_antag_minds -= antag_mind //commented out for debugging in case something breaks while(length(possible_candidates) && length(candidates) < antag_count) //both of these pick_n_take from possible_candidates so this should be fine if(prompted_picking) @@ -226,12 +219,14 @@ break var/mob/candidate = pick_n_take(candidates) + if(!candidate.mind) candidate.mind = new /datum/mind(candidate.key) setup_minds += candidate.mind candidate.mind.special_role = antag_flag candidate.mind.restricted_roles = restricted_roles + setup = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm b/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm index 9825ab7f68f3..d90993f09861 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -19,12 +19,17 @@ JOB_CYBORG, ) min_players = 20 + weight = 3 /datum/round_event_control/antagonist/solo/changeling/roundstart name = "Changelings" roundstart = TRUE earliest_start = 0 + maximum_antags = 1 + shared_occurences = list(/datum/round_event_control/antagonist/solo/changeling/midround) /datum/round_event_control/antagonist/solo/changeling/midround name = "Genome Awakening (Changelings)" prompted_picking = TRUE + max_occurrences = 2 + shared_occurences = list(/datum/round_event_control/antagonist/solo/changeling/roundstart) diff --git a/monkestation/code/modules/storytellers/gamemode_subsystem.dm b/monkestation/code/modules/storytellers/gamemode_subsystem.dm index 6e1252838818..d75f5a82fd3c 100644 --- a/monkestation/code/modules/storytellers/gamemode_subsystem.dm +++ b/monkestation/code/modules/storytellers/gamemode_subsystem.dm @@ -438,7 +438,7 @@ SUBSYSTEM_DEF(gamemode) var/high_pop_bound = pop_scale_thresholds[track] var/scale_penalty = pop_scale_penalties[track] - var/perceived_pop = max(low_pop_bound, active_players) // after max pop we start generating even more threat + var/perceived_pop = min(max(low_pop_bound, active_players), high_pop_bound) var/divisor = high_pop_bound - low_pop_bound /// If the bounds are equal, we'd be dividing by zero or worse, if upper is smaller than lower, we'd be increasing the factor, just make it 1 and continue. diff --git a/monkestation/code/modules/surgery/organs/internal/butts.dm b/monkestation/code/modules/surgery/organs/internal/butts.dm index c7747e73aa47..70c6c5e292f7 100644 --- a/monkestation/code/modules/surgery/organs/internal/butts.dm +++ b/monkestation/code/modules/surgery/organs/internal/butts.dm @@ -175,6 +175,15 @@ //EMOTE MESSAGE/MOB TARGETED FARTS var/hit_target = FALSE + + var/list/ignored_mobs = list() + for(var/mob/anything in GLOB.player_list) + if(!anything.client) + continue + if(!anything.client.prefs.read_preference(/datum/preference/toggle/prude_mode)) + continue + ignored_mobs |= anything + for(var/mob/living/Targeted in Location) if(Targeted != user) user.visible_message("[user] [pick( @@ -185,7 +194,7 @@ "commits an act of butthole bioterror all over [Targeted]!", "poots, singing [Targeted]'s eyebrows!", "humiliates [Targeted] like never before!", - "gets real close to [Targeted]'s face and cuts the cheese!")]") + "gets real close to [Targeted]'s face and cuts the cheese!")]", ignored_mobs = ignored_mobs) hit_target = TRUE break if(!hit_target) @@ -193,7 +202,7 @@ //SOUND HANDLING - playsound(user, pick(sound_effect), volume , use_reverb = TRUE, pressure_affected = FALSE) + playsound(user, pick(sound_effect), volume , use_reverb = TRUE, pressure_affected = FALSE, mixer_channel = CHANNEL_PRUDE) //GAS CREATION, ASS DETACHMENT & COOLDOWNS if(!cooling_down) @@ -257,7 +266,7 @@ new_butt.desc = "hiss!" new_butt.icon_state = "buttbot_xeno" - playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 25 ,use_reverb = TRUE, mixer_channel = CHANNEL_SOUND_EFFECTS) + playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 25 ,use_reverb = TRUE, mixer_channel = CHANNEL_PRUDE) qdel(src) @@ -285,7 +294,7 @@ bot_cover_flags |= BOT_COVER_EMAGGED var/turf/butt = get_turf(src) butt.atmos_spawn_air("miasma=5;TEMP=310.15") - playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 100 ,use_reverb = TRUE, mixer_channel = CHANNEL_SOUND_EFFECTS) + playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 100 ,use_reverb = TRUE, mixer_channel = CHANNEL_PRUDE) /mob/living/simple_animal/bot/buttbot/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods) . = ..() @@ -303,7 +312,7 @@ cooling_down = FALSE return say(joined_text) - playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 25 , use_reverb = TRUE, mixer_channel = CHANNEL_SOUND_EFFECTS) + playsound(src, pick('sound/misc/fart1.ogg', 'monkestation/sound/effects/fart2.ogg', 'monkestation/sound/effects/fart3.ogg', 'monkestation/sound/effects/fart4.ogg'), 25 , use_reverb = TRUE, mixer_channel = CHANNEL_PRUDE) spawn(20) cooling_down = FALSE diff --git a/monkestation/code/modules/virology/disease/symtoms/stage4.dm b/monkestation/code/modules/virology/disease/symtoms/stage4.dm index 09813e1d4211..f6bf9943abf3 100644 --- a/monkestation/code/modules/virology/disease/symtoms/stage4.dm +++ b/monkestation/code/modules/virology/disease/symtoms/stage4.dm @@ -238,10 +238,17 @@ var/datum/dna/saved_dna var/original_name var/activated = 0 + ///old info + var/datum/dna/old_dna + var/old_name /datum/symptom/dnaspread/activate(mob/living/carbon/mob) if(!activated) to_chat(mob, span_warning("You don't feel like yourself..")) + old_dna = new + C.dna.copy_dna(old_dna) + old_name = C.real_name + if(!iscarbon(mob)) return var/mob/living/carbon/C = mob @@ -256,6 +263,10 @@ /datum/symptom/dnaspread/deactivate(mob/living/carbon/mob) activated = FALSE + if(!old_dna) + return + old_dna.copy_dna(C.dna) + C.real_name = old_name /datum/symptom/dnaspread/Copy(datum/disease/advanced/disease) var/datum/symptom/dnaspread/new_e = ..(disease) diff --git a/monkestation/code/modules/wiremod_chem/components/inputs/fermenter_input.dm b/monkestation/code/modules/wiremod_chem/components/inputs/fermenter_input.dm index 4255583a6662..7233d4fc49cd 100644 --- a/monkestation/code/modules/wiremod_chem/components/inputs/fermenter_input.dm +++ b/monkestation/code/modules/wiremod_chem/components/inputs/fermenter_input.dm @@ -5,6 +5,7 @@ icon = 'icons/obj/plumbing/plumbers.dmi' reagent_flags = TRANSPARENT | DRAINABLE component_name = "Fermenter Input" + density = FALSE /obj/structure/chemical_input/fermenter/Initialize(mapload, bolt, layer) diff --git a/monkestation/code/modules/wiremod_chem/components/inputs/grinder_input.dm b/monkestation/code/modules/wiremod_chem/components/inputs/grinder_input.dm index e989ed83ddfc..a502fe3f04a8 100644 --- a/monkestation/code/modules/wiremod_chem/components/inputs/grinder_input.dm +++ b/monkestation/code/modules/wiremod_chem/components/inputs/grinder_input.dm @@ -5,6 +5,7 @@ icon_state = "grinder_chemical" reagent_flags = TRANSPARENT | DRAINABLE component_name = "Grinder Input" + density = FALSE /obj/structure/chemical_input/grinder/Initialize(mapload, bolt, layer) . = ..() diff --git a/rust_g.dll b/rust_g.dll index 059c79e34029..30f63e72f4b1 100644 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/tgstation.dme b/tgstation.dme index b9cf0383be47..53f8f1eb820d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -393,16 +393,19 @@ #include "code\__DEFINES\~monkestation\cooldowns.dm" #include "code\__DEFINES\~monkestation\DNA.dm" #include "code\__DEFINES\~monkestation\factions.dm" +#include "code\__DEFINES\~monkestation\guns.dm" #include "code\__DEFINES\~monkestation\interaction_particles.dm" #include "code\__DEFINES\~monkestation\keybinding.dm" #include "code\__DEFINES\~monkestation\level_traits.dm" #include "code\__DEFINES\~monkestation\logging.dm" #include "code\__DEFINES\~monkestation\maps.dm" +#include "code\__DEFINES\~monkestation\market.dm" #include "code\__DEFINES\~monkestation\mecha.dm" #include "code\__DEFINES\~monkestation\misc.dm" #include "code\__DEFINES\~monkestation\mobs.dm" #include "code\__DEFINES\~monkestation\particles.dm" #include "code\__DEFINES\~monkestation\physics.dm" +#include "code\__DEFINES\~monkestation\projectiles.dm" #include "code\__DEFINES\~monkestation\robots.dm" #include "code\__DEFINES\~monkestation\smoothing.dm" #include "code\__DEFINES\~monkestation\span.dm" @@ -415,6 +418,7 @@ #include "code\__DEFINES\~monkestation\virology.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" +#include "code\__DEFINES\~monkestation\dcs\signals\signals_guns.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_traitor.dm" #include "code\__HELPERS\_auxtools_api.dm" #include "code\__HELPERS\_lists.dm" @@ -3971,6 +3975,7 @@ #include "code\modules\logging\categories\log_category_compats.dm" #include "code\modules\logging\categories\log_category_debug.dm" #include "code\modules\logging\categories\log_category_game.dm" +#include "code\modules\logging\categories\log_category_internal.dm" #include "code\modules\logging\categories\log_category_misc.dm" #include "code\modules\logging\categories\log_category_monke.dm" #include "code\modules\logging\categories\log_category_pda.dm" @@ -6060,6 +6065,7 @@ #include "monkestation\code\modules\client\preferences\interaction_mode.dm" #include "monkestation\code\modules\client\preferences\inventory.dm" #include "monkestation\code\modules\client\preferences\loadout_override_preference.dm" +#include "monkestation\code\modules\client\preferences\prude.dm" #include "monkestation\code\modules\client\preferences\runechat.dm" #include "monkestation\code\modules\client\preferences\sounds.dm" #include "monkestation\code\modules\client\preferences\alt_jobs\_job.dm" @@ -6359,6 +6365,71 @@ #include "monkestation\code\modules\modular_bartending\item_modifications\reagent_modification.dm" #include "monkestation\code\modules\modular_bartending\reactions\food_reactions.dm" #include "monkestation\code\modules\modular_computers\file_system\programs\crewmanifest.dm" +#include "monkestation\code\modules\modular_guns\__base_attachment.dm" +#include "monkestation\code\modules\modular_guns\__base_modular_gun.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\__base_attachment_datum.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\barrels.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\frames.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\grip.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\keychains.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\magazine.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\sight.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\stock.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\underbarrel.dm" +#include "monkestation\code\modules\modular_guns\attachment_datums\welrod.dm" +#include "monkestation\code\modules\modular_guns\ballistics\frames\ak.dm" +#include "monkestation\code\modules\modular_guns\ballistics\frames\ak_st.dm" +#include "monkestation\code\modules\modular_guns\ballistics\frames\mk58.dm" +#include "monkestation\code\modules\modular_guns\ballistics\frames\wintermute.dm" +#include "monkestation\code\modules\modular_guns\ballistics\frames\wintermute_sl.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\barrel\_base_barrels.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\barrel\mk58\standard_barrels.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\frames\_base_frame.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\frames\mk58\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\frames\mk58\standard_frames.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\_base_grips.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\ak\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\ak\standard_grips.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\ak-st\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\ak-st\standard_grips.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\mk58\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\mk58\standard_grips.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\wintermute\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\grips\wintermute\standard_grips.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\keychains\_base_keychains.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\keychains\mk58\standard_keychains.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\mags\_base_mag.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\mags\ak\standard_mags.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\mags\ak-st\standard_mags.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\mags\mk58\standard_mags.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\mags\wintermute\standard_mags.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\sights\_base_sights.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\sights\mk58\standard_sights.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\_base_stock.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\ak\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\ak\standard_stocks.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\ak-st\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\ak-st\standard_stocks.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\mk_58\standard_stocks.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\wintermute\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\stocks\wintermute\standard_stocks.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\underbarrel\_base_underbarrel.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\underbarrel\flashlight\_base_flashlight.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\underbarrel\flashlight\mk58.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\underbarrel\mk58\makeshift.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\underbarrel\mk58\standard_underbarrel.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\welrod\_base_welrod.dm" +#include "monkestation\code\modules\modular_guns\ballistics\parts\welrod\mk58\standard_welrod.dm" +#include "monkestation\code\modules\modular_guns\blackmarket\auction.dm" +#include "monkestation\code\modules\modular_guns\blackmarket\restock_market.dm" +#include "monkestation\code\modules\modular_guns\blackmarket\auction_items\gun_parts.dm" +#include "monkestation\code\modules\modular_guns\blackmarket\auction_items\restock_gun_parts.dm" +#include "monkestation\code\modules\modular_guns\components\attachments.dm" +#include "monkestation\code\modules\modular_guns\components\ghetto.dm" +#include "monkestation\code\modules\modular_guns\components\gun_jammable.dm" +#include "monkestation\code\modules\modular_guns\components\gun_stat_modifiers.dm" +#include "monkestation\code\modules\modular_guns\crafting\part_recipes.dm" +#include "monkestation\code\modules\modular_guns\makeshift_effects\__base_effect.dm" #include "monkestation\code\modules\ocean_content\department_consoles\engineering.dm" #include "monkestation\code\modules\ocean_content\fluff\barrier.dm" #include "monkestation\code\modules\ocean_content\fluff\base_turf_editor.dm" diff --git a/tgui/packages/tgui/interfaces/BlackMarketUplink.js b/tgui/packages/tgui/interfaces/BlackMarketUplink.js index 627386997e9f..ee446f22f00f 100644 --- a/tgui/packages/tgui/interfaces/BlackMarketUplink.js +++ b/tgui/packages/tgui/interfaces/BlackMarketUplink.js @@ -1,6 +1,7 @@ +import { round } from 'common/math'; import { useBackend } from '../backend'; -import { AnimatedNumber, Box, Button, Modal, Section, Stack, Tabs } from '../components'; -import { formatMoney } from '../format'; +import { AnimatedNumber, Box, Button, Modal, Section, Stack, Tabs, Slider } from '../components'; +import { formatMoney, formatTime } from '../format'; import { Window } from '../layouts'; export const BlackMarketUplink = (props, context) => { @@ -12,82 +13,40 @@ export const BlackMarketUplink = (props, context) => { money, viewing_market, viewing_category, + auction, } = data; return ( -
- formatMoney(value) + ' cr'} - /> - - } - /> - - {markets.map((market) => ( - - act('set_market', { - market: market.id, - }) - }> - {market.name} - - ))} - - - - - {categories.map((category) => ( - - act('set_category', { - category: category, - }) - }> - {category} - - ))} - - - - {items.map((item) => ( - - - - {item.name} - - - {item.amount ? item.amount + ' in stock' : 'Out of stock'} - - {formatMoney(item.cost) + ' cr'} - -