Files
b1029a24f8 Power Cell Rework + Energy Weapon Rebalance (& misc changes) (#7438)
- all cells in the game are now small, medium, large
- super, hyper capacity cells, device, and weapon cells are all removed
- cells now have standardized variants, some of which are printable by
R&D
- energy weapons rebalanced
- **advanced energy guns and stun revolvers removed** - use the new
modular weapon system and microfission cells.

---------

Co-authored-by: silicons <silicons@silicons.dev>
2025-12-24 12:15:01 +01:00

273 lines
8.0 KiB
Plaintext

//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//
/**
* a holder for a pack of objects that can be ordered
*
* todo: rename to supply_pack
*/
/datum/supply_pack
/// name of pack
var/name = "Supply Pack"
/// arbitrary category to group under
var/category = "Miscellaneous"
/// flags
var/supply_pack_flags = NONE
/// raw worth of everything in pack
///
/// * if null, it will be autodetected.
var/worth
/// raw worth of non-deterministic parts of pack
///
/// * required for non-deterministic packs if you don't want to hard-set worth
var/worth_additional
//* Container *//
/// type of the container
var/container_type = /obj/structure/closet/crate/plastic
/// override name of container
var/container_name
/// override desc of container
var/container_desc
/// set access of container
var/list/container_access
/// set req one access of container
var/list/container_one_access
//* Contents *//
/// contains these entity descriptors
///
/// * don't be fooled; this **is** a lazy list! this means it's null while empty.
/// * a descriptor associated to amount
/// * a list of list("entity" = ..., "amount" = number, "entity_hint" (optional), "container_hint" (optional)), associated to amount
var/list/contains = list()
/// contains some amount of these entity descriptor groups
///
/// * don't be fooled; this **is** a lazy list! this means it's null while empty.
/// * this should be a list of lists with "entities", "amount" as keys
/// * "entities" should be associated to a list of entities as per [contains]; the entity can be associated to a number for weight
/// * "amount" should be associated to a random amount of them to spawn
/// * amount will be distrbuted randomly as needed, evenly, across the entities.
var/list/contains_some = list()
/// a list of custom 'contains' lines that get printed to the manifest/interface
///
/// * don't be fooled; this **is** a lazy list! this means it's null while empty.
var/list/contains_custom_text = list()
// * For Lazy People *//
/// amount contained
var/lazy_gacha_amount = 1
/// list of entities
var/list/lazy_gacha_contained
//* legacy *//
/// if null, it will be auto-converted from worth
var/legacy_cost
var/legacy_contraband = FALSE
/// literally just a flag so the subsystem picks it up
var/legacy = FALSE
/**
* **Always call this before using it!**
*/
/datum/supply_pack/proc/initialize()
populate()
generate()
compact()
/**
* use this to manipulate our contents before generation.
*/
/datum/supply_pack/proc/populate()
return
/datum/supply_pack/proc/generate()
// resolve accesses
for(var/i in 1 to length(container_access))
var/key = container_access[i]
if(ispath(key, /datum/access))
var/datum/access/resolved_access = SSjob.access_path_lookup[key]
container_access[i] = resolved_access.access_value
for(var/i in 1 to length(container_one_access))
var/key = container_one_access[i]
if(ispath(key, /datum/access))
var/datum/access/resolved_access = SSjob.access_path_lookup[key]
container_one_access[i] = resolved_access.access_value
// auto-detect worth
if(isnull(worth))
worth = detect_worth()
if(!worth)
stack_trace("pack [src] ([type]) failed to detect worth.")
// autoset container name
if(isnull(container_name))
container_name = name
// gacha
if(length(lazy_gacha_contained) && lazy_gacha_amount)
contains_some[++contains_some.len] = list(
"entities" = lazy_gacha_contained,
"amount" = lazy_gacha_amount,
)
lazy_gacha_contained = null
// legacy
if(isnull(legacy_cost))
legacy_cost = ceil(worth * 0.06)
/datum/supply_pack/proc/compact()
if(!length(contains))
contains = null
if(!length(contains_some))
contains_some = null
if(!length(contains_custom_text))
contains_custom_text = null
/datum/supply_pack/proc/detect_worth()
. = 0
// if non-deterministic, must need that
if(length(contains_some) || length(contains_custom_text))
if(isnull(worth_additional))
. = INFINITY
CRASH("attempted to generate worth on a non-deterministic crate (has contains_some or contains_custom_text); fix this.")
// add worth additional
. += worth_additional
// container
if(container_type)
. += SSsupply.value_entity_via_descriptor(container_type)
// deterministic contents
for(var/descriptor as anything in contains)
var/amount = contains[descriptor] || 1
var/worth
if(islist(descriptor))
var/list/descriptor_list = descriptor
worth = SSsupply.value_entity_via_descriptor(
descriptor_list["entity"],
descriptor_list["amount"],
descriptor_list["entity_hint"],
descriptor_list["container_hint"],
)
else
worth = SSsupply.value_entity_via_descriptor(descriptor, amount)
. += worth
/**
* todo: return list of entities?
*
* @return container spawned, or null (which can also mean we don't use a container for some reason)
*/
/datum/supply_pack/proc/instantiate_pack_at(atom/where)
. = instantiate_container(where)
instantiate_contents(.)
/datum/supply_pack/proc/instantiate_container(atom/where)
RETURN_TYPE(/atom/movable)
if(!container_type)
return
var/atom/movable/container = new container_type(where)
. = container
container.name = container_name
container.desc = container_desc
if(isobj(container))
var/obj/obj_container = container
if(container_access)
// todo: getter / setter for req-accesses, enforced cached & deduped lists
obj_container.req_access = container_access.Copy()
if(container_one_access)
// todo: getter / setter for req-accesses, enforced cached & deduped lists
obj_container.req_one_access = container_one_access.Copy()
/**
* todo: return list of entities?
*/
/datum/supply_pack/proc/instantiate_contents(atom/where)
var/list/descriptors_to_spawn = resolve_contents_descriptors()
for(var/descriptor in descriptors_to_spawn)
var/amount = descriptors_to_spawn[descriptor] || 1
SSsupply.instantiate_entity_via_descriptor(descriptor, amount, null, null, where)
/**
* @return list of descriptor associated to amount
*/
/datum/supply_pack/proc/resolve_contents_descriptors()
. = contains? contains.Copy() : list()
if(length(contains_some))
for(var/list/entry as anything in contains_some)
var/list/entities = entry["entities"]
var/amount = entry["amount"]
// this is basically an inlined pickweight()
var/total_weight = 0
for(var/key in entities)
total_weight += entities[key] || 1
if(total_weight == length(entities))
for(var/i in 1 to amount)
.[pick(entities)] += 1
else
for(var/i in 1 to amount)
var/chosen = rand(1, total_weight)
var/remaining = chosen
for(var/j in 1 to length(entities))
var/entity = entities[j]
var/weight = entities[entity]
remaining -= weight
if(remaining <= 0)
.[entity] += 1
//* LEGACY CRAP *//
/**
* generates our HTML manifest as a **list**
*
* argument is provided for container incase you want to modify based on what actually spawned
*/
/datum/supply_pack/proc/get_html_manifest(atom/movable/container)
RETURN_TYPE(/list)
var/list/lines = list()
lines += "Contents:<br>"
lines += "<ul>"
var/list/assembled = list()
var/truncated = FALSE
for(var/atom/movable/thing in container)
assembled["[thing]"] += 1
if(length(assembled) > 100)
truncated = TRUE
break
for(var/i in 1 to length(assembled))
var/key = assembled[i]
var/value = assembled[key]
assembled[i] = "<li>[value > 1? "[value] [key](s)" : "[key]"]</li>"
lines += assembled
if(truncated)
lines += "<li>... (truncated)</li>"
lines += "</ul>"
return lines
/datum/supply_pack/proc/nanoui_manifest_list()
. = list()
for(var/descriptor in contains)
var/amount = contains[descriptor]
var/described = SSsupply.describe_entity_via_descriptor(descriptor, amount)
. += described
for(var/list/gacha_list as anything in contains_some)
var/list/entities = gacha_list["entities"]
for(var/entity in entities)
var/described = SSsupply.describe_entity_via_descriptor(entity)
. += described
/datum/supply_pack/proc/nanoui_is_random()
return !!length(contains_some)