Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

running bugfix PR #6914

Merged
merged 28 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions citadel.dme
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,7 @@
#include "code\game\objects\items\storage\wallets.dm"
#include "code\game\objects\items\storage\medical\firstaid.dm"
#include "code\game\objects\items\storage\medical\hypokit.dm"
#include "code\game\objects\items\storage\misc\survival.dm"
#include "code\game\objects\items\storage\misc_legacy\bible.dm"
#include "code\game\objects\items\storage\misc_legacy\fancy.dm"
#include "code\game\objects\items\storage\misc_legacy\laundry_basket.dm"
Expand Down Expand Up @@ -2026,6 +2027,10 @@
#include "code\game\objects\structures\tables\update_triggers.dm"
#include "code\game\objects\systems\_system.dm"
#include "code\game\objects\systems\cell_slot.dm"
#include "code\game\objects\systems\storage\storage-filters.dm"
#include "code\game\objects\systems\storage\storage-indirection.dm"
#include "code\game\objects\systems\storage\storage-indirection_holder.dm"
#include "code\game\objects\systems\storage\storage-limits.dm"
#include "code\game\objects\systems\storage\storage-screen_object.dm"
#include "code\game\objects\systems\storage\storage-ui.dm"
#include "code\game\objects\systems\storage\storage.dm"
Expand Down Expand Up @@ -2259,6 +2264,7 @@
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.dm"
#include "code\modules\admin\verbs\SDQL2\wrappers\map.dm"
#include "code\modules\admin\verbs\SDQL2\wrappers\math.dm"
#include "code\modules\admin\verbs\server\admin_reboot.dm"
#include "code\modules\admin\view_variables\admin_delete.dm"
#include "code\modules\admin\view_variables\color_matrix_editor.dm"
Expand Down
35 changes: 33 additions & 2 deletions code/__DEFINES/materials/helpers.dm
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//

//* object checks
//* /datum/prototype/material declaration helpers *//

#define DECLARE_MATERIAL(PATH_FRAGMENT) \
/datum/prototype/material##PATH_FRAGMENT

/**
* Generates material stacks for a material.
*
* The material must have:
*
* * a defined `display_name`
* * a defined `sheet_singular_name`
* * a defined `sheet_plural_name`
* * a defined `icon`
* * a defined `icon_stack_count`
*/
#define GENERATE_MATERIAL_STACKS(PATH_FRAGMENT) \
/obj/item/stack/material##PATH_FRAGMENT { \
name = /datum/prototype/material##PATH_FRAGMENT::name + " " + /datum/prototype/material##PATH_FRAGMENT::sheet_singular_name; \
icon = /datum/prototype/material##PATH_FRAGMENT::icon; \
icon_state = "stack-1"; \
material = /datum/prototype/material##PATH_FRAGMENT; \
no_variants = TRUE; \
amount = 1; \
} \
/obj/item/stack/material##PATH_FRAGMENT/full_stack { \
name = /datum/prototype/material##PATH_FRAGMENT::name + " " + /datum/prototype/material##PATH_FRAGMENT::sheet_plural_name; \
icon_state = "stack"; \
amount = 50; \
}

//* Material Traits - Checks *//

/// We are ticking materials.
#define IS_TICKING_MATERIALS(A) (A.atom_flags & ATOM_MATERIALS_TICKING)
#define START_TICKING_MATERIALS(A) SSmaterials.add_ticked_object(src)
#define STOP_TICKING_MATERIALS(A) SSmaterials.remove_ticked_object(src)

//* /atom level invocation of traits
//* Material Traits - /atom invocation *//

/// Invocation of material traits
/// A - the atom
Expand Down
23 changes: 16 additions & 7 deletions code/__DEFINES/objects/objects.dm
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 silicons *//
//* Copyright (c) 2024 Citadel Station Developers *//

//* /obj/var/hides_underfloor

/// do not change these willy-nilly, these are strings for the map editor.

/// just Don't
#define OBJ_UNDERFLOOR_DISABLED "disabled"
/// * this is different from 'NEVER'
#define OBJ_UNDERFLOOR_UNSUPPORTED "unsupported"
/// never underfloor, even if floor isn't plating
#define OBJ_UNDERFLOOR_NEVER "never"
/// always underfloor, as long as floor isn't plating
#define OBJ_UNDERFLOOR_ALWAYS "always"
/// Should be underfloor, and is not currently underfloor.
/// * Setting to this at runtime is equal to setting to [OBJ_UNDERFLOOR_ACTIVE].
/// The atom will automatically hide under the floor if the floor is covered.
#define OBJ_UNDERFLOOR_INACTIVE "inactive"
/// Should be underfloor, and is currently underfloor.
/// * Setting to this at runtime is equal to setting to [OBJ_UNDERFLOOR_INACTIVE].
/// The atom will automatically hide under the floor if the floor is covered.
#define OBJ_UNDERFLOOR_ACTIVE "active"
/// automatic
///
/// * gets set to UNDERFLOOR_NEVER if we were made while the floor is intact
/// * gets set to UNDERFLOOR_ALWAYS if we were made while the floor isn't intact
#define OBJ_UNDERFLOOR_IF_CREATED_UNCOVERED "initially-covered"
/// automatic
///
/// * This is what you usually want.
/// * IF_CREATED_UNCOVERED, but always underfloor if made in mapload
#define OBJ_UNDERFLOOR_UNLESS_PLACED_ONTOP "initially-underfloor"

Expand All @@ -26,9 +34,10 @@ DEFINE_ENUM("obj_hides_underfloor", list(
"hides_underfloor",
),
), list(
"Disabled" = OBJ_UNDERFLOOR_DISABLED,
"Never" = OBJ_UNDERFLOOR_NEVER,
"Always" = OBJ_UNDERFLOOR_ALWAYS,
"Unsupported" = OBJ_UNDERFLOOR_UNSUPPORTED,
"No" = OBJ_UNDERFLOOR_NEVER,
"Yes (Currently Uncovered)" = OBJ_UNDERFLOOR_INACTIVE,
"Yes (Currently Covered)" = OBJ_UNDERFLOOR_ACTIVE,
"If Created Uncovered (Init Only)" = OBJ_UNDERFLOOR_IF_CREATED_UNCOVERED,
"If Created Uncovered Or In Mapload (Init Only)" = OBJ_UNDERFLOOR_UNLESS_PLACED_ONTOP,
))
27 changes: 26 additions & 1 deletion code/controllers/subsystem/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,34 @@ SUBSYSTEM_DEF(atoms)
* * ... - rest of args are passed to new() / Initialize().
*/
/datum/controller/subsystem/atoms/proc/instance_atom_immediate(path, mapload, atom/where, ...)
SHOULD_NOT_SLEEP(TRUE)
var/old_init_status = atom_init_status
atom_init_status = mapload? ATOM_INIT_IN_NEW_MAPLOAD : ATOM_INIT_IN_NEW_REGULAR
var/atom/created = new path(arglist(args.Copy()))
var/atom/created = new path(arglist(args.Copy(3)))
atom_init_status = old_init_status
return created

/**
* immediately creates and inits an atom with a preloader callback.
*
* @params
* * path - typepath
* * mapload - treat as mapload?
* * preload_call - callback to invoke with (created) for the created atom. This is not allowed to sleep.
* * where - location to init at
* * ... - rest of args are passed to new() / Initialize().
*/
/datum/controller/subsystem/atoms/proc/instance_atom_immediate_with_preloader(path, mapload, datum/callback/preload_call, atom/where, ...)
SHOULD_NOT_SLEEP(TRUE)
var/old_init_status = atom_init_status
atom_init_status = ATOM_INIT_IN_SUBSYSTEM
var/atom/created = new path(arglist(args.Copy(4)))
preload_call.invoke_no_sleep(created)
atom_init_status = mapload? ATOM_INIT_IN_NEW_MAPLOAD : ATOM_INIT_IN_NEW_REGULAR
// this sets 'where' to if we should be mapload.
// this is acceptable because args[4] ('where') is not used again.
args[4] = mapload
InitAtom(created, FALSE, args.Copy(4))
atom_init_status = old_init_status
return created

Expand Down
27 changes: 21 additions & 6 deletions code/datums/callback.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,24 +101,39 @@
else
calling_arguments = args
if(datum_flags & DF_VAR_EDITED)
return WrapAdminProcCall(object, delegate, calling_arguments)
if(object == GLOBAL_PROC)
return call(delegate)(arglist(calling_arguments))
return call(object, delegate)(arglist(calling_arguments))
. = WrapAdminProcCall(object, delegate, calling_arguments)
else if(object == GLOBAL_PROC)
. = call(delegate)(arglist(calling_arguments))
else
. = call(object, delegate)(arglist(calling_arguments))
pass()

/**
* Invoke this callback and crash if it sleeps.
*
* * Use when a callback should never sleep, as call() cannot be verified by static analysis.
* * Do not use in performance critical code. This wraps calls more aggressively than InvokeAsync().
* * `null` is returned if the call sleeps.
*
* The specific use case here is an async call where:
*
* * It's always invalid behavior for a callback to sleep.
* * The caller should be protected (caller shouldn't be interrupted by the sleep).
*
* This allows enforcement of the above invariants by loudly runtiming and bringing attention to the issue,
* as opposed to the usual way of compile checking it (which we can't because this is a reflection-based call to an arbitrary proc).
*/
/datum/callback/proc/invoke_no_sleep(...)
. = CALLBACK_SLEEP_SENTINEL
ASYNC
. = Invoke(arglist(args))
. = invoke_no_sleep_call(arglist(args))
if(. == CALLBACK_SLEEP_SENTINEL)
. = null
CRASH("Callback [src] slept on a no-sleeping invoke.")

/datum/callback/proc/invoke_no_sleep_call(...)
set waitfor = FALSE
. = Invoke(arglist(args))

/**
* Invoke this callback async (waitfor=false)
*
Expand Down
55 changes: 53 additions & 2 deletions code/datums/outfits/outfit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,59 @@
for(var/i=0,i<number,i++)
H.equip_to_slot_or_del(new path(H), /datum/inventory_slot/abstract/attach_as_accessory, INV_OP_FLUFFLESS | INV_OP_SILENT)

if(H.species)
H.species.equip_survival_gear(H, flags&OUTFIT_EXTENDED_SURVIVAL, flags&OUTFIT_COMPREHENSIVE_SURVIVAL)
// deal with racial & survival gear
var/list/to_inject_box = list()
var/list/to_inject_inv = list()
H.species.apply_survival_gear(H, to_inject_box, to_inject_inv)
H.species.apply_racial_gear(H, to_inject_box, to_inject_inv)

if(length(to_inject_box))
var/obj/item/survival_box = new /obj/item/storage/box/survival
for(var/descriptor in to_inject_box)
if(ispath(descriptor))
new descriptor(survival_box)
else if(IS_ANONYMOUS_TYPEPATH(descriptor))
new descriptor(survival_box)
else if(isitem(descriptor))
var/obj/item/moving = descriptor
moving.forceMove(survival_box)
else
stack_trace("invalid descriptor '[descriptor]' encountered")
survival_box.obj_storage.fit_to_contents(no_shrink = TRUE)

if(!H.inventory.equip_to_slot_if_possible(survival_box, /datum/inventory_slot/abstract/put_in_backpack))
if(!H.inventory.put_in_hands(survival_box))
survival_box.forceMove(H.drop_location())

if(length(to_inject_inv))
var/list/atom/movable/arbitrary_instantiated_gear = list()
for(var/descriptor in to_inject_inv)
if(ispath(descriptor))
arbitrary_instantiated_gear += new descriptor
else if(IS_ANONYMOUS_TYPEPATH(descriptor))
arbitrary_instantiated_gear += new descriptor
else if(ismovable(descriptor))
arbitrary_instantiated_gear += descriptor
else
stack_trace("invalid descriptor '[descriptor]' encountered")
for(var/atom/movable/gear as anything in arbitrary_instantiated_gear)
if(isitem(gear))
// try to put into inv, then hands, then nearby
var/obj/item/gear_item = gear
if(!H.equip_to_slots_if_possible(
gear_item,
list(
/datum/inventory_slot/abstract/put_in_backpack,
/datum/inventory_slot/abstract/put_in_belt,
/datum/inventory_slot/abstract/put_in_hands,
/datum/inventory_slot/inventory/pocket/left,
/datum/inventory_slot/inventory/pocket/right,
),
))
gear_item.forceMove(H.drop_location())
else
// put nearby
gear.forceMove(H.drop_location())

/datum/outfit/proc/equip_id(mob/living/carbon/human/H, rank, assignment)
if(!id_slot || !id_type)
Expand Down
28 changes: 26 additions & 2 deletions code/datums/recipe/stack_recipe.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,30 @@
var/on_border = FALSE
// todo: material constraints

//* Product Descriptors *//

/// Automatically create empty storage / cells / containers / whatever
/// * Usually this is on, because usually stacks are not meant to create the insides of a container.
var/product_auto_create_empty = TRUE

//* Internal *//

/// preloader callback, do not touch
var/datum/callback/preloader_callback

/datum/stack_recipe/New()
if(ispath(result_type, /obj/item/stack))
result_is_stack = TRUE

var/atom/casted = result_type
on_border = !!(initial(casted.atom_flags) & ATOM_BORDER)

preloader_callback = CALLBACK(src, PROC_REF(make_preload_hook))

/datum/stack_recipe/Destroy()
QDEL_NULL(preloader_callback)
return ..()

/**
* attepmt to craft
*
Expand Down Expand Up @@ -139,16 +156,23 @@
if(!--safety)
CRASH("safety hit")
var/making_amount = min(amount, max_amount)
var/obj/item/stack/creating = new result_type(where, making_amount)
var/obj/item/stack/creating = SSatoms.instance_atom_immediate_with_preloader(result_type, FALSE, preloader_callback, where, making_amount)
amount -= making_amount
created += creating
else
for(var/i in 1 to min(amount, 50))
var/atom/movable/creating = new result_type(where)
var/atom/movable/creating = SSatoms.instance_atom_immediate_with_preloader(result_type, FALSE, preloader_callback, where)
creating.setDir(use_dir)
created += creating
return TRUE

/**
* preloads an atom we make
*/
/datum/stack_recipe/proc/make_preload_hook(atom/product)
SHOULD_NOT_SLEEP(TRUE)
product.preload_from_stack_recipe(src)

/**
* tgui stack recipe data
*/
Expand Down
12 changes: 12 additions & 0 deletions code/game/atoms/_atom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,32 @@

return ..()

//* Preload Hooks *//

/**
* Called by the maploader if a dmm_context is set
*
* todo: rename to preload_from_mapload()
*/
/atom/proc/preloading_instance(datum/dmm_context/context)
return

/**
* hook for abstract direction sets from the maploader
*
* todo: this might need to be part of preloading_instance; investigate
*
* return FALSE to override maploader automatic rotation
*/
/atom/proc/preloading_dir(datum/dmm_context/context)
return TRUE

/**
* Preloads before Initialize(), invoked by init from a stack recipe.
*/
/atom/proc/preload_from_stack_recipe(datum/stack_recipe/recipe)
return

/atom/proc/reveal_blood()
return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
/obj/item/storage/belt/medical,
/obj/item/radio/headset/heads/cmo,
/obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/storage/hypokit/advanced/cmo,
/obj/item/storage/hypokit/advanced/cmo/full/loaded,
/obj/item/clothing/accessory/stethoscope,
/obj/item/clothing/glasses/hud/health,
/obj/item/clothing/suit/storage/toggle/labcoat/cmo,
Expand Down Expand Up @@ -175,7 +175,7 @@
/obj/item/healthanalyzer,
/obj/item/storage/box/pillbottles,
/obj/item/storage/box/syringes,
/obj/item/storage/hypokit,
/obj/item/storage/hypokit/full/loaded,
)
worth = 450
container_type = /obj/structure/closet/crate/corporate/nanomed
Expand All @@ -201,7 +201,7 @@
/obj/item/cartridge/medical,
/obj/item/flashlight/pen,
/obj/item/clothing/accessory/storage/white_vest,
/obj/item/storage/hypokit,
/obj/item/storage/hypokit/full/loaded,
)
worth = 450
container_type = /obj/structure/closet/crate/secure/corporate/nanomed
Expand Down
1 change: 1 addition & 0 deletions code/game/machinery/vending/medical.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
/obj/item/storage/single_use/med_pouch/oxyloss = 3,
/obj/item/storage/single_use/med_pouch/burn = 3,
/obj/item/storage/single_use/med_pouch/trauma = 3,
/obj/item/hypospray = 6,
/obj/item/storage/hypokit = 6,
)
contraband = list(
Expand Down
Loading
Loading