Files
Timothy TeakettleandGitHub 920bcbed82 loadout sanitization fixes (#7432)
## About The Pull Request
loadout name/desc is stored not encoded and is encoded when it's applied
to the item
we still do a length check on it

collars don't reset their name when you apply a tag now, by storing what
it considers its initial name

## Why It's Good For The Game
fixes bugs

## Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Please note that
maintainers freely reserve the right to remove and add tags should they
deem it appropriate. You can attempt to finagle the system all you want,
but it's best to shoot for clear communication right off the bat. -->

🆑
fix: loadout items with a changed name/desc should no longer double
sanitize
fix: collars don't reset their name when you apply a tag now
🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
2025-12-17 12:02:08 -05:00

153 lines
5.0 KiB
Plaintext

var/list/gear_datums = list()
/proc/tgui_loadout_context()
. = list()
var/list/instances = list()
var/list/categories = list()
for(var/id in global.gear_datums)
var/datum/loadout_entry/entry = global.gear_datums[id]
LAZYDISTINCTADD(categories[entry.category], entry.subcategory)
var/list/instance = entry.tgui_entry_data()
instances[instance["id"]] = instance
.["instances"] = instances
.["categories"] = categories
.["maxEntries"] = LOADOUT_MAX_ITEMS
/datum/loadout_entry
abstract_type = /datum/loadout_entry
/// unique id - must be unique (duh)
var/id
/// allowed standard customizations
var/loadout_customize_flags = LOADOUT_CUSTOMIZE_COLOR | LOADOUT_CUSTOMIZE_DESC | LOADOUT_CUSTOMIZE_NAME
/// name used for save/load don't change this or everyone loses it
var/name
/// what we display our name as. feel free to change this. defaults to name.
var/display_name
/// Description of this gear. If left blank will default to the description of the pathed item.
var/description
/// Path to item.
var/path
/// Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points.
var/cost = 1
/// Slot to equip to.
var/slot
/// Roles that can spawn with this item.
var/list/allowed_roles
// todo: remove in favor of uid locks and or just a better system.
// Term to check the whitelist for.
var/legacy_species_lock
/// category. can't be null.
var/category = LOADOUT_CATEGORY_GENERAL
/// subcategory. can't be null.
var/subcategory = "Miscellaneous"
/// List of datums which will alter the item after it has been spawned.
var/list/tweaks = list()
/// Does it go on the exploitable information list?
var/exploitable = 0
var/static/datum/loadout_tweak/color/gear_tweak_free_color_choice = new
var/list/ckeywhitelist
/// Seasonal whitelist - only create if holiday is active. NOTE: This IGNORES ALLOW_HOLIDAYS config! This is because character setup isn't subsystem-init-synced so we must init all of this dumb shit before config loads.
var/list/holiday_whitelist
/datum/loadout_entry/New()
if(!description)
var/obj/O = path
description = initial(O.desc)
if(!name)
var/obj/O = path
name = initial(O.name)
if(isnull(display_name))
display_name = name
/**
* remove & regex this to just directly access the `.id` variable when we have id's on every entry.
*/
/datum/loadout_entry/proc/legacy_get_id()
return name
/**
* encodes data for tgui/interfaces/CharacterSetup/CharacterLoadout.tsx's [LoadoutEntry] interface.
*/
/datum/loadout_entry/proc/tgui_entry_data()
var/list/tweaks = list()
for(var/datum/loadout_tweak/tweak as anything in src.tweaks)
tweaks += tweak.id
return list(
"name" = display_name || name,
"id" = legacy_get_id(),
"cost" = cost,
"category" = category,
"subcategory" = subcategory,
"customize" = loadout_customize_flags,
"desc" = description,
"tweaks" = tweaks,
)
/datum/loadout_entry/proc/instantiate(atom/where, list/entry_data)
var/path = src.path
var/list/tweak_assembled = list()
for(var/datum/loadout_tweak/tweak as anything in tweaks)
var/tweak_data = entry_data[LOADOUT_ENTRYDATA_TWEAKS]?[tweak.id]
if(isnull(tweak_data))
continue
where = tweak.tweak_spawn_location(where, tweak_data)
path = tweak.tweak_spawn_path(path, tweak_data)
tweak_assembled[tweak] = tweak_data
if(!path)
CRASH("[src] ([src.type]) attempted to spawn a null path with data: '[json_encode(entry_data)]'.")
var/obj/item/spawned = new path(where)
if((loadout_customize_flags & LOADOUT_CUSTOMIZE_NAME) && entry_data[LOADOUT_ENTRYDATA_RENAME])
spawned.name = sanitize(entry_data[LOADOUT_ENTRYDATA_RENAME])
if((loadout_customize_flags & LOADOUT_CUSTOMIZE_DESC) && entry_data[LOADOUT_ENTRYDATA_REDESC])
spawned.desc = sanitize(entry_data[LOADOUT_ENTRYDATA_REDESC])
if((loadout_customize_flags & LOADOUT_CUSTOMIZE_COLOR) && entry_data[LOADOUT_ENTRYDATA_RECOLOR])
spawned.color = entry_data[LOADOUT_ENTRYDATA_RECOLOR]
for(var/datum/loadout_tweak/tweak as anything in tweak_assembled)
tweak.tweak_item(spawned, tweak_assembled[tweak])
//! legacy start
var/mob/M = where
if(istype(M) && exploitable)
M.amend_exploitable(spawned)
//! end
return spawned
/legacy_hook/startup/proc/populate_gear_list()
// Create a list of gear datums to sort
for(var/geartype in typesof(/datum/loadout_entry)-/datum/loadout_entry)
var/datum/loadout_entry/G = geartype
if(initial(G.abstract_type) == geartype)
continue
G = new geartype
if(!G.name)
stack_trace("Missing name on [G.type].")
continue
if(!isnum(G.cost))
stack_trace("Missing cost on [G.type]")
continue
if(!G.path)
stack_trace("Missing path on [G.type].")
continue
if(!G.category)
stack_trace("Missing category on [G.type].")
continue
if(!G.subcategory)
stack_trace("Missing subcategory on [G.type].")
continue
if(length(G.holiday_whitelist))
var/found = FALSE
for(var/name in G.holiday_whitelist)
if(name in SSevents.holidays)
found = TRUE
break
if(!found)
continue
global.gear_datums[G.legacy_get_id()] = G
return 1