From cb346a3847f26a9e6e5d80a01136210c6006b009 Mon Sep 17 00:00:00 2001
From: Letter N <24603524+LetterN@users.noreply.github.com>
Date: Fri, 5 Mar 2021 14:29:36 +0800
Subject: [PATCH] a
---
.github/workflows/ci_suite.yml | 4 +-
code/__HELPERS/unsorted.dm | 44 +++--
code/_onclick/hud/plane_master.dm | 3 -
code/datums/callback.dm | 176 +++++++++---------
code/datums/components/material_container.dm | 95 ++++++++--
code/datums/materials/_material.dm | 111 ++++++++---
code/game/atoms.dm | 6 +-
code/game/objects/items/stacks/cash.dm | 2 +-
.../game/objects/items/stacks/sheets/glass.dm | 14 +-
.../objects/items/stacks/sheets/sheets.dm | 2 +-
code/game/objects/items/stacks/stack.dm | 84 +++++----
code/modules/admin/callproc/callproc.dm | 59 +++---
.../machinery/portable/canister.dm | 2 -
code/modules/power/cable.dm | 11 +-
tools/build/build.js | 1 +
tools/ci/check_grep.sh | 2 +-
tools/ci/run_server.sh | 5 +
17 files changed, 386 insertions(+), 235 deletions(-)
diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml
index 168807e742..a6b91bd559 100644
--- a/.github/workflows/ci_suite.yml
+++ b/.github/workflows/ci_suite.yml
@@ -98,8 +98,8 @@ jobs:
bash tools/ci/install_byond.sh
source $HOME/BYOND/byond/bin/byondsetup
tgui/bin/tgui --build
- # bash tools/ci/dm.sh -DCIBUILDING tgstation.dme
- # bash tools/ci/run_server.sh
+ bash tools/ci/dm.sh -DCIBUILDING tgstation.dme
+ # bash tools/ci/run_server.sh
test_windows:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index d0bb17efd2..ee4b09d42c 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1247,28 +1247,40 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
#define FOR_DVIEW_END GLOB.dview_mob.loc = null
-//can a window be here, or is there a window blocking it?
-/proc/valid_window_location(turf/T, dir_to_check)
- if(!T)
+/**
+ * Checks whether the target turf is in a valid state to accept a directional window
+ * or other directional pseudo-dense object such as railings.
+ *
+ * Returns FALSE if the target turf cannot accept a directional window or railing.
+ * Returns TRUE otherwise.
+ *
+ * Arguments:
+ * * dest_turf - The destination turf to check for existing windows and railings
+ * * test_dir - The prospective dir of some atom you'd like to put on this turf.
+ * * is_fulltile - Whether the thing you're attempting to move to this turf takes up the entire tile or whether it supports multiple movable atoms on its tile.
+ */
+/proc/valid_window_location(turf/dest_turf, test_dir, is_fulltile = FALSE)
+ if(!dest_turf)
return FALSE
- for(var/obj/O in T)
- if(istype(O, /obj/machinery/door/window) && (O.dir == dir_to_check || dir_to_check == FULLTILE_WINDOW_DIR))
- return FALSE
- if(istype(O, /obj/structure/windoor_assembly))
- var/obj/structure/windoor_assembly/W = O
- if(W.ini_dir == dir_to_check || dir_to_check == FULLTILE_WINDOW_DIR)
+ for(var/obj/turf_content in dest_turf)
+ if(istype(turf_content, /obj/machinery/door/window))
+ if((turf_content.dir == test_dir) || is_fulltile)
return FALSE
- if(istype(O, /obj/structure/window))
- var/obj/structure/window/W = O
- if(W.ini_dir == dir_to_check || W.ini_dir == FULLTILE_WINDOW_DIR || dir_to_check == FULLTILE_WINDOW_DIR)
+ if(istype(turf_content, /obj/structure/windoor_assembly))
+ var/obj/structure/windoor_assembly/windoor_assembly = turf_content
+ if(windoor_assembly.dir == test_dir || is_fulltile)
return FALSE
- if(istype(O, /obj/structure/railing))
- var/obj/structure/railing/rail = O
- if(rail.ini_dir == dir_to_check || rail.ini_dir == FULLTILE_WINDOW_DIR || dir_to_check == FULLTILE_WINDOW_DIR)
+ if(istype(turf_content, /obj/structure/window))
+ var/obj/structure/window/window_structure = turf_content
+ if(window_structure.dir == test_dir || window_structure.fulltile || is_fulltile)
+ return FALSE
+ if(istype(turf_content, /obj/structure/railing))
+ var/obj/structure/railing/rail = turf_content
+ if(rail.dir == test_dir || is_fulltile)
return FALSE
return TRUE
-/proc/pass()
+/proc/pass(...)
return
/proc/get_mob_or_brainmob(occupant)
diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm
index f5b8991e20..4c736c9a2b 100644
--- a/code/_onclick/hud/plane_master.dm
+++ b/code/_onclick/hud/plane_master.dm
@@ -38,9 +38,6 @@
/obj/screen/plane_master/proc/shadow(_size, _offset = 0, _x = 0, _y = 0, _color = "#04080FAA")
filters += filter(type = "drop_shadow", x = _x, y = _y, color = _color, size = _size, offset = _offset)
-/obj/screen/plane_master/proc/clear_filters()
- filters = list()
-
///Contains just the floor
/obj/screen/plane_master/floor
name = "floor plane master"
diff --git a/code/datums/callback.dm b/code/datums/callback.dm
index 62e10922f3..b5baea28f1 100644
--- a/code/datums/callback.dm
+++ b/code/datums/callback.dm
@@ -1,53 +1,53 @@
/**
- *# Callback Datums
- *A datum that holds a proc to be called on another object, used to track proccalls to other objects
- *
- * ## USAGE
- *
- * ```
- * var/datum/callback/C = new(object|null, /proc/type/path|"procstring", arg1, arg2, ... argn)
- * var/timerid = addtimer(C, time, timertype)
- * you can also use the compiler define shorthand
- * var/timerid = addtimer(CALLBACK(object|null, /proc/type/path|procstring, arg1, arg2, ... argn), time, timertype)
- * ```
- *
- * Note: proc strings can only be given for datum proc calls, global procs must be proc paths
- *
- * Also proc strings are strongly advised against because they don't compile error if the proc stops existing
- *
- * In some cases you can provide a shortform of the procname, see the proc typepath shortcuts documentation below
- *
- * ## INVOKING THE CALLBACK
- *`var/result = C.Invoke(args, to, add)` additional args are added after the ones given when the callback was created
- *
- * `var/result = C.InvokeAsync(args, to, add)` Asyncronous - returns . on the first sleep then continues on in the background
- * after the sleep/block ends, otherwise operates normally.
- *
- * ## PROC TYPEPATH SHORTCUTS
- * (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...)
- *
- * ### global proc while in another global proc:
- * .procname
- *
- * `CALLBACK(GLOBAL_PROC, .some_proc_here)`
- *
- * ### proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents:
- * .procname
- *
- * `CALLBACK(src, .some_proc_here)`
- *
- * ### when the above doesn't apply:
- *.proc/procname
- *
- * `CALLBACK(src, .proc/some_proc_here)`
- *
- *
- * proc defined on a parent of a some type
- *
- * `/some/type/.proc/some_proc_here`
- *
- * Otherwise you must always provide the full typepath of the proc (/type/of/thing/proc/procname)
- */
+ *# Callback Datums
+ *A datum that holds a proc to be called on another object, used to track proccalls to other objects
+ *
+ * ## USAGE
+ *
+ * ```
+ * var/datum/callback/C = new(object|null, /proc/type/path|"procstring", arg1, arg2, ... argn)
+ * var/timerid = addtimer(C, time, timertype)
+ * you can also use the compiler define shorthand
+ * var/timerid = addtimer(CALLBACK(object|null, /proc/type/path|procstring, arg1, arg2, ... argn), time, timertype)
+ * ```
+ *
+ * Note: proc strings can only be given for datum proc calls, global procs must be proc paths
+ *
+ * Also proc strings are strongly advised against because they don't compile error if the proc stops existing
+ *
+ * In some cases you can provide a shortform of the procname, see the proc typepath shortcuts documentation below
+ *
+ * ## INVOKING THE CALLBACK
+ *`var/result = C.Invoke(args, to, add)` additional args are added after the ones given when the callback was created
+ *
+ * `var/result = C.InvokeAsync(args, to, add)` Asyncronous - returns . on the first sleep then continues on in the background
+ * after the sleep/block ends, otherwise operates normally.
+ *
+ * ## PROC TYPEPATH SHORTCUTS
+ * (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...)
+ *
+ * ### global proc while in another global proc:
+ * .procname
+ *
+ * `CALLBACK(GLOBAL_PROC, .some_proc_here)`
+ *
+ * ### proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents:
+ * .procname
+ *
+ * `CALLBACK(src, .some_proc_here)`
+ *
+ * ### when the above doesn't apply:
+ *.proc/procname
+ *
+ * `CALLBACK(src, .proc/some_proc_here)`
+ *
+ *
+ * proc defined on a parent of a some type
+ *
+ * `/some/type/.proc/some_proc_here`
+ *
+ * Otherwise you must always provide the full typepath of the proc (/type/of/thing/proc/procname)
+ */
/datum/callback
///The object we will be calling the proc on
@@ -60,13 +60,13 @@
var/datum/weakref/user
/**
- * Create a new callback datum
- *
- * Arguments
- * * thingtocall the object to call the proc on
- * * proctocall the proc to call on the target object
- * * ... an optional list of extra arguments to pass to the proc
- */
+ * Create a new callback datum
+ *
+ * Arguments
+ * * thingtocall the object to call the proc on
+ * * proctocall the proc to call on the target object
+ * * ... an optional list of extra arguments to pass to the proc
+ */
/datum/callback/New(thingtocall, proctocall, ...)
if (thingtocall)
object = thingtocall
@@ -76,13 +76,13 @@
if(usr)
user = WEAKREF(usr)
/**
- * Immediately Invoke proctocall on thingtocall, with waitfor set to false
- *
- * Arguments:
- * * thingtocall Object to call on
- * * proctocall Proc to call on that object
- * * ... optional list of arguments to pass as arguments to the proc being called
- */
+ * Immediately Invoke proctocall on thingtocall, with waitfor set to false
+ *
+ * Arguments:
+ * * thingtocall Object to call on
+ * * proctocall Proc to call on that object
+ * * ... optional list of arguments to pass as arguments to the proc being called
+ */
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
set waitfor = FALSE
@@ -97,13 +97,13 @@
call(thingtocall, proctocall)(arglist(calling_arguments))
/**
- * Invoke this callback
- *
- * Calls the registered proc on the registered object, if the user ref
- * can be resolved it also inclues that as an arg
- *
- * If the datum being called on is varedited, the call is wrapped via WrapAdminProcCall
- */
+ * Invoke this callback
+ *
+ * Calls the registered proc on the registered object, if the user ref
+ * can be resolved it also inclues that as an arg
+ *
+ * If the datum being called on is varedited, the call is wrapped via [WrapAdminProcCall][/proc/WrapAdminProcCall]
+ */
/datum/callback/proc/Invoke(...)
if(!usr)
var/datum/weakref/W = user
@@ -130,13 +130,13 @@
return call(object, delegate)(arglist(calling_arguments))
/**
- * Invoke this callback async (waitfor=false)
- *
- * Calls the registered proc on the registered object, if the user ref
- * can be resolved it also inclues that as an arg
- *
- * If the datum being called on is varedited, the call is wrapped via WrapAdminProcCall
- */
+ * Invoke this callback async (waitfor=false)
+ *
+ * Calls the registered proc on the registered object, if the user ref
+ * can be resolved it also inclues that as an arg
+ *
+ * If the datum being called on is varedited, the call is wrapped via WrapAdminProcCall
+ */
/datum/callback/proc/InvokeAsync(...)
set waitfor = FALSE
@@ -166,7 +166,7 @@
/**
Helper datum for the select callbacks proc
- */
+ */
/datum/callback_select
var/list/finished
var/pendingcount
@@ -192,16 +192,16 @@
finished[index] = rtn
/**
- * Runs a list of callbacks asyncronously, returning only when all have finished
- *
- * Callbacks can be repeated, to call it multiple times
- *
- * Arguments:
- * * list/callbacks the list of callbacks to be called
- * * list/callback_args the list of lists of arguments to pass into each callback
- * * savereturns Optionally save and return the list of returned values from each of the callbacks
- * * resolution The number of byond ticks between each time you check if all callbacks are complete
- */
+ * Runs a list of callbacks asyncronously, returning only when all have finished
+ *
+ * Callbacks can be repeated, to call it multiple times
+ *
+ * Arguments:
+ * * list/callbacks the list of callbacks to be called
+ * * list/callback_args the list of lists of arguments to pass into each callback
+ * * savereturns Optionally save and return the list of returned values from each of the callbacks
+ * * resolution The number of byond ticks between each time you check if all callbacks are complete
+ */
/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
if (!callbacks)
return
diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm
index 7adc634621..24f043db36 100644
--- a/code/datums/components/material_container.dm
+++ b/code/datums/components/material_container.dm
@@ -10,25 +10,37 @@
*/
/datum/component/material_container
+ /// The total amount of materials this material container contains
var/total_amount = 0
+ /// The maximum amount of materials this material container can contain
var/max_amount
- var/sheet_type
+ /// Map of material ref -> amount
var/list/materials //Map of key = material ref | Value = amount
+ /// The list of materials that this material container can accept
+ var/list/allowed_materials
var/show_on_examine
var/disable_attackby
var/list/allowed_typecache
+ /// The last main material that was inserted into this container
var/last_inserted_id
+ /// Whether or not this material container allows specific amounts from sheets to be inserted
var/precise_insertion = FALSE
+ /// A callback invoked before materials are inserted into this container
var/datum/callback/precondition
+ /// A callback invoked after materials are inserted into this container
var/datum/callback/after_insert
/// Sets up the proper signals and fills the list of materials with the appropriate references.
/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert, _disable_attackby)
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
materials = list()
max_amount = max(0, max_amt)
show_on_examine = _show_on_examine
disable_attackby = _disable_attackby
+ allowed_materials = mat_list || list()
if(allowed_types)
if(ispath(allowed_types) && allowed_types == /obj/item/stack)
allowed_typecache = GLOB.typecache_stack
@@ -38,14 +50,32 @@
precondition = _precondition
after_insert = _after_insert
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
- RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/OnExamine)
+ RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attackby)
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
- for(var/mat in mat_list) //Make the assoc list ref | amount
- var/datum/material/M = SSmaterials.GetMaterialRef(mat)
- materials[M] = 0
+ for(var/mat in mat_list) //Make the assoc list material reference -> amount
+ var/mat_ref = SSmaterials.GetMaterialRef(mat)
+ if(isnull(mat_ref))
+ continue
+ var/mat_amt = mat_list[mat]
+ if(isnull(mat_amt))
+ mat_amt = 0
+ materials[mat_ref] += mat_amt
+
+/datum/component/material_container/Destroy(force, silent)
+ materials = null
+ allowed_typecache = null
+ // if(insertion_check)
+ // QDEL_NULL(insertion_check)
+ if(precondition)
+ QDEL_NULL(precondition)
+ if(after_insert)
+ QDEL_NULL(after_insert)
+ return ..()
+
+/datum/component/material_container/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
-/datum/component/material_container/proc/OnExamine(datum/source, mob/user, list/examine_list)
if(show_on_examine)
for(var/I in materials)
var/datum/material/M = I
@@ -54,7 +84,9 @@
examine_list += "It has [amt] units of [lowertext(M.name)] stored."
/// Proc that allows players to fill the parent with mats
-/datum/component/material_container/proc/OnAttackBy(datum/source, obj/item/I, mob/living/user)
+/datum/component/material_container/proc/on_attackby(datum/source, obj/item/I, mob/living/user)
+ SIGNAL_HANDLER
+
var/list/tc = allowed_typecache
if(disable_attackby)
return
@@ -63,20 +95,21 @@
if(I.item_flags & ABSTRACT)
return
if((I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION) || (tc && !is_type_in_typecache(I, tc)))
+ // if(!(mat_container_flags & MATCONTAINER_SILENT))
to_chat(user, "[parent] won't accept [I]!")
return
. = COMPONENT_NO_AFTERATTACK
var/datum/callback/pc = precondition
if(pc && !pc.Invoke(user))
return
- var/material_amount = get_item_material_amount(I)
+ var/material_amount = get_item_material_amount(I) //, mat_container_flags)
if(!material_amount)
to_chat(user, "[I] does not contain sufficient materials to be accepted by [parent].")
return
if((!precise_insertion || !GLOB.typecache_stack[I.type]) && !has_space(material_amount))
- to_chat(user, "[parent] has not enough space. Please remove materials from [parent] in order to insert more.")
+ to_chat(user, "[parent] is full. Please remove materials from [parent] in order to insert more.")
return
- user_insert(I, user)
+ user_insert(I, user) //, mat_container_flags)
/// Proc used for when player inserts materials
/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user)
@@ -94,7 +127,7 @@
if(!user.temporarilyRemoveItemFromInventory(I))
to_chat(user, "[I] is stuck to you and cannot be placed into [parent].")
return
- var/inserted = insert_item(I, stack_amt = requested_amount)
+ var/inserted = insert_item(I, stack_amt = requested_amount)//, breakdown_flags= mat_container_flags)
if(inserted)
to_chat(user, "You insert a material total of [inserted] into [parent].")
qdel(I)
@@ -117,16 +150,46 @@
last_inserted_id = insert_item_materials(I, multiplier)
return material_amount
+/**
+ * Inserts the relevant materials from an item into this material container.
+ *
+ * Arguments:
+ * - [source][/obj/item]: The source of the materials we are inserting.
+ * - multiplier: The multiplier for the materials being inserted.
+ * - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source
+ */
/datum/component/material_container/proc/insert_item_materials(obj/item/I, multiplier = 1)
var/primary_mat
var/max_mat_value = 0
- for(var/MAT in materials)
- materials[MAT] += I.custom_materials[MAT] * multiplier
- total_amount += I.custom_materials[MAT] * multiplier
- if(I.custom_materials[MAT] > max_mat_value)
+ var/list/item_materials = I.custom_materials
+ for(var/MAT in item_materials)
+ if(!can_hold_material(MAT))
+ continue
+ materials[MAT] += item_materials[MAT] * multiplier
+ total_amount += item_materials[MAT] * multiplier
+ if(item_materials[MAT] > max_mat_value)
+ max_mat_value = item_materials[MAT]
primary_mat = MAT
+
return primary_mat
+/**
+ * The default check for whether we can add materials to this material container.
+ *
+ * Arguments:
+ * - [mat][/atom/material]: The material we are checking for insertability.
+ */
+/datum/component/material_container/proc/can_hold_material(datum/material/mat)
+ if(mat in allowed_typecache)
+ return TRUE
+ if(istype(mat) && (((mat.id in allowed_typecache) ||mat.type in allowed_materials)))
+ allowed_materials += mat // This could get messy with passing lists by ref... but if you're doing that the list expansion is probably being taken care of elsewhere anyway...
+ return TRUE
+ // if(insertion_check?.Invoke(mat))
+ // allowed_materials += mat
+ // return TRUE
+ return FALSE
+
/// For inserting an amount of material
/datum/component/material_container/proc/insert_amount_mat(amt, var/datum/material/mat)
if(!istype(mat))
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index 5148aab4ac..ec8037cfa6 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -1,15 +1,24 @@
/*! Material datum
+
Simple datum which is instanced once per type and is used for every object of said material. It has a variety of variables that define behavior. Subtyping from this makes it easier to create your own materials.
+
*/
/datum/material
+ /// What the material is referred to as IC.
var/name = "material"
+ /// A short description of the material. Not used anywhere, yet...
var/desc = "its..stuff."
+ /// What the material is indexed by in the SSmaterials.materials list. Defaults to the type of the material.
+ var/id
+
///Base color of the material, is used for greyscale. Item isn't changed in color if this is null.
var/color
///Base alpha of the material, is used for greyscale icons.
var/alpha
+ ///Bitflags that influence how SSmaterials handles this material.
+ // var/init_flags = MATERIAL_INIT_MAPLOAD
///Materials "Traits". its a map of key = category | Value = Bool. Used to define what it can be used for
var/list/categories = list()
///The type of sheet this material creates. This should be replaced as soon as possible by greyscale sheets
@@ -22,7 +31,7 @@ Simple datum which is instanced once per type and is used for every object of sa
var/value_per_unit = 0
///Armor modifiers, multiplies an items normal armor vars by these amounts.
var/armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1, "acid" = 1)
- ///How beautiful is this material per unit?
+ ///How beautiful is this material per unit.
var/beauty_modifier = 0
///Can be used to override the sound items make, lets add some SLOSHing.
var/item_sound_override
@@ -30,14 +39,31 @@ Simple datum which is instanced once per type and is used for every object of sa
var/turf_sound_override
///what texture icon state to overlay
var/texture_layer_icon_state
- ///a cached filter for the texture icon
+ ///a cached icon for the texture filter
var/cached_texture_filter
+ ///What type of shard the material will shatter to
+ var/obj/item/shard_type
+
+
+/** Handles initializing the material.
+ *
+ * Arugments:
+ * - _id: The ID the material should use. Overrides the existing ID.
+ */
+/datum/material/proc/Initialize(_id, ...)
+ if(_id)
+ id = _id
+ else if(isnull(id))
+ id = type
+
+ if(texture_layer_icon_state)
+ cached_texture_filter = icon('icons/materials/composite.dmi', texture_layer_icon_state)
+
+ return TRUE
/datum/material/New()
. = ..()
- if(texture_layer_icon_state)
- var/texture_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state)
- cached_texture_filter = filter(type="layer", icon=texture_icon, blend_mode = BLEND_INSET_OVERLAY)
+ Initialize()
///This proc is called when the material is added to an object.
/datum/material/proc/on_applied(atom/source, amount, material_flags)
@@ -48,8 +74,10 @@ Simple datum which is instanced once per type and is used for every object of sa
source.alpha = alpha
if(texture_layer_icon_state)
ADD_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
- source.filters += cached_texture_filter
+ source.add_filter("material_texture_[name]",1,layering_filter(icon=cached_texture_filter,blend_mode=BLEND_INSET_OVERLAY))
+ if(alpha < 255)
+ source.opacity = FALSE
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = "[name] [source.name]"
@@ -59,7 +87,7 @@ Simple datum which is instanced once per type and is used for every object of sa
if(istype(source, /obj)) //objs
on_applied_obj(source, amount, material_flags)
- else if(isturf(source, /turf)) //turfs
+ if(istype(source, /turf)) //turfs
on_applied_turf(source, amount, material_flags)
source.mat_update_desc(src)
@@ -67,8 +95,9 @@ Simple datum which is instanced once per type and is used for every object of sa
///This proc is called when a material updates an object's description
/atom/proc/mat_update_desc(/datum/material/mat)
return
+
///This proc is called when the material is added to an object specifically.
-/datum/material/proc/on_applied_obj(var/obj/o, amount, material_flags)
+/datum/material/proc/on_applied_obj(obj/o, amount, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/new_max_integrity = CEILING(o.max_integrity * integrity_modifier, 1)
o.modify_max_integrity(new_max_integrity)
@@ -92,43 +121,73 @@ Simple datum which is instanced once per type and is used for every object of sa
I.hitsound = item_sound_override
I.usesound = item_sound_override
I.throwhitsound = item_sound_override
+ // I.mob_throw_hit_sound = item_sound_override
+ // I.equip_sound = item_sound_override
+ // I.pickup_sound = item_sound_override
+ // I.drop_sound = item_sound_override
-/datum/material/proc/on_applied_turf(var/turf/T, amount, material_flags)
+/datum/material/proc/on_applied_turf(turf/T, amount, material_flags)
if(isopenturf(T))
- if(!turf_sound_override)
- return
- var/turf/open/O = T
- O.footstep = turf_sound_override
- O.barefootstep = turf_sound_override
- O.clawfootstep = turf_sound_override
- O.heavyfootstep = turf_sound_override
+ if(turf_sound_override)
+ var/turf/open/O = T
+ O.footstep = turf_sound_override
+ O.barefootstep = turf_sound_override
+ O.clawfootstep = turf_sound_override
+ O.heavyfootstep = turf_sound_override
+ // if(alpha < 255)
+ // T.AddElement(/datum/element/turf_z_transparency, TRUE)
+ return
///This proc is called when the material is removed from an object.
-/datum/material/proc/on_removed(atom/source, material_flags)
+/datum/material/proc/on_removed(atom/source, amount, material_flags)
if(material_flags & MATERIAL_COLOR) //Prevent changing things with pre-set colors, to keep colored toolboxes their looks for example
if(color)
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
- source.alpha = initial(source.alpha)
if(texture_layer_icon_state)
- source.filters -= cached_texture_filter
+ source.remove_filter("material_texture_[name]")
REMOVE_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
+ source.alpha = initial(source.alpha)
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = initial(source.name)
- if(istype(source, /obj)) //objs
- on_removed_obj(source, material_flags)
+ if(beauty_modifier) //component/beauty/InheritComponent() will handle the removal.
+ addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, -beauty_modifier * amount)), 0)
- else if(istype(source, /turf)) //turfs
- on_removed_turf(source, material_flags)
+ if(istype(source, /obj)) //objs
+ on_removed_obj(source, amount, material_flags)
+
+ if(istype(source, /turf)) //turfs
+ on_removed_turf(source, amount, material_flags)
///This proc is called when the material is removed from an object specifically.
-/datum/material/proc/on_removed_obj(obj/o, material_flags)
+/datum/material/proc/on_removed_obj(obj/o, amount, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/new_max_integrity = initial(o.max_integrity)
o.modify_max_integrity(new_max_integrity)
o.force = initial(o.force)
o.throwforce = initial(o.throwforce)
-/datum/material/proc/on_removed_turf(turf/T, material_flags)
- return
+/datum/material/proc/on_removed_turf(turf/T, amount, material_flags)
+ // if(alpha)
+ // RemoveElement(/datum/element/turf_z_transparency, FALSE)
+
+/**
+ * This proc is called when the mat is found in an item that's consumed by accident. see /obj/item/proc/on_accidental_consumption.
+ * Arguments
+ * * M - person consuming the mat
+ * * S - (optional) item the mat is contained in (NOT the item with the mat itself)
+ */
+/datum/material/proc/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ return FALSE
+
+/** Returns the composition of this material.
+ *
+ * Mostly used for alloys when breaking down materials.
+ *
+ * Arguments:
+ * - amount: The amount of the material to break down.
+ * - breakdown_flags: Some flags dictating how exactly this material is being broken down.
+ */
+/datum/material/proc/return_composition(amount=1, breakdown_flags=NONE)
+ return list((src) = amount) // Yes we need the parenthesis, without them BYOND stringifies src into "src" and things break.
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 0a866449cc..18674cdb17 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1214,6 +1214,10 @@
filter_data -= name
update_filters()
+/atom/proc/clear_filters()
+ filter_data = null
+ filters = null
+
/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)
@@ -1222,7 +1226,7 @@
if(custom_materials) //Only runs if custom materials existed at first. Should usually be the case but check anyways
for(var/i in custom_materials)
var/datum/material/custom_material = SSmaterials.GetMaterialRef(i)
- custom_material.on_removed(src, material_flags) //Remove the current materials
+ custom_material.on_removed(src, custom_materials[i], material_flags) //Remove the current materials
if(!length(materials))
custom_materials = null
diff --git a/code/game/objects/items/stacks/cash.dm b/code/game/objects/items/stacks/cash.dm
index e2036835ce..68762a63c7 100644
--- a/code/game/objects/items/stacks/cash.dm
+++ b/code/game/objects/items/stacks/cash.dm
@@ -14,7 +14,7 @@
grind_results = list(/datum/reagent/cellulose = 10)
var/value = 0
-/obj/item/stack/spacecash/Initialize()
+/obj/item/stack/spacecash/Initialize(mapload, new_amount, merge = TRUE)
. = ..()
update_desc()
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index de2e3b89fe..026b73ca15 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -41,6 +41,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
material_type = /datum/material/glass
point_value = 1
tableVariant = /obj/structure/table/glass
+ matter_amount = 4
+ cost = 500
shard_type = /obj/item/shard
/obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user)
@@ -69,12 +71,13 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
if (get_amount() < 1 || CC.get_amount() < 5)
to_chat(user, "You attach wire to the [name].")
var/obj/item/stack/light_w/new_tile = new(user.loc)
new_tile.add_fingerprint(user)
- else if(istype(W, /obj/item/stack/rods))
+ return
+ if(istype(W, /obj/item/stack/rods))
var/obj/item/stack/rods/V = W
if (V.get_amount() >= 1 && get_amount() >= 1)
var/obj/item/stack/sheet/rglass/RG = new (get_turf(user))
@@ -86,9 +89,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
user.put_in_hands(RG)
else
to_chat(user, "You need one rod and one sheet of glass to make reinforced glass!")
- return
- else
- return ..()
+ return
+ return ..()
@@ -164,6 +166,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
merge_type = /obj/item/stack/sheet/rglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10)
point_value = 4
+ matter_amount = 6
shard_type = /obj/item/shard
/obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params)
@@ -211,6 +214,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
merge_type = /obj/item/stack/sheet/plasmarglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10)
point_value = 23
+ matter_amount = 8
shard_type = /obj/item/shard/plasma
/obj/item/stack/sheet/plasmarglass/get_main_recipes()
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index 57c8ba75d8..57d0659ef6 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -19,7 +19,7 @@
///What type of wall does this sheet spawn
var/walltype
-/obj/item/stack/sheet/Initialize(mapload, new_amount, merge)
+/obj/item/stack/sheet/Initialize(mapload, new_amount, merge = TRUE)
. = ..()
pixel_x = rand(-4, 4)
pixel_y = rand(-4, 4)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 436c59ff7d..017c210070 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -42,6 +42,11 @@
var/matter_amount = 0
/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE)
+ //do this first, lazily inflate the value
+ if(LAZYLEN(custom_materials))
+ for(var/i in custom_materials)
+ custom_materials[i] *= amount
+
if(new_amount != null)
amount = new_amount
while(amount > max_amount)
@@ -88,7 +93,13 @@
/** Updates the custom materials list of this stack.
*/
/obj/item/stack/proc/update_custom_materials()
- set_custom_materials(mats_per_unit, amount)
+ set_custom_materials(mats_per_unit, amount, is_update=TRUE)
+
+/**
+ * Override to make things like metalgen accurately set custom materials
+ */
+/obj/item/stack/set_custom_materials(list/materials, multiplier=1, is_update=FALSE)
+ return is_update ? ..() : set_mats_per_unit(materials, multiplier / (amount || 1))
/obj/item/stack/on_grind()
. = ..()
@@ -297,50 +308,55 @@
return TRUE
return ..()
-/obj/item/stack/proc/building_checks(datum/stack_recipe/R, multiplier)
- if (get_amount() < R.req_amount*multiplier)
- if (R.req_amount*multiplier>1)
- to_chat(usr, "You haven't got enough [src] to build \the [R.req_amount*multiplier] [R.title]\s!")
+/obj/item/stack/proc/building_checks(datum/stack_recipe/recipe, multiplier)
+ if (get_amount() < recipe.req_amount*multiplier)
+ if (recipe.req_amount*multiplier>1)
+ to_chat(usr, "You haven't got enough [src] to build \the [recipe.req_amount*multiplier] [recipe.title]\s!")
else
- to_chat(usr, "You haven't got enough [src] to build \the [R.title]!")
+ to_chat(usr, "You haven't got enough [src] to build \the [recipe.title]!")
return FALSE
- var/turf/T = get_turf(usr)
+ var/turf/dest_turf = get_turf(usr)
- var/obj/D = R.result_type
- if(R.window_checks && !valid_window_location(T, initial(D.dir) == FULLTILE_WINDOW_DIR ? FULLTILE_WINDOW_DIR : usr.dir))
- to_chat(usr, "The [R.title] won't fit here!")
- return FALSE
- if(R.one_per_turf && (locate(R.result_type) in T))
- to_chat(usr, "There is another [R.title] here!")
- return FALSE
- if(R.on_floor)
- if(!isfloorturf(T))
- to_chat(usr, "\The [R.title] must be constructed on the floor!")
+ // If we're making a window, we have some special snowflake window checks to do.
+ if(ispath(recipe.result_type, /obj/structure/window))
+ var/obj/structure/window/result_path = recipe.result_type
+ if(!valid_window_location(dest_turf, usr.dir, is_fulltile = initial(result_path.fulltile)))
+ to_chat(usr, "The [recipe.title] won't fit here!")
return FALSE
- for(var/obj/AM in T)
- if(istype(AM,/obj/structure/grille))
+
+ if(recipe.one_per_turf && (locate(recipe.result_type) in dest_turf))
+ to_chat(usr, "There is another [recipe.title] here!")
+ return FALSE
+
+ if(recipe.on_floor)
+ if(!isfloorturf(dest_turf))
+ to_chat(usr, "\The [recipe.title] must be constructed on the floor!")
+ return FALSE
+
+ for(var/obj/object in dest_turf)
+ if(istype(object, /obj/structure/grille))
continue
- if(istype(AM,/obj/structure/table))
+ if(istype(object, /obj/structure/table))
continue
- if(istype(AM,/obj/structure/window))
- var/obj/structure/window/W = AM
- if(!W.fulltile)
+ if(istype(object, /obj/structure/window))
+ var/obj/structure/window/window_structure = object
+ if(!window_structure.fulltile)
continue
- if(AM.density)
- to_chat(usr, "Theres a [AM.name] here. You cant make a [R.title] here!")
+ if(object.density)
+ to_chat(usr, "There is \a [object.name] here. You cant make \a [recipe.title] here!")
return FALSE
- if(R.placement_checks)
- switch(R.placement_checks)
+ if(recipe.placement_checks)
+ switch(recipe.placement_checks)
if(STACK_CHECK_CARDINALS)
var/turf/step
for(var/direction in GLOB.cardinals)
- step = get_step(T, direction)
- if(locate(R.result_type) in step)
- to_chat(usr, "\The [R.title] must not be built directly adjacent to another!")
+ step = get_step(dest_turf, direction)
+ if(locate(recipe.result_type) in step)
+ to_chat(usr, "\The [recipe.title] must not be built directly adjacent to another!")
return FALSE
if(STACK_CHECK_ADJACENT)
- if(locate(R.result_type) in range(1, T))
- to_chat(usr, "\The [R.title] must be constructed at least one tile away from others of its type!")
+ if(locate(recipe.result_type) in range(1, dest_turf))
+ to_chat(usr, "\The [recipe.title] must be constructed at least one tile away from others of its type!")
return FALSE
return TRUE
@@ -513,15 +529,12 @@
var/time = 0
var/one_per_turf = FALSE
var/on_floor = FALSE
- var/window_checks = FALSE
var/placement_checks = FALSE
var/applies_mats = FALSE
var/trait_booster = null
var/trait_modifier = 1
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, window_checks = FALSE, placement_checks = FALSE, applies_mats = FALSE, trait_booster = null, trait_modifier = 1)
-
-
src.title = title
src.result_type = result_type
src.req_amount = req_amount
@@ -530,7 +543,6 @@
src.time = time
src.one_per_turf = one_per_turf
src.on_floor = on_floor
- src.window_checks = window_checks
src.placement_checks = placement_checks
src.applies_mats = applies_mats
src.trait_booster = trait_booster
diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm
index c13353b7cd..21bf732493 100644
--- a/code/modules/admin/callproc/callproc.dm
+++ b/code/modules/admin/callproc/callproc.dm
@@ -1,4 +1,3 @@
-
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
@@ -21,7 +20,7 @@
return
target = value["value"]
if(!istype(target))
- to_chat(usr, "Invalid target.")
+ to_chat(usr, "Invalid target.", confidential = TRUE)
return
if("No")
target = null
@@ -41,12 +40,12 @@
if(targetselected)
if(!hascall(target, procname))
- to_chat(usr, "Error: callproc(): type [target.type] has no [proctype] named [procpath].")
+ to_chat(usr, "Error: callproc(): type [target.type] has no [proctype] named [procpath].", confidential = TRUE)
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
- to_chat(usr, "Error: callproc(): [procpath] does not exist.")
+ to_chat(usr, "Error: callproc(): [procpath] does not exist.", confidential = TRUE)
return
var/list/lst = get_callproc_args()
@@ -55,24 +54,24 @@
if(targetselected)
if(!target)
- to_chat(usr, "Error: callproc(): owner of proc no longer exists.")
+ to_chat(usr, "Error: callproc(): owner of proc no longer exists.", confidential = TRUE)
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
- message_admins(msg) //Proccall announce removed.
+ message_admins(msg) //Proccall announce removed.
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
- message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
+ message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(get_retval)
get_retval += returnval
. = get_callproc_returnval(returnval, procname)
if(.)
- to_chat(usr, .)
+ to_chat(usr, ., confidential = TRUE)
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
@@ -84,34 +83,30 @@ GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
-GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
-GLOBAL_PROTECT(AdminProcCallSpamPrevention)
+/// Wrapper for proccalls where the datum is flagged as vareditted
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
- if(target != GLOBAL_PROC && procname == "Del")
- to_chat(usr, "Calling Del() is not allowed")
+ if(target && procname == "Del")
+ to_chat(usr, "Calling Del() is not allowed", confidential = TRUE)
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
- to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
+ to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!", confidential = TRUE)
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
+
if(current_caller && current_caller != ckey)
- if(!GLOB.AdminProcCallSpamPrevention[ckey])
- to_chat(usr, "Another set of admin called procs are still running, your proc will be run after theirs finish.")
- GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
- UNTIL(!GLOB.AdminProcCaller)
- to_chat(usr, "Running your proc")
- GLOB.AdminProcCallSpamPrevention -= ckey
- else
- UNTIL(!GLOB.AdminProcCaller)
+ // hey kev i removed the sleep here because it blocks this proc
+ to_chat(usr, "Another set of admin called procs are still running. Try again later.", confidential = TRUE)
+ return
+
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
- GLOB.LastAdminCalledTargetRef = "[REF(target)]"
- GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
+ GLOB.LastAdminCalledTargetRef = REF(target)
+ GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
@@ -120,11 +115,11 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
- return call(text2path("/proc/[procname]"))(arglist(arguments))
+ return call("/proc/[procname]")(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
- log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
+ log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
@@ -145,17 +140,17 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
if(!procname)
return
if(!hascall(A,procname))
- to_chat(usr, "Error: callproc_datum(): type [A.type] has no proc named [procname].")
+ to_chat(usr, "Error: callproc_datum(): type [A.type] has no proc named [procname].", confidential = TRUE)
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
- to_chat(usr, "Error: callproc_datum(): owner of proc no longer exists.")
+ to_chat(usr, "Error: callproc_datum(): owner of proc no longer exists.", confidential = TRUE)
return
+ log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
- log_admin(msg)
message_admins(msg)
admin_ticket_log(A, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -163,7 +158,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
if(.)
- to_chat(usr, .)
+ to_chat(usr, ., confidential = TRUE)
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
@@ -188,7 +183,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
. = ""
if(islist(returnval))
var/list/returnedlist = returnval
- . = ""
+ . = ""
if(returnedlist.len)
var/assoc_check = returnedlist[1]
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
@@ -202,7 +197,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
. += "\n[elem]"
else
. = "[procname] returned an empty list"
- . += ""
+ . += ""
else
- . = "[procname] returned: [!isnull(returnval) ? returnval : "null"]"
+ . = "[procname] returned: [!isnull(returnval) ? html_encode(returnval) : "null"]"
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 494942691a..ad0f7927a4 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -194,7 +194,6 @@
can_min_release_pressure = (ONE_ATMOSPHERE / 30)
prototype = TRUE
-
/obj/machinery/portable_atmospherics/canister/proto/default/oxygen
name = "prototype canister"
desc = "A prototype canister for a prototype bike, what could go wrong?"
@@ -209,7 +208,6 @@
air_contents.copy_from(existing_mixture)
else
create_gas()
-
update_icon()
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 1058277cdf..9e779b9c1b 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -531,7 +531,7 @@ By design, d1 is the smallest direction and d2 is the highest
user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
return(OXYLOSS)
-/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null)
+/obj/item/stack/cable_coil/Initialize(mapload, new_amount, merge = TRUE)
. = ..()
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
@@ -823,7 +823,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/item/stack/cable_coil/random
color = "#ffffff"
-/obj/item/stack/cable_coil/random/Initialize(mapload, new_amount = null, param_color = null)
+/obj/item/stack/cable_coil/random/Initialize(mapload, new_amount, merge = TRUE, param_color = null)
. = ..()
var/list/cable_colors = GLOB.cable_colors
color = pick(cable_colors)
@@ -835,12 +835,13 @@ By design, d1 is the smallest direction and d2 is the highest
amount = null
icon_state = "coil2"
-/obj/item/stack/cable_coil/cut/Initialize(mapload)
- . = ..()
+/obj/item/stack/cable_coil/cut/Initialize(mapload, new_amount, merge = TRUE)
+ // do random amount calls BEFORE we add the mats or else the code eats shit and dies
if(!amount)
amount = rand(1,2)
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
+ . = ..()
update_icon()
/obj/item/stack/cable_coil/cut/red
@@ -869,7 +870,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/item/stack/cable_coil/cut/random
color = "#ffffff"
-/obj/item/stack/cable_coil/cut/random/Initialize(mapload, new_amount = null, param_color = null)
+/obj/item/stack/cable_coil/cut/random/Initialize(mapload, new_amount, merge = TRUE, param_color = null)
. = ..()
var/list/cable_colors = GLOB.cable_colors
color = pick(cable_colors)
diff --git a/tools/build/build.js b/tools/build/build.js
index 6236ec6b53..089a78f1bc 100755
--- a/tools/build/build.js
+++ b/tools/build/build.js
@@ -48,6 +48,7 @@ const taskDm = new Task('dm')
.depends('tgui/public/tgui.html')
.depends('tgui/public/*.bundle.*')
.depends('tgui/public/*.chunk.*')
+ .depends(process.platform === 'win32' ? 'byond-extools.*' : 'libbyond-extools.*')
.depends('tgstation.dme')
.provides('tgstation.dmb')
.provides('tgstation.rsc')
diff --git a/tools/ci/check_grep.sh b/tools/ci/check_grep.sh
index 51a53ac4be..fe92630aad 100755
--- a/tools/ci/check_grep.sh
+++ b/tools/ci/check_grep.sh
@@ -70,7 +70,7 @@ while read f; do
done < <(find . -type f -name '*.dm')
if grep -P '^/[\w/]\S+\(.*(var/|, ?var/.*).*\)' code/**/*.dm; then
echo "changed files contains proc argument starting with 'var'"
- st=1
+ # st=1
fi;
if grep -i 'centcomm' code/**/*.dm; then
echo "ERROR: Misspelling(s) of CENTCOM detected in code, please remove the extra M(s)."
diff --git a/tools/ci/run_server.sh b/tools/ci/run_server.sh
index 4d943846f0..ef548370f1 100755
--- a/tools/ci/run_server.sh
+++ b/tools/ci/run_server.sh
@@ -7,6 +7,11 @@ mkdir ci_test/config
#test config
cp tools/ci/ci_config.txt ci_test/config/config.txt
+#throw extools into ldd
+cp libbyond-extools.so ~/.byond/bin/libbyond-extools.so
+chmod +x ~/.byond/bin/libbyond-extools.so
+ldd ~/.byond/bin/libbyond-extools.so
+
cd ci_test
DreamDaemon tgstation.dmb -close -trusted -verbose -params "log-directory=ci"
cd ..