Files
CatoChristopherMrow 02e183642e Spritebloat final boss (#5704)
## About The Pull Request
SO! This pr does a few things:
One, it makes a new system for having properly dynamic uniforms. You can
select the core components (for most things, a shirt and pants),
accessories, etc. I've gone ahead and made a dynamic security uniform
via this. I also made a dynamic security cap!

Two, it adds a few black reskins. All the reskins do is remove some
small red accent. The reskins are available for the following:

Sec hud sunglasses
Sec gloves
Sec belt

Tackle gloves and gorrila gloves both can also now be reskinned to the
black variant that already existed.

Before anyone screams, I am adding NO blue. (Though, you could recolor
the uniform in the loadout)

(video was too big for github so here it is on catbox)
https://files.catbox.moe/8wtgkv.mp4
## Why It's Good For The Game
I kept feeling unsatisfied with my options as security, and as a whole.
Hopefully this is a better uniform system, even if we don't end up using
it that much.
## Proof Of Testing
<details>
<summary>Screenshots/Videos</summary>

</details>

## Changelog
🆑 UvvU
add: Added dynamic uniform support
add: Added black varients for the sec huds, belt, and gloves
/🆑
2026-06-23 22:06:44 +02:00

202 lines
6.6 KiB
Plaintext

///Helper to create a typepath to be used in the UI
#define SANITIZED_PATH(path)(replacetext(replacetext("[path]", "/obj/item/", ""), "/", "-"))
/obj/machinery/vending/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet_batched/vending),
)
/obj/machinery/vending/ui_interact(mob/user, datum/tgui/ui)
if(SEND_SIGNAL(src, COMSIG_VENDING_UI_INTERACT, user, ui) & VENDING_DENIED)
if(icon_deny)
flick(icon_deny, src)
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Vending", name)
ui.open()
/**
* Returns a list of given product records of the vendor to be used in UI.
* arguments:
* records - list of records available
* categories - list of categories available
* premium - bool of whether a record should be priced by a custom/premium price or not
*/
/obj/machinery/vending/proc/collect_records_for_static_data(list/records, list/categories, premium)
PROTECTED_PROC(TRUE)
var/static/list/default_category = list(
"name" = "Products",
"icon" = "cart-shopping",
)
var/list/out_records = list()
for (var/datum/data/vending_product/record as anything in records)
var/list/static_record = list(
path = SANITIZED_PATH(record.product_path),
name = record.name,
price = record.price,
ref = REF(record),
colorable = record.colorable,
)
var/atom/printed = record.product_path
//BUBBER ADDITION START - Dynamic uniforms
var/component_preview_applied = FALSE
if(ispath(printed, /obj/item))
var/obj/item/printed_item = printed
if(initial(printed_item.greyscale_component_style_type))
static_record["image"] = get_component_style_vending_preview_image(printed_item)
component_preview_applied = TRUE
//BUBBER ADDITION END
// If it's not GAGS and has no innate colors we have to care about, we use DMIcon
//BUBBER EDIT START - dynamic uniform
if(!component_preview_applied \
&& ispath(printed, /atom) \
&& (!initial(printed.greyscale_config) || !initial(printed.greyscale_colors)) \
&& !initial(printed.color) \
)
//BUBBER EDIT END
static_record["icon"] = initial(printed.icon)
static_record["icon_state"] = initial(printed.icon_state)
var/list/category = record.category || default_category
if (!isnull(category))
if (!(category["name"] in categories))
categories[category["name"]] = list("icon" = category["icon"])
static_record["category"] = category["name"]
if (premium)
static_record["premium"] = TRUE
out_records += list(static_record)
return out_records
/obj/machinery/vending/ui_static_data(mob/user)
var/list/data = list()
if(ad_list.len)
data["ad"] = ad_list[rand(1, ad_list.len)]
data["all_products_free"] = all_products_free
data["department"] = payment_department
data["jobDiscount"] = DEPARTMENT_DISCOUNT
data["product_records"] = list()
data["displayed_currency_icon"] = displayed_currency_icon
data["displayed_currency_name"] = " [displayed_currency_name]"
var/list/categories = list()
data["product_records"] = collect_records_for_static_data(product_records, categories)
data["coin_records"] = collect_records_for_static_data(coin_records, categories, premium = TRUE)
data["hidden_records"] = collect_records_for_static_data(hidden_records, categories, premium = TRUE)
data["categories"] = categories
return data
/**
* Returns the balance that the vendor will use for proceeding payment. Most vendors would want to use the user's
* card's account credits balance.
* arguments:
* passed_id - the id card that will be billed for the product
*/
/obj/machinery/vending/proc/fetch_balance_to_use(obj/item/card/id/passed_id)
PROTECTED_PROC(TRUE)
return passed_id.registered_account.account_balance
/obj/machinery/vending/ui_data(mob/user)
. = list()
var/obj/item/card/id/card_used
var/held_cash = 0
if(isliving(user))
var/mob/living/living_user = user
card_used = living_user.get_idcard(TRUE)
held_cash = living_user.tally_physical_credits()
var/list/user_data = null
if(card_used?.registered_account)
user_data = list()
user_data["name"] = card_used.registered_account.account_holder
user_data["cash"] = fetch_balance_to_use(card_used) + held_cash
if(card_used.registered_account.account_job)
user_data["job"] = card_used.registered_account.account_job.title
user_data["department"] = card_used.registered_account.account_job.paycheck_department
else
user_data["job"] = "No Job"
user_data["department"] = DEPARTMENT_UNASSIGNED
.["user"] = user_data
.["stock"] = list()
for (var/datum/data/vending_product/product_record as anything in product_records + coin_records + hidden_records)
.["stock"][SANITIZED_PATH(product_record.product_path)] = list(
amount = product_record.amount,
free = length(product_record.returned_products)
)
if(prob(10) && ad_list.len)
.["ad"] = ad_list[rand(1, ad_list.len)]
.["extended_inventory"] = extended_inventory
/obj/machinery/vending/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("vend")
. = vend(params, ui.user)
if("select_colors")
var/datum/data/vending_product/product = locate(params["ref"])
if(!istype(product))
return FALSE
var/atom/fake_atom = product.product_path
//BUBBER ADDITION START - Dynamic uniforms
if(ispath(fake_atom, /obj/item))
var/obj/item/fake_item = fake_atom
if(initial(fake_item.greyscale_component_style_type))
return open_component_style_vending_menu(product, params, ui.user)
//BUBBER ADDITION END
var/config = initial(fake_atom.greyscale_config)
if(!config)
return FALSE
var/list/allowed_configs = list("[config]")
if(ispath(fake_atom, /obj/item))
var/obj/item/item = fake_atom
if(initial(item.greyscale_config_worn))
allowed_configs += "[initial(item.greyscale_config_worn)]"
if(initial(item.greyscale_config_inhand_left))
allowed_configs += "[initial(item.greyscale_config_inhand_left)]"
if(initial(item.greyscale_config_inhand_right))
allowed_configs += "[initial(item.greyscale_config_inhand_right)]"
var/datum/greyscale_modify_menu/menu = new(
src, ui.user, allowed_configs, CALLBACK(src, PROC_REF(_vend_greyscale), params, ui.user),
starting_icon_state=initial(fake_atom.icon_state),
starting_config = initial(fake_atom.greyscale_config),
starting_colors = initial(fake_atom.greyscale_colors)
)
menu.ui_interact(ui.user)
return TRUE
/**
* Vends a greyscale modified item.
* arguments:
* menu - greyscale config menu that has been used to vend the item
*/
/obj/machinery/vending/proc/_vend_greyscale(list/params, mob/user, datum/greyscale_modify_menu/menu)
PRIVATE_PROC(TRUE)
if(user != menu.user)
return
vend(params, user, menu.split_colors)
#undef SANITIZED_PATH