mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-30 21:17:04 +01:00
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:
co-authored by
Zandario
VM_USER <VM_USER>
AlphaM01
LordPapalus
parent
1f99f4b154
commit
28e11dee54
@@ -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
|
||||
Reference in New Issue
Block a user