mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-28 12:17:04 +01:00
232 lines
8.7 KiB
Plaintext
232 lines
8.7 KiB
Plaintext
//* This file is explicitly licensed under the MIT license. *//
|
|
//* Copyright (c) 2024 Citadel Station Developers *//
|
|
|
|
/**
|
|
* design datums for holding what lathes can print.
|
|
*
|
|
* relevant bitfields are in [code/__DEFINES/machines/lathe.dm]
|
|
*/
|
|
/datum/prototype/design
|
|
/// Abstract type.
|
|
abstract_type = /datum/prototype/design
|
|
|
|
//? Design Data - Core
|
|
/// design flags - see [code/__DEFINES/datums/design.dm]
|
|
var/design_flags = NONE
|
|
/// how are we unlocked - see [code/__DEFINES/datums/design.dm]
|
|
var/design_unlock = NONE
|
|
/// is stack? autodetected.
|
|
var/is_stack = FALSE
|
|
/// max stack amount? autodetected.
|
|
var/max_stack
|
|
|
|
//? Design Data - UI
|
|
/// name of design, shows in UIs. this is usually built from build_name. do *not* manually set this most of the time.
|
|
var/name
|
|
/// desc of design, shows in UIs. if null, it'll be auto-detected from the build_path if possible.
|
|
var/desc
|
|
/// overrides build_name for purposes of name generation.
|
|
var/design_name
|
|
/// category - string or list, or null; null results in undefined behavior depending on UI.
|
|
var/category = DESIGN_CATEGORY_MISC
|
|
|
|
/// subcategory - string or list, or null. null generally results in no seperate subcategory header
|
|
var/subcategory = null
|
|
|
|
//? Build Data
|
|
/// name of item before any name-generation is done. also shown in ui. if null, it'll be auto-detected from the build_path if possible.
|
|
var/build_name
|
|
/// desc of item before any desc-generation is done. also shown in ui. if null, it'll be auto-detected from the build_path if possible.
|
|
var/build_desc
|
|
/// type of what we build
|
|
///
|
|
/// * Autodetection only works on /obj's.
|
|
var/build_path
|
|
/// Types of lathes that can print us.
|
|
/// * Type: /bitfield/lathe_type
|
|
var/lathe_type = NONE
|
|
/// time needed in deciseconds - for stacks, this is time *PER SHEET*.
|
|
var/work = 5 SECONDS
|
|
|
|
//? Build Costs
|
|
/// list of specific materials needed - typepath or id to amount. null to auto-detect from the object in question. list() for no cost (DANGEROUS).
|
|
///
|
|
/// * This should always be using typepath instead of ID for hardcoded designs, as typepaths can be eagerly loaded before
|
|
/// the materials repository can initialize normally.
|
|
/// * This will always be transformed into IDs at runtime.
|
|
/// * If you're making one at runtime, always put in IDs, as automatic detection/generation may not run.
|
|
var/list/materials_base
|
|
/// for variable-material designs: assoc list of key to amounts
|
|
/// the key will be fed into print() during creation with the material id the user picked
|
|
/// autodetected if null.
|
|
/// this should obviously match material_parts on the /obj in question.
|
|
/// todo: add optional parts and constraints
|
|
var/list/material_costs
|
|
/// for variable-material designs: assoc list of keys to constraints
|
|
/// this should obviously match material_parts on the /obj in question.
|
|
var/list/material_constraints
|
|
/// for variable-material designs: assoc list of keys to tags, for autodetect
|
|
/// this should obviously match material_parts on the /obj in question.
|
|
var/list/material_autodetect_tags
|
|
/// Items needed, as ingredients list - see [code/__HELPERS/datastructs/ingredients.dm]
|
|
///
|
|
/// * This should always be using typepath instead of ID where possible for hardcoded designs, as typepaths can be eagerly
|
|
/// loaded before the materials repository can initialize normally.
|
|
var/list/ingredients
|
|
/// list of reagents needed - typepath or id to amount. null to auto-detect from the object in question. list() for no cost (DANGEROUS).
|
|
///
|
|
/// * This should always be using typepath instead of ID for hardcoded designs, as typepaths can be eagerly loaded before
|
|
/// the materials repository can initialize normally.
|
|
var/list/reagents
|
|
// todo: reagent_parts?
|
|
|
|
//? legacy
|
|
///IDs of that techs the object originated from and the minimum level requirements.
|
|
var/list/req_tech = list()
|
|
|
|
var/complexity = 1 //'complexity' or storage space required on design disks. almost always 1.
|
|
|
|
/datum/prototype/design/New()
|
|
autodetect()
|
|
generate()
|
|
|
|
/datum/prototype/design/proc/autodetect()
|
|
if(isnull(build_path))
|
|
return
|
|
if(ispath(build_path, /obj/item/stack))
|
|
is_stack = TRUE
|
|
var/obj/item/stack/stack_path = build_path
|
|
max_stack = initial(stack_path.max_amount)
|
|
var/obj/instance = SSatoms.instance_atom_immediate(build_path)
|
|
// lathe designs shouldn't be qdeleting, but incase someone puts in a random..
|
|
if(QDELETED(instance))
|
|
return
|
|
if(!isobj(instance))
|
|
qdel(instance)
|
|
return
|
|
if(isnull(materials_base))
|
|
var/list/fetched = instance.detect_material_base_costs()
|
|
if(length(fetched))
|
|
materials_base = fetched
|
|
if(isnull(material_costs))
|
|
var/list/fetched = instance.detect_material_part_costs()
|
|
if(length(fetched))
|
|
material_costs = fetched
|
|
if(isnull(reagents))
|
|
// if(!isnull(instance.reagents))
|
|
// reagents = instance.reagents.Copy()
|
|
// detected_materials = TRUE
|
|
reagents = list() // nah no autodetect for now, reagents are way to ocomplicated
|
|
if(!build_name)
|
|
build_name = instance.name
|
|
if(!build_desc)
|
|
build_desc = instance.desc
|
|
qdel(instance)
|
|
|
|
/datum/prototype/design/proc/generate()
|
|
if(!name)
|
|
name = generate_name(design_name || build_name)
|
|
if(!desc)
|
|
desc = generate_desc(design_name || build_name, build_desc)
|
|
// materials base must be IDs at runtime.
|
|
materials_base = SSmaterials.preprocess_kv_keys_to_ids(materials_base)
|
|
|
|
/datum/prototype/design/proc/generate_name(template)
|
|
return template
|
|
|
|
/datum/prototype/design/proc/generate_desc(template_name, template_desc)
|
|
return template_desc
|
|
|
|
/**
|
|
* Encodes data for [tgui/packages/tgui/interfaces/common/Design.tsx]
|
|
*/
|
|
/datum/prototype/design/proc/ui_data_list()
|
|
return list(
|
|
"name" = name,
|
|
"truncated_name" = length(name) <= 18 ? name : copytext(name, 1, 19) + "..",
|
|
"desc" = desc,
|
|
"id" = id,
|
|
"work" = work,
|
|
"categories" = COERCE_OPTIONS_LIST(category),
|
|
"subcategories" = COERCE_OPTIONS_LIST(subcategory),
|
|
"materials" = length(materials_base)? materials_base : null,
|
|
"material_parts" = length(material_costs)? material_costs : null,
|
|
"material_constraints" = length(material_constraints)? material_constraints : null,
|
|
"autodetect_tags" = length(material_autodetect_tags)? material_autodetect_tags : null,
|
|
"reagents" = length(reagents)? reagents : null,
|
|
"ingredients" = length(ingredients)? ingredients : null,
|
|
"resultItem" = list(
|
|
"name" = build_name,
|
|
"desc" = build_desc,
|
|
),
|
|
)
|
|
|
|
/**
|
|
* Return a new instance of the item for the design
|
|
* This is called even before the fabricator can touch the item.
|
|
*
|
|
* @params
|
|
* * where - where to print
|
|
* * amount - how many to print
|
|
* * material_parts - keys to ids
|
|
* * ingredient_parts - ingredients
|
|
* * reagent_parts - keys to ids
|
|
* * cost_multiplier - the cost multiplier used to print it
|
|
*
|
|
* @return created atom, or list of created atoms.
|
|
*/
|
|
/datum/prototype/design/proc/print(atom/where, amount, list/material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
|
|
var/list/resolved_material_parts = SSmaterials.preprocess_kv_values_to_instances(material_parts)
|
|
if(is_stack)
|
|
var/stack_size = max_stack
|
|
if(stack_size >= amount)
|
|
. = new build_path(where, amount)
|
|
on_print(., resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
|
|
else
|
|
. = list()
|
|
var/safety = 0
|
|
var/left = amount
|
|
var/atom/made
|
|
while(left)
|
|
if(++safety > 50)
|
|
CRASH("way too high")
|
|
var/making = min(left, stack_size)
|
|
made = new build_path(where, making)
|
|
left -= making
|
|
. += made
|
|
on_print(made, resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
|
|
else
|
|
if(amount > 50)
|
|
STACK_TRACE("way too high")
|
|
if(amount == 1)
|
|
. = new build_path(where)
|
|
on_print(., resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
|
|
else
|
|
. = list()
|
|
var/atom/made
|
|
for(var/i in 1 to min(amount, 50))
|
|
made = new build_path(where)
|
|
on_print(made, resolved_material_parts, ingredient_parts, reagent_parts, cost_multiplier)
|
|
. += made
|
|
|
|
/**
|
|
* material parts gets resolved to instances
|
|
*/
|
|
/datum/prototype/design/proc/on_print(atom/created, list/resolved_material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
|
|
if(isobj(created))
|
|
var/obj/O = created
|
|
O.set_materials_base(materials_base)
|
|
O.set_material_parts(resolved_material_parts)
|
|
O.material_multiplier = cost_multiplier
|
|
|
|
/**
|
|
* called when a lathe prints a design, instead of print()
|
|
*
|
|
* @params
|
|
* * where - where to put the finished product
|
|
* * fabricator - the lathe printing the product
|
|
* * material_parts - assoc list of materials to use, based on the variable of the same name
|
|
*/
|
|
/datum/prototype/design/proc/lathe_print(atom/where, amount, list/material_parts, list/ingredient_parts, list/reagent_parts, obj/machinery/lathe/fabricator, cost_multiplier = 1)
|
|
return print(where, amount, material_parts, ingredient_parts, reagent_parts, cost_multiplier)
|