Files
Bubberstation/code/datums/datacore.dm
SkyratBot e142e098b4 [MIRROR] Removes overlay queuing, saves 6/7 seconds of initialize. Lightly modifies stat tracking macros [MDB IGNORE] (#16449)
* Removes overlay queuing, saves 6/7 seconds of initialize. Lightly modifies stat tracking macros

* merge conflict

* other changes

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: tastyfish <crazychris32@gmail.com>
2022-09-27 17:52:53 -04:00

422 lines
17 KiB
Plaintext

GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
//TODO: someone please get rid of this shit
/datum/datacore
var/list/medical = list()
var/medicalPrintCount = 0
var/list/general = list()
var/list/security = list()
var/securityPrintCount = 0
var/securityCrimeCounter = 0
///This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/list/locked = list()
/datum/data
var/name = "data"
/datum/data/record
name = "record"
var/list/fields = list()
/datum/data/record/Destroy()
GLOB.data_core.medical -= src
GLOB.data_core.security -= src
GLOB.data_core.general -= src
GLOB.data_core.locked -= src
. = ..()
/// A helper proc to get the front photo of a character from the record.
/// Handles calling `get_photo()`, read its documentation for more information.
/datum/data/record/proc/get_front_photo()
return get_photo("photo_front", SOUTH)
/// A helper proc to get the side photo of a character from the record.
/// Handles calling `get_photo()`, read its documentation for more information.
/datum/data/record/proc/get_side_photo()
return get_photo("photo_side", WEST)
/**
* You shouldn't be calling this directly, use `get_front_photo()` or `get_side_photo()`
* instead.
*
* This is the proc that handles either fetching (if it was already generated before) or
* generating (if it wasn't) the specified photo from the specified record. This is only
* intended to be used by records that used to try to access `fields["photo_front"]` or
* `fields["photo_side"]`, and will return an empty icon if there isn't any of the necessary
* fields.
*
* Arguments:
* * field_name - The name of the key in the `fields` list, of the record itself.
* * orientation - The direction in which you want the character appearance to be rotated
* in the outputed photo.
*
* Returns an empty `/icon` if there was no `character_appearance` entry in the `fields` list,
* returns the generated/cached photo otherwise.
*/
/datum/data/record/proc/get_photo(field_name, orientation)
if(fields[field_name])
return fields[field_name]
if(!fields["character_appearance"])
return new /icon()
var/mutable_appearance/character_appearance = fields["character_appearance"]
character_appearance.setDir(orientation)
var/icon/picture_image = getFlatIcon(character_appearance)
var/datum/picture/picture = new
picture.picture_name = "[fields["name"]]"
picture.picture_desc = "This is [fields["name"]]."
picture.picture_image = picture_image
var/obj/item/photo/photo = new(null, picture)
fields[field_name] = photo
return photo
/datum/data/crime
name = "crime"
var/crimeName = ""
var/crimeDetails = ""
var/author = ""
var/time = ""
var/fine = 0
var/paid = 0
var/dataId = 0
/datum/datacore/proc/createCrimeEntry(cname = "", cdetails = "", author = "", time = "", fine = 0)
var/datum/data/crime/c = new /datum/data/crime
c.crimeName = cname
c.crimeDetails = cdetails
c.author = author
c.time = time
c.fine = fine
c.paid = 0
c.dataId = ++securityCrimeCounter
return c
/datum/datacore/proc/addCitation(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["citation"]
crimes |= crime
return
/datum/datacore/proc/removeCitation(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["citation"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/datum/datacore/proc/payCitation(id, cDataId, amount)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["citation"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crime.paid = crime.paid + amount
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SEC)
D.adjust_money(amount)
return
/**
* Adds crime to security record.
*
* Is used to add single crime to someone's security record.
* Arguments:
* * id - record id.
* * datum/data/crime/crime - premade array containing every variable, usually created by createCrimeEntry.
*/
/datum/datacore/proc/addCrime(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["crim"]
crimes |= crime
return
/**
* Deletes crime from security record.
*
* Is used to delete single crime to someone's security record.
* Arguments:
* * id - record id.
* * cDataId - id of already existing crime.
*/
/datum/datacore/proc/removeCrime(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/**
* Adds details to a crime.
*
* Is used to add or replace details to already existing crime.
* Arguments:
* * id - record id.
* * cDataId - id of already existing crime.
* * details - data you want to add.
*/
/datum/datacore/proc/addCrimeDetails(id, cDataId, details)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crime.crimeDetails = details
return
/datum/datacore/proc/manifest()
for(var/i in GLOB.new_player_list)
var/mob/dead/new_player/N = i
if(N.new_character)
log_manifest(N.ckey,N.new_character.mind,N.new_character)
if(ishuman(N.new_character))
manifest_inject(N.new_character, N.client) // SKYRAT EDIT - Alt-titles - ORIGINAL: manifest_inject(N.new_character)
CHECK_TICK
/datum/datacore/proc/manifest_modify(name, assignment, trim)
var/datum/data/record/foundrecord = find_record("name", name, GLOB.data_core.general)
if(foundrecord)
foundrecord.fields["rank"] = assignment
foundrecord.fields["trim"] = trim
/datum/datacore/proc/get_manifest()
// First we build up the order in which we want the departments to appear in.
var/list/manifest_out = list()
for(var/datum/job_department/department as anything in SSjob.joinable_departments)
manifest_out[department.department_name] = list()
manifest_out[DEPARTMENT_UNASSIGNED] = list()
var/list/departments_by_type = SSjob.joinable_departments_by_type
for(var/datum/data/record/record as anything in GLOB.data_core.general)
var/name = record.fields["name"]
var/rank = record.fields["rank"] // user-visible job
var/trim = record.fields["trim"] // internal jobs by trim type
var/datum/job/job = SSjob.GetJob(trim)
if(!job || !(job.job_flags & JOB_CREW_MANIFEST) || !LAZYLEN(job.departments_list)) // In case an unlawful custom rank is added.
var/list/misc_list = manifest_out[DEPARTMENT_UNASSIGNED]
misc_list[++misc_list.len] = list(
"name" = name,
"rank" = rank,
"trim" = trim, // SKYRAT CHANGE ADDITION - ALTERNATIVE_JOB_TITLES
)
continue
for(var/department_type as anything in job.departments_list)
var/datum/job_department/department = departments_by_type[department_type]
if(!department)
stack_trace("get_manifest() failed to get job department for [department_type] of [job.type]")
continue
var/list/entry = list(
"name" = name,
"rank" = rank,
"trim" = trim, // SKYRAT CHANGE ADDITION - ALTERNATIVE_JOB_TITLES
)
var/list/department_list = manifest_out[department.department_name]
if(istype(job, department.department_head))
department_list.Insert(1, null)
department_list[1] = entry
else
department_list[++department_list.len] = entry
// Trim the empty categories.
for (var/department in manifest_out)
if(!length(manifest_out[department]))
manifest_out -= department
return manifest_out
/datum/datacore/proc/get_manifest_html(monochrome = FALSE)
var/list/manifest = get_manifest()
var/dat = {"
<head><style>
.manifest {border-collapse:collapse;}
.manifest td, th {border:1px solid [monochrome?"black":"#DEF; background-color:white; color:black"]; padding:.25em}
.manifest th {height: 2em; [monochrome?"border-top-width: 3px":"background-color: #48C; color:white"]}
.manifest tr.head th { [monochrome?"border-top-width: 1px":"background-color: #488;"] }
.manifest tr.alt td {[monochrome?"border-top-width: 2px":"background-color: #DEF"]}
</style></head>
<table class="manifest" width='350px'>
<tr class='head'><th>Name</th><th>Rank</th></tr>
"}
for(var/department in manifest)
var/list/entries = manifest[department]
dat += "<tr><th colspan=3>[department]</th></tr>"
//JUST
var/even = FALSE
for(var/entry in entries)
var/list/entry_list = entry
dat += "<tr[even ? " class='alt'" : ""]><td>[entry_list["name"]]</td><td>[entry_list["rank"] == entry_list["trim"] ? entry_list["rank"] : "[entry_list["rank"]] ([entry_list["trim"]])"]</td></tr>" // SKYRAT CHANGE EDIT - ALTERNATIVE_JOB_TITLES - Original: dat += "<tr[even ? " class='alt'" : ""]><td>[entry_list["name"]]</td><td>[entry_list["rank"]]</td></tr>"
even = !even
dat += "</table>"
dat = replacetext(dat, "\n", "")
dat = replacetext(dat, "\t", "")
return dat
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/human_client) // SKYRAT EDIT - Alt-titles - ORIGINAL: /datum/datacore/proc/manifest_inject(mob/living/carbon/human/H)
set waitfor = FALSE
var/static/list/show_directions = list(SOUTH, WEST)
if(H.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST)
var/assignment = H.mind.assigned_role.title
// SKYRAT EDIT ADDITION BEGIN - ALTERNATIVE_JOB_TITLES
// The alt job title, if user picked one, or the default
var/chosen_assignment = human_client?.prefs.alt_job_titles[assignment] || assignment
// SKYRAT EDIT ADDITION END - ALTERNATIVE_JOB_TITLES
var/static/record_id_num = 1001
var/id = num2hex(record_id_num++,6)
var/mutable_appearance/character_appearance = new(H.appearance)
//These records should ~really~ be merged or something
//General Record
var/datum/data/record/G = new()
G.fields["id"] = id
G.fields["name"] = H.real_name
G.fields["rank"] = chosen_assignment // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - Original: G.fields["rank"] = assignment
G.fields["trim"] = assignment
G.fields["initial_rank"] = assignment
G.fields["age"] = H.age
G.fields["species"] = H.dna.species.name
G.fields["fingerprint"] = md5(H.dna.unique_identity)
G.fields["p_stat"] = "Active"
G.fields["m_stat"] = "Stable"
G.fields["gender"] = H.gender
if(H.gender == "male")
G.fields["gender"] = "Male"
else if(H.gender == "female")
G.fields["gender"] = "Female"
else
G.fields["gender"] = "Other"
G.fields["character_appearance"] = character_appearance
// SKYRAT ADDITION START - RP RECORDS
G.fields["past_records"] = human_client?.prefs?.read_preference(/datum/preference/text/general) || ""
G.fields["background_records"] = human_client?.prefs?.read_preference(/datum/preference/text/background) || ""
G.fields["exploitable_records"] = human_client?.prefs?.read_preference(/datum/preference/text/exploitable) || ""
// SKYRAT ADDITION END
general += G
//Medical Record
var/datum/data/record/M = new()
M.fields["id"] = id
M.fields["name"] = H.real_name
M.fields["blood_type"] = H.dna.blood_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["mi_dis"] = H.get_quirk_string(!medical, CAT_QUIRK_MINOR_DISABILITY)
M.fields["mi_dis_d"] = H.get_quirk_string(medical, CAT_QUIRK_MINOR_DISABILITY)
M.fields["ma_dis"] = H.get_quirk_string(!medical, CAT_QUIRK_MAJOR_DISABILITY)
M.fields["ma_dis_d"] = H.get_quirk_string(medical, CAT_QUIRK_MAJOR_DISABILITY)
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = H.get_quirk_string(!medical, CAT_QUIRK_NOTES)
M.fields["notes_d"] = H.get_quirk_string(medical, CAT_QUIRK_NOTES)
// SKYRAT EDIT ADD - RP RECORDS
M.fields["past_records"] = human_client?.prefs?.read_preference(/datum/preference/text/medical) || ""
// SKYRAT EDIT END
medical += M
//Security Record
var/datum/data/record/S = new()
S.fields["id"] = id
S.fields["name"] = H.real_name
S.fields["criminal"] = "None"
S.fields["citation"] = list()
S.fields["crim"] = list()
S.fields["notes"] = "No notes."
// SKYRAT EDIT ADD - RP RECORDS
S.fields["past_records"] = human_client?.prefs?.read_preference(/datum/preference/text/security) || ""
// SKYRAT EDIT END
security += S
//Locked Record
var/datum/data/record/L = new()
L.fields["id"] = md5("[H.real_name][assignment]") //surely this should just be id, like the others?
L.fields["name"] = H.real_name
L.fields["rank"] = chosen_assignment // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - Original: L.fields["rank"] = assignment
L.fields["trim"] = assignment
G.fields["initial_rank"] = assignment
L.fields["age"] = H.age
L.fields["gender"] = H.gender
if(H.gender == "male")
G.fields["gender"] = "Male"
else if(H.gender == "female")
G.fields["gender"] = "Female"
else
G.fields["gender"] = "Other"
L.fields["blood_type"] = H.dna.blood_type
L.fields["b_dna"] = H.dna.unique_enzymes
L.fields["identity"] = H.dna.unique_identity
L.fields["species"] = H.dna.species.type
L.fields["features"] = H.dna.features
L.fields["character_appearance"] = character_appearance
L.fields["mindref"] = H.mind
locked += L
return
//Todo: Add citations to the prinout - you get them from sec record's "citation" field, same as "crim" (which is frankly a terrible fucking field name)
///Standardized printed records. SPRs. Like SATs but for bad guys who probably didn't actually finish school. Input the records and out comes a paper.
/proc/print_security_record(datum/data/record/general_data, datum/data/record/security, atom/location)
if(!istype(general_data) && !istype(security))
stack_trace("called without any datacores! this may or may not be intentional!")
if(!isatom(location)) //can't drop the paper if we didn't get passed an atom.
CRASH("NO VALID LOCATION PASSED.")
GLOB.data_core.securityPrintCount++ //just alters the name of the paper.
var/obj/item/paper/printed_paper = new(location)
var/final_paper_text = "<CENTER><B>Security Record - (SR-[GLOB.data_core.securityPrintCount])</B></CENTER><BR>"
if((istype(general_data, /datum/data/record) && GLOB.data_core.general.Find(general_data)))
final_paper_text += text("Name: [] ID: []<BR>\nGender: []<BR>\nAge: []<BR>", general_data.fields["name"], general_data.fields["id"], general_data.fields["gender"], general_data.fields["age"])
final_paper_text += "\nSpecies: [general_data.fields["species"]]<BR>"
final_paper_text += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", general_data.fields["fingerprint"], general_data.fields["p_stat"], general_data.fields["m_stat"])
//SKYRAT EDIT ADD - RP RECORDS
if(!(general_data.fields["past_records"] == ""))
final_paper_text += "\nGeneral Records:\n[general_data.fields["past_records"]]\n"
//SKYRAT EDIT ADD END
else
final_paper_text += "<B>General Record Lost!</B><BR>"
if((istype(security, /datum/data/record) && GLOB.data_core.security.Find(security)))
//final_paper_text += text("<BR>\n<CENTER><B>Security Data</B></CENTER><BR>\nCriminal Status: []", security.fields["criminal"]) // ORIGINAL
//SKYRAT EDIT ADDITION START - RP RECORDS
final_paper_text += text("<BR>\n<CENTER><B>Security Data</B></CENTER><BR>\n")
if(!(security.fields["past_records"] == ""))
final_paper_text += "\nSecurity Records:\n[security.fields["past_records"]]\n"
final_paper_text += text("Criminal Status: []", security.fields["criminal"])
//SKYRAT EDIT END
final_paper_text += "<BR>\n<BR>\nCrimes:<BR>\n"
final_paper_text +={"<table style="text-align:center;" border="1" cellspacing="0" width="100%">
<tr>
<th>Crime</th>
<th>Details</th>
<th>Author</th>
<th>Time Added</th>
</tr>"}
for(var/datum/data/crime/c in security.fields["crim"])
final_paper_text += "<tr><td>[c.crimeName]</td>"
final_paper_text += "<td>[c.crimeDetails]</td>"
final_paper_text += "<td>[c.author]</td>"
final_paper_text += "<td>[c.time]</td>"
final_paper_text += "</tr>"
final_paper_text += "</table>"
final_paper_text += text("<BR>\nImportant Notes:<BR>\n\t[]<BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", security.fields["notes"])
var/counter = 1
while(security.fields[text("com_[]", counter)])
final_paper_text += text("[]<BR>", security.fields[text("com_[]", counter)])
counter++
printed_paper.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, general_data.fields["name"])
else //if no security record
final_paper_text += "<B>Security Record Lost!</B><BR>"
printed_paper.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, "Record Lost")
final_paper_text += "</TT>"
printed_paper.add_raw_text(final_paper_text)
printed_paper.update_appearance() //make sure we make the paper look like it has writing on it.