diff --git a/baystation12.dme b/baystation12.dme index a89b58dd1c34d..a84d26578807d 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1584,6 +1584,8 @@ #include "code\modules\client\preference_setup\loadout\lists\xenowear.dm" #include "code\modules\client\preference_setup\occupation\occupation.dm" #include "code\modules\client\preference_setup\occupation\skill_selection.dm" +#include "code\modules\client\preference_setup\psionics\01_basic.dm" +#include "code\modules\client\preference_setup\psionics\02_abilities.dm" #include "code\modules\clothing\_clothing.dm" #include "code\modules\clothing\_clothing_flags.dm" #include "code\modules\clothing\buttons.dm" diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 09ef39dbb7262..7f78a425db410 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -49,7 +49,7 @@ var/list/species_branch_rank_cache_ = list() var/list/psi_faculties // Starting psi faculties, if any. var/psi_latency_chance = 0 // Chance of an additional psi latency, if any. - var/give_psionic_implant_on_join = TRUE // If psionic, will be implanted for control. + var/give_psionic_implant_on_join = FALSE // If psionic, will be implanted for control. var/use_species_whitelist // If set, restricts the job to players with the given species whitelist. This does NOT restrict characters joining as the job to the species itself. @@ -57,6 +57,8 @@ var/faction = MOB_FACTION_CREW + var/global/psi_allowed_species = list(/datum/species/human,/datum/species/human/vatgrown,/datum/species/human/tritonian,/datum/species/human/gravworlder,/datum/species/human/spacer) + /datum/job/New() if(prob(100-availablity_chance)) //Close positions, blah blah. @@ -71,6 +73,41 @@ /datum/job/dd_SortValue() return title +/datum/job/proc/give_psi(mob/living/carbon/human/H) + if(!(all_species[H.client.prefs.species].type in psi_allowed_species)) + return + + if(psi_latency_chance && prob(psi_latency_chance)) + H.set_psi_rank(pick(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS, PSI_CONSCIOUSNESS, PSI_MANIFESTATION, PSI_METAKINESIS), 1, defer_update = TRUE) + + var/list/psi_abilities_by_name = H.client.prefs.psi_abilities + + LAZYINITLIST(psi_faculties) + for(var/faculty_name in psi_abilities_by_name) + var/faculty_id = SSpsi.faculties_by_name[faculty_name].id + psi_faculties |= list("[faculty_id]" = psi_abilities_by_name[faculty_name]) + + for(var/psi in psi_faculties) + H.set_psi_rank(psi, psi_faculties[psi], take_larger = TRUE, defer_update = TRUE) + + H.psi.update() + + give_psionic_implant_on_join ||= (H.client.prefs.psi_openness && H.client.prefs.psi_status < 4) + + if(!give_psionic_implant_on_join) + return + + var/obj/item/implant/psi_control/imp = new + imp.implanted(H) + imp.forceMove(H) + imp.imp_in = H + imp.implanted = TRUE + var/obj/item/organ/external/affected = H.get_organ(BP_HEAD) + if(affected) + affected.implants += imp + imp.part = affected + to_chat(H, SPAN_DANGER("As a registered psionic, you are fitted with a psi-dampening control implant. Using psi-power while the implant is active will result in neural shocks and your violation being reported.")) + /datum/job/proc/equip(mob/living/carbon/human/H, alt_title, datum/mil_branch/branch, datum/mil_rank/grade) if (required_language) @@ -81,24 +118,7 @@ H.add_language(LANGUAGE_SPACER) H.set_default_language(all_languages[LANGUAGE_SPACER]) - if(psi_latency_chance && prob(psi_latency_chance)) - H.set_psi_rank(pick(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS), 1, defer_update = TRUE) - if(islist(psi_faculties)) - for(var/psi in psi_faculties) - H.set_psi_rank(psi, psi_faculties[psi], take_larger = TRUE, defer_update = TRUE) - if(H.psi) - H.psi.update() - if(give_psionic_implant_on_join) - var/obj/item/implant/psi_control/imp = new - imp.implanted(H) - imp.forceMove(H) - imp.imp_in = H - imp.implanted = TRUE - var/obj/item/organ/external/affected = H.get_organ(BP_HEAD) - if(affected) - affected.implants += imp - imp.part = affected - to_chat(H, SPAN_DANGER("As a registered psionic, you are fitted with a psi-dampening control implant. Using psi-power while the implant is active will result in neural shocks and your violation being reported.")) + give_psi(H) var/singleton/hierarchy/outfit/outfit = get_outfit(H, alt_title, branch, grade) if(outfit) . = outfit.equip(H, title, alt_title) diff --git a/code/game/objects/items/passport.dm b/code/game/objects/items/passport.dm index 4c4395b94c983..f93ff57f2d698 100644 --- a/code/game/objects/items/passport.dm +++ b/code/game/objects/items/passport.dm @@ -21,6 +21,12 @@ fingerprint = "N/A" info = "\icon[src] [src]:\nName: [H.real_name]\nSpecies: [H.get_species()]\nPronouns: [H.pronouns]\nAge: [H.age]\nPlace of Birth: [pob]\nFingerprint: [fingerprint]" + var/psi + if(H.client?.prefs?.psi_threat_level && H.client.prefs.psi_openness) + psi = "Psionics status: [GLOB.psi_status2text[H.client.prefs.psi_status]]\n" + psi += "Psionics threat level: [H.client.prefs.psi_threat_level]\n" + info = "\icon[src] [src]:\nName: [H.real_name]\nSpecies: [H.get_species()]\nGender: [gender2text(H.gender)]\nAge: [H.age]\n[psi]Place of Birth: [pob]\nFingerprint: [fingerprint]" + /obj/item/passport/attack_self(mob/user as mob) user.visible_message( SPAN_ITALIC("[user] opens and checks [src]."), diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 2862b1f50a63c..b52e9b4d40e9b 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -221,6 +221,9 @@ var/global/const/NO_EMAG_ACT = -50 var/detail_color var/extra_details + var/psi_status + var/psi_level + /obj/item/card/id/Initialize() .=..() if(job_access_type) @@ -268,7 +271,7 @@ var/global/const/NO_EMAG_ACT = -50 if(front && side) send_rsc(user, front, "front.png") send_rsc(user, side, "side.png") - var/datum/browser/popup = new(user, "idcard", name, 600, 250) + var/datum/browser/popup = new(user, "idcard", name, 600, 350) popup.set_content(dat()) popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() @@ -293,7 +296,7 @@ var/global/const/NO_EMAG_ACT = -50 id_card.formal_name_prefix = initial(id_card.formal_name_prefix) id_card.formal_name_suffix = initial(id_card.formal_name_suffix) - if(client && client.prefs) + if(client?.prefs) for(var/culturetag in client.prefs.cultural_info) var/singleton/cultural_info/culture = SSculture.get_culture(client.prefs.cultural_info[culturetag]) if(culture) @@ -314,6 +317,10 @@ var/global/const/NO_EMAG_ACT = -50 id_card.dna_hash = dna.unique_enzymes id_card.fingerprint_hash= md5(dna.uni_identity) + if(client?.prefs?.psi_threat_level && client.prefs.psi_openness) + id_card.psi_level = client.prefs.psi_threat_level + id_card.psi_status = GLOB.psi_status2text[client.prefs.psi_status] + /mob/living/carbon/human/set_id_info(obj/item/card/id/id_card) ..() id_card.age = age @@ -327,25 +334,39 @@ var/global/const/NO_EMAG_ACT = -50 for(var/add_access in category.add_accesses) id_card.access.Add(add_access) +/obj/item/card/id/proc/extra_dat() + . = list() + if(psi_status) + . += "Psionics status: [psi_status]
" + . += "Psionics threat level: [psi_level]
" + /obj/item/card/id/proc/dat() var/list/dat = list("" + dat += "" dat += "
") - dat += text("Name: []
", "[formal_name_prefix][registered_name][formal_name_suffix]") - dat += text("Pronouns: []
\n", sex) - dat += text("Age: []
\n", age) + dat += text("Name: []
", "[formal_name_prefix][registered_name][formal_name_suffix]") + dat += text("Pronouns: []
\n", sex) + dat += text("Age: []

\n", age) + + dat += jointext(extra_dat(), null) + dat += "
" if(GLOB.using_map.flags & MAP_HAS_BRANCH) dat += text("Branch: []
\n", military_branch ? military_branch.name : "\[UNSET\]") if(GLOB.using_map.flags & MAP_HAS_RANK) dat += text("Rank: []
\n", military_rank ? military_rank.name : "\[UNSET\]") + dat += "
" dat += text("Assignment: []
\n", assignment) dat += text("Fingerprint: []
\n", fingerprint_hash) dat += text("Blood Type: []
\n", blood_type) dat += text("DNA Hash: []

\n", dna_hash) if(front && side) - dat +="
Photo:
Photo:
" + dat += "" + dat += "" + dat += "
" - return jointext(dat,null) + + return jointext(dat, null) /obj/item/card/id/attack_self(mob/user as mob) user.visible_message("\The [user] shows you: [icon2html(src, viewers(get_turf(src)))] [src.name]. The assignment on the card: [src.assignment]",\ diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index 09344a28fcf70..1803a2b7cf894 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -30,6 +30,11 @@ var/global/const/CHARACTER_PREFERENCE_INPUT_TITLE = "Character Preference" sort_order = 4 category_item_type = /datum/category_item/player_setup_item/antagonism +/datum/category_group/player_setup_category/psionics_preferences + name = "Psionics" + sort_order = 5 + category_item_type = /datum/category_item/player_setup_item/psionics + /datum/category_group/player_setup_category/loadout_preferences name = "Loadout" sort_order = 6 diff --git a/code/modules/client/preference_setup/psionics/01_basic.dm b/code/modules/client/preference_setup/psionics/01_basic.dm new file mode 100644 index 0000000000000..e0a04aa3b303d --- /dev/null +++ b/code/modules/client/preference_setup/psionics/01_basic.dm @@ -0,0 +1,55 @@ +GLOBAL_LIST_INIT(psi_status2text, list("C", "B", "A", "S")) +GLOBAL_LIST_INIT(text2psi_status, list("C" = 1, "B" = 2, "A" = 3, "S" = 4)) + +/datum/preferences + var/psi_threat_level = 0 + var/psi_status = 4 + var/psi_openness = FALSE + +/datum/category_item/player_setup_item/psionics/basic + name = "Basic" + sort_order = 1 + +/datum/category_item/player_setup_item/psionics/basic/load_character(datum/pref_record_reader/R) + pref.psi_threat_level = R.read("psi_threat_level") + pref.psi_status = R.read("psi_status") + pref.psi_openness = R.read("psi_openness") + +/datum/category_item/player_setup_item/psionics/basic/save_character(datum/pref_record_writer/W) + W.write("psi_threat_level", pref.psi_threat_level) + W.write("psi_status", pref.psi_status) + W.write("psi_openness", pref.psi_openness) + +/datum/category_item/player_setup_item/psionics/basic/sanitize_character() + pref.psi_threat_level = clamp(pref.psi_threat_level, 0, 4) + pref.psi_status = clamp(pref.psi_status , 1, 4) + +/datum/category_item/player_setup_item/psionics/basic/content() + . = list() + . += "Threat level: [pref.psi_threat_level]
" + + if(pref.psi_threat_level) + . += "Psionic status: [GLOB.psi_status2text[pref.psi_status]]
" + . += "Openness: [pref.psi_openness ? "Yes" : "No"]
" + + . = jointext(.,null) + +/datum/category_item/player_setup_item/psionics/OnTopic(href, list/href_list, mob/user) + if(href_list["select_psi_threat_level"]) + pref.psi_threat_level = text2num(input("Select threat level", CHARACTER_PREFERENCE_INPUT_TITLE, pref.psi_threat_level) in list("0", "1", "2", "3", "4")) + pref.psi_threat_level = clamp(pref.psi_threat_level, 0, 4) + return TOPIC_REFRESH + + else if(href_list["select_psi_status"]) + var/selection = input("Select psionics status", CHARACTER_PREFERENCE_INPUT_TITLE, GLOB.psi_status2text[pref.psi_status]) in GLOB.text2psi_status + if(!(selection in GLOB.text2psi_status)) + return TOPIC_HANDLED + + pref.psi_status = GLOB.text2psi_status[selection] + return TOPIC_REFRESH + + else if(href_list["toggle_psi_openness"]) + pref.psi_openness = !pref.psi_openness + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/psionics/02_abilities.dm b/code/modules/client/preference_setup/psionics/02_abilities.dm new file mode 100644 index 0000000000000..efa51e8751231 --- /dev/null +++ b/code/modules/client/preference_setup/psionics/02_abilities.dm @@ -0,0 +1,117 @@ +GLOBAL_LIST_INIT(psi_level2cost, list(\ + "Blunt" = 0, \ + "Latent" = 1, \ + "Apprentice" = 2, \ + "Operant" = 4, \ + "Master" = 6, \ + "Grandmaster" = 8 \ +)) + +GLOBAL_LIST_INIT(psi_faculty2color, list(\ + "Catastellia" = COLOR_SURGERY_BLUE, + "Allaxetia" = COLOR_SURGERY_BLUE, + "Hyloforia" = COLOR_MEDICAL_UNKNOWN_IMPLANT, + "Demiurgy" = COLOR_LIGHT_CYAN, + "Metaplexy" = COLOR_SEDONA, + "Teleplexy" = COLOR_LIGHT_CYAN, + "Ephanoferia" = MANIFEST_COLOR_SERVICE +)) + +GLOBAL_LIST_INIT(psi_threat_level2free_points, list(3, 4, 9, 14)) + +/datum/preferences + var/list/psi_abilities + + +/datum/category_item/player_setup_item/psionics/abilities + name = "Abilities" + sort_order = 3 + +/datum/category_item/player_setup_item/psionics/abilities/load_character(datum/pref_record_reader/R) + pref.psi_abilities = R.read("psi_abilities") + +/datum/category_item/player_setup_item/psionics/abilities/save_character(datum/pref_record_writer/W) + W.write("psi_abilities", pref.psi_abilities) + +/datum/category_item/player_setup_item/psionics/abilities/sanitize_character() + if(pref.psi_abilities) + return ..() + + pref.psi_abilities = list() + for(var/faculty in SSpsi.faculties_by_name) + pref.psi_abilities[faculty] = 1 + + return ..() + +/datum/category_item/player_setup_item/psionics/abilities/proc/calculate_free_points() + . = GLOB.psi_threat_level2free_points[pref.psi_threat_level] + + for(var/faculty in pref.psi_abilities) + for(var/level in 1 to GLOB.psi_level2cost.len) + var/level_name = GLOB.psi_level2cost[level] + var/level_cost = GLOB.psi_level2cost[level_name] + + if(pref.psi_abilities[faculty] == level) + . -= level_cost + +/datum/category_item/player_setup_item/psionics/abilities/proc/can_select_level(faculty, level) + return (calculate_free_points() + GLOB.psi_level2cost[GLOB.psi_level2cost[pref.psi_abilities[faculty]]]) >= GLOB.psi_level2cost[GLOB.psi_level2cost[level]] + +/datum/category_item/player_setup_item/psionics/abilities/content() + if(!pref.psi_threat_level) + return ..() + + . = list() + + . += "" + + . += "
" + + . += FONT_LARGE("Points remaining: [calculate_free_points()]") + + . += "" + + for(var/faculty in pref.psi_abilities) + . += "" + . += "" + + for(var/level_index in 1 to GLOB.psi_level2cost.len) + var/level_name = GLOB.psi_level2cost[level_index] + + if(pref.psi_abilities[faculty] == level_index) + . += "" + else if(can_select_level(faculty, level_index)) + . += "" + else + . += "" + + . += "" + + . += "
[faculty]:
[level_name]
[level_name]
" + + . += "
" + + . = jointext(., null) + +/datum/category_item/player_setup_item/psionics/abilities/OnTopic(href, list/href_list, mob/user) + if(..()) + return TOPIC_HANDLED + + if(href_list["select"]) + var/level = text2num(href_list["select"]) + var/faculty = href_list["faculty"] + + if(!can_select_level(faculty, level)) + return TOPIC_HANDLED + + pref.psi_abilities[faculty] = level + + return TOPIC_REFRESH diff --git a/mods/_fd/backgrounds/code/factions_ipc.dm b/mods/_fd/backgrounds/code/factions_ipc.dm index 4c5c9c14a552a..d2899f4bc866b 100644 --- a/mods/_fd/backgrounds/code/factions_ipc.dm +++ b/mods/_fd/backgrounds/code/factions_ipc.dm @@ -39,11 +39,10 @@ if(is_species(SPECIES_IPC)) id_card.ipc_gen = get_cultural_value(TAG_FACTION) -/obj/item/card/id/dat() - var/list/dat = list("
") +/obj/item/card/id/extra_dat() + . = ..() if(ipc_gen) - dat += text("Registration: []
\n", ipc_gen) - ..() + . += "Registration: [ipc_gen]
" /singleton/cultural_info/faction/ipc economic_power = 0.1