lore/contractor/background/character overhaul project (public branch edition) (#4488)

Co-authored-by: silicons <2003111+silicons@users.noreply.github.com>
Co-authored-by: Zandario <zandarioh@gmail.com>
Co-authored-by: VM_USER <VM_USER>
Co-authored-by: AlphaM01 <33434925+AlphaM01@users.noreply.github.com>
Co-authored-by: LordPapalus <54518057+LordPapalus@users.noreply.github.com>
This commit is contained in:
silicons
2022-11-09 01:57:00 -06:00
committed by GitHub
co-authored by Zandario VM_USER <VM_USER> AlphaM01 LordPapalus
parent 1f99f4b154
commit 28e11dee54
604 changed files with 9140 additions and 4230 deletions
@@ -0,0 +1,67 @@
/**
* Manages character setup, character saving, loading,
* and will eventually serve as the middleware
* between character preferences and character
* persistence as well.
*/
SUBSYSTEM_DEF(characters)
name = "Characters"
init_order = INIT_ORDER_CHARACTERS
priority = FIRE_PRIORITY_CHARSETUP
subsystem_flags = SS_BACKGROUND
wait = 1 SECOND
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/prefs_awaiting_setup = list()
var/list/preferences_datums = list()
var/list/newplayers_requiring_init = list()
var/list/save_queue = list()
/datum/controller/subsystem/characters/Initialize()
rebuild_caches()
for(var/ckey in GLOB.preferences_datums)
var/datum/preferences/P = GLOB.preferences_datums[ckey]
if(!istype(P))
stack_trace("what?")
continue
P.Initialize()
return ..()
/datum/controller/subsystem/characters/Recover()
. = ..()
rebuild_caches()
/datum/controller/subsystem/characters/proc/rebuild_caches()
rebuild_species()
rebuild_languages()
rebuild_character_species()
rebuild_backgrounds()
/*
/datum/controller/subsystem/characters/Initialize()
while(prefs_awaiting_setup.len)
var/datum/preferences/prefs = prefs_awaiting_setup[prefs_awaiting_setup.len]
prefs_awaiting_setup.len--
prefs.setup()
while(newplayers_requiring_init.len)
var/mob/new_player/new_player = newplayers_requiring_init[newplayers_requiring_init.len]
newplayers_requiring_init.len--
new_player.deferred_login()
. = ..()
*/ //Might be useful if we ever switch to Bay prefs.
/datum/controller/subsystem/characters/fire(resumed = FALSE)
while(save_queue.len)
var/datum/preferences/prefs = save_queue[save_queue.len]
save_queue.len--
if(!QDELETED(prefs))
prefs.save_preferences()
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/characters/proc/queue_preferences_save(var/datum/preferences/prefs)
save_queue |= prefs
@@ -0,0 +1,112 @@
/datum/controller/subsystem/characters
//! Backgrounds - to be shoved into some lore system later (maybe)
var/list/character_origins
var/list/character_citizenships
var/list/character_religions
var/list/character_factions
/datum/controller/subsystem/characters/proc/rebuild_backgrounds()
character_origins = list()
character_citizenships = list()
character_religions = list()
character_factions = list()
for(var/path in subtypesof(/datum/lore/character_background))
var/datum/lore/character_background/L = path
if(initial(L.abstract_type) == path)
continue
L = new path
if(!L.id)
stack_trace("no ID on [L.type]")
continue
if(istype(L, /datum/lore/character_background/citizenship))
if(character_citizenships[L.id])
stack_trace("dupe [L.id] on [L.type]")
continue
character_citizenships[L.id] = L
if(istype(L, /datum/lore/character_background/origin))
if(character_origins[L.id])
stack_trace("dupe [L.id] on [L.type]")
continue
character_origins[L.id] = L
if(istype(L, /datum/lore/character_background/religion))
if(character_religions[L.id])
stack_trace("dupe [L.id] on [L.type]")
continue
character_religions[L.id] = L
if(istype(L, /datum/lore/character_background/faction))
if(character_factions[L.id])
stack_trace("dupe [L.id] on [L.type]")
continue
character_factions[L.id] = L
tim_sort(character_origins, /proc/cmp_auto_compare, TRUE)
tim_sort(character_citizenships, /proc/cmp_auto_compare, TRUE)
tim_sort(character_religions, /proc/cmp_auto_compare, TRUE)
tim_sort(character_factions, /proc/cmp_auto_compare, TRUE)
/datum/controller/subsystem/characters/proc/available_citizenships(species_id)
. = list()
for(var/id in character_citizenships)
var/datum/lore/character_background/citizenship/L = character_citizenships[id]
if(L.check_species_id(species_id))
. += L
/datum/controller/subsystem/characters/proc/available_religions(species_id)
. = list()
for(var/id in character_religions)
var/datum/lore/character_background/religion/L = character_religions[id]
if(L.check_species_id(species_id))
. += L
/datum/controller/subsystem/characters/proc/available_factions(species_id, origin_id, citizenship_id)
. = list()
for(var/id in character_factions)
var/datum/lore/character_background/faction/L = character_factions[id]
if(L.origin_whitelist && !(origin_id in L.origin_whitelist))
continue
if(L.citizenship_whitelist && !(citizenship_id in L.citizenship_whitelist))
continue
if(L.check_species_id(species_id))
. += L
/datum/controller/subsystem/characters/proc/available_origins(species_id, category)
. = list()
for(var/id in character_origins)
var/datum/lore/character_background/origin/L = character_origins[id]
if(category && (L.category != category))
continue
if(L.check_species_id(species_id))
. += L
/datum/controller/subsystem/characters/proc/resolve_citizenship(id)
RETURN_TYPE(/datum/lore/character_background/citizenship)
if(ispath(id))
var/datum/lore/character_background/bg = id
id = initial(bg.id)
return character_citizenships[id]
/datum/controller/subsystem/characters/proc/resolve_faction(id)
RETURN_TYPE(/datum/lore/character_background/faction)
if(ispath(id))
var/datum/lore/character_background/bg = id
id = initial(bg.id)
return character_factions[id]
/datum/controller/subsystem/characters/proc/resolve_religion(id)
RETURN_TYPE(/datum/lore/character_background/religion)
if(ispath(id))
var/datum/lore/character_background/bg = id
id = initial(bg.id)
return character_religions[id]
/datum/controller/subsystem/characters/proc/resolve_origin(id)
RETURN_TYPE(/datum/lore/character_background/origin)
if(ispath(id))
var/datum/lore/character_background/bg = id
id = initial(bg.id)
return character_origins[id]
/datum/controller/subsystem/characters/proc/job_locks_for_faction(id)
var/datum/lore/character_background/faction/F = resolve_faction(id)
return F.job_whitelist
@@ -0,0 +1,83 @@
/datum/controller/subsystem/characters
//! Species
/**
* yeah so funny right
*
* we have a lot of fake-people around (minor races/human reskins)
* i can't remove them because that'd ruffle feathers
* ( literally, looking at you harpies )
* so **everyone** gets to be a /datum/character_species
* that way we get the name, desc, and species id of what
* actual species we should be any are able to do roundstart tweaks.
*/
var/list/character_species_lookup
/**
* species ui cache
* so we don't rebuild this every time someone makes an ui
* list of categories associated to lists
* second layer of list contains:
* {name: str, desc: str, whitelisted: 1 or 0, id: str}
*/
var/list/character_species_cache
/datum/controller/subsystem/characters/proc/rebuild_character_species()
// make species lookup
character_species_lookup = list()
for(var/path in species_paths)
var/datum/species/S = species_paths[path]
if(!(S.species_spawn_flags & SPECIES_SPAWN_ALLOWED)) // don't bother lmao
continue
if(!S.uid)
stack_trace("no species ID on [S.type].")
continue
if(character_species_lookup[S.uid])
stack_trace("species uid collision on [S.uid] from [S.type].")
continue
character_species_lookup[S.uid] = S.construct_character_species()
for(var/path in subtypesof(/datum/character_species))
var/datum/character_species/S = path
if(initial(S.abstract_type) == path)
continue
S = new path
if(character_species_lookup[S.uid])
stack_trace("ignoring custom character species path [path] - collides on uid [S.uid]")
continue
character_species_lookup[S.uid] = S
// make species data cache
character_species_cache = list()
for(var/id in character_species_lookup)
var/datum/character_species/S = character_species_lookup[id]
LAZYINITLIST(character_species_cache[S.category])
character_species_cache[S.category] += list(list(
"id" = S.uid,
"whitelisted" = S.whitelisted,
"name" = S.name,
"desc" = S.desc,
"appearance_flags" = S.species_appearance_flags,
"flags" = S.species_flags,
"category" = S.category, // note to self optimize this
))
tim_sort(character_species_lookup, /proc/cmp_auto_compare, TRUE)
/datum/controller/subsystem/characters/proc/resolve_character_species(uid)
RETURN_TYPE(/datum/character_species)
return character_species_lookup[uid]
/datum/controller/subsystem/characters/proc/construct_character_species(uid)
RETURN_TYPE(/datum/species)
var/datum/character_species/faux = resolve_character_species(uid)
var/datum/species/built = new faux.real_species_type
if(faux.is_real)
// let's assume they aren't an idiot and didn't hardcode a real species as a character species
return built
faux.tweak(built)
return built
/datum/controller/subsystem/characters/proc/all_character_species()
RETURN_TYPE(/list)
. = list()
for(var/uid in character_species_lookup)
. += character_species_lookup[uid]
@@ -0,0 +1,79 @@
/datum/controller/subsystem/characters
/// languages by id
var/list/language_lookup
/// languages by path
var/list/language_paths
// todo: better way to determine so we have no collisions
/// language key cache
var/list/language_keys
// todo: remove
/// language by name
var/list/language_names
/datum/controller/subsystem/characters/proc/rebuild_languages()
language_lookup = list()
language_keys = list()
language_names = list()
language_paths = list()
for(var/path in subtypesof(/datum/language))
var/datum/language/L = path
if(initial(L.abstract_type) == path)
continue
L = new path
if(language_lookup[L.id])
stack_trace("duped language id [L.id] on [path] skipped")
continue
if(language_names[L.name])
stack_trace("duped language name [L.name] on [path] skipped")
continue
language_lookup[L.id] = L
language_names[L.name] = L
language_paths[path] = L
if(!(L.language_flags & NONGLOBAL))
language_keys[L.key] = L
tim_sort(language_names, /proc/cmp_auto_compare, TRUE)
tim_sort(language_keys, /proc/cmp_auto_compare)
tim_sort(language_paths, /proc/cmp_auto_compare, TRUE)
/datum/controller/subsystem/characters/proc/resolve_language(id_path_name)
if(ispath(id_path_name))
return resolve_language_path(id_path_name)
return resolve_language_id(id_path_name) || resolve_language_name(id_path_name)
// todo: deprecated
/datum/controller/subsystem/characters/proc/resolve_language_name(name)
RETURN_TYPE(/datum/language)
return language_names[name]
/datum/controller/subsystem/characters/proc/resolve_language_id(id)
RETURN_TYPE(/datum/language)
return language_lookup[id]
// todo: deprecated
/datum/controller/subsystem/characters/proc/resolve_language_path(path)
RETURN_TYPE(/datum/language)
ASSERT(ispath(path, /datum/language))
return language_paths[path]
/**
* returns all language datums
* do NOT modify these unless you know what you are doing!
*/
/datum/controller/subsystem/characters/proc/all_languages()
RETURN_TYPE(/list)
. = list()
for(var/path in language_paths)
. += language_paths[path]
/**
* returns all language names
*/
/datum/controller/subsystem/characters/proc/all_language_names()
RETURN_TYPE(/list)
. = list()
for(var/name in language_names)
. += name
/datum/controller/subsystem/characters/proc/resolve_language_key(key)
return language_keys[key]
@@ -0,0 +1,120 @@
/datum/controller/subsystem/characters
/// species by id
var/list/species_lookup
/// species by type
var/list/species_paths
/// species by name
var/list/species_names
// todo: ids
/// playable species - names
var/list/whitelisted_species
// todo: ids
/// whitelisted species - names
var/list/playable_species
// todo: ids
/// custom species icon bases - names
var/list/custom_species_bases
/// default species path
var/default_species_path = /datum/species/human
/datum/controller/subsystem/characters/proc/rebuild_species()
species_lookup = list()
species_paths = list()
species_names = list()
playable_species = list()
whitelisted_species = list()
custom_species_bases = list()
var/static/list/blacklisted_icon_ids = list(SPECIES_ID_CUSTOM, SPECIES_ID_PROMETHEAN)
var/static/list/whitelisted_icon_ids = list(SPECIES_ID_VULPKANIN, SPECIES_ID_XENOMORPH_HUNTER)
for(var/path in subtypesof(/datum/species))
var/datum/species/S = path
if(initial(S.abstract_type) == path)
continue
S = new path
if(species_lookup[S.uid])
stack_trace("species id collision on [S.uid] on [path]")
continue
if(species_names[S.name])
stack_trace("species name collision on [S.name] on [path]")
continue
species_lookup[S.uid] = S
species_names[S.name] = S
species_paths[path] = S
if(S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED)
whitelisted_species += S.name
if(!(S.species_spawn_flags & SPECIES_SPAWN_RESTRICTED))
playable_species += S.name
if((!(S.species_spawn_flags & (SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_RESTRICTED)) && !(S.get_species_id() in blacklisted_icon_ids)) || (S.get_species_id() in whitelisted_icon_ids))
custom_species_bases += S.name
tim_sort(species_lookup, /proc/cmp_auto_compare, TRUE)
tim_sort(species_names, /proc/cmp_auto_compare, TRUE)
tim_sort(species_lookup, /proc/cmp_auto_compare, TRUE)
tim_sort(whitelisted_species, /proc/cmp_auto_compare)
tim_sort(playable_species, /proc/cmp_auto_compare)
tim_sort(custom_species_bases, /proc/cmp_auto_compare)
/datum/controller/subsystem/characters/proc/resolve_species(id_path_name)
RETURN_TYPE(/datum/species)
if(ispath(id_path_name))
return species_paths[id_path_name]
return species_lookup[id_path_name] || species_names[id_path_name]
/datum/controller/subsystem/characters/proc/resolve_species_id(id)
RETURN_TYPE(/datum/species)
return species_lookup[id]
/datum/controller/subsystem/characters/proc/resolve_species_path(path)
RETURN_TYPE(/datum/species)
ASSERT(ispath(path, /datum/species)) // why are you passing in invalid paths?
return species_paths[path]
// todo: deprecated kinda - most of these uses should just be id
/datum/controller/subsystem/characters/proc/resolve_species_name(name)
RETURN_TYPE(/datum/species)
return species_names[name]
/datum/controller/subsystem/characters/proc/construct_species_id(id)
RETURN_TYPE(/datum/species)
var/datum/species/static_copy = resolve_species_id(id)
if(!static_copy)
return
return new static_copy.type
/datum/controller/subsystem/characters/proc/construct_species_path(path)
RETURN_TYPE(/datum/species)
ASSERT(ispath(path, /datum/species)) // why are you passing in invalid paths?
return new path
// todo: deprecated
/datum/controller/subsystem/characters/proc/construct_species_name(name)
RETURN_TYPE(/datum/species)
var/datum/species/static_copy = resolve_species_name(name)
if(!static_copy)
return
return new static_copy.type
// todo: deprecated
/**
* returns all static species datums
* DO NOT EVER MODIFY THESE.
*/
/datum/controller/subsystem/characters/proc/all_static_species_meta()
RETURN_TYPE(/list)
. = list()
for(var/path in species_paths)
. += species_paths[path]
/datum/controller/subsystem/characters/proc/all_species_names()
RETURN_TYPE(/list)
. = list()
for(var/name in species_names)
. += name
/**
* default species id for when someone's species is removed/no longer playable
*/
/datum/controller/subsystem/characters/proc/default_species_id()
var/datum/species/S = resolve_species_path(ispath(default_species_path, /datum/species)? default_species_path : /datum/species/human)
return S.id