Skip to content

Commit

Permalink
psionics setup
Browse files Browse the repository at this point in the history
  • Loading branch information
kcalbCube committed Jun 7, 2024
1 parent 7086d3b commit 2bbd69f
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 30 deletions.
2 changes: 2 additions & 0 deletions baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
58 changes: 39 additions & 19 deletions code/game/jobs/job/job.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@
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.

var/required_language

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.
Expand All @@ -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)
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions code/game/objects/items/passport.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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]."),
Expand Down
35 changes: 28 additions & 7 deletions code/game/objects/items/weapons/cards_ids.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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]<br>"
. += "Psionics threat level: [psi_level]<br>"

/obj/item/card/id/proc/dat()
var/list/dat = list("<table><tr><td>")
dat += text("Name: []</A><BR>", "[formal_name_prefix][registered_name][formal_name_suffix]")
dat += text("Pronouns: []</A><BR>\n", sex)
dat += text("Age: []</A><BR>\n", age)
dat += text("Name: []</A><br>", "[formal_name_prefix][registered_name][formal_name_suffix]")
dat += text("Pronouns: []</A><br>\n", sex)
dat += text("Age: []</A><br><br>\n", age)

dat += jointext(extra_dat(), null)
dat += "<br>"

if(GLOB.using_map.flags & MAP_HAS_BRANCH)
dat += text("Branch: []</A><BR>\n", military_branch ? military_branch.name : "\[UNSET\]")
if(GLOB.using_map.flags & MAP_HAS_RANK)
dat += text("Rank: []</A><BR>\n", military_rank ? military_rank.name : "\[UNSET\]")
dat += "<br>"

dat += text("Assignment: []</A><BR>\n", assignment)
dat += text("Fingerprint: []</A><BR>\n", fingerprint_hash)
dat += text("Blood Type: []<BR>\n", blood_type)
dat += text("DNA Hash: []<BR><BR>\n", dna_hash)
if(front && side)
dat +="<td align = center valign = top>Photo:<br><img src=front.png height=80 width=80 border=4><img src=side.png height=80 width=80 border=4></td>"
dat += "<td align = center valign = top>Photo:<br>"
dat += "<img style='image-rendering: pixelated;' src=front.png height=96 width=96>"
dat += "<img style='image-rendering: pixelated;' src=side.png height=96 width=96>"
dat += "</td>"
dat += "</tr></table>"
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]",\
Expand Down
5 changes: 5 additions & 0 deletions code/modules/client/preference_setup/preference_setup.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions code/modules/client/preference_setup/psionics/01_basic.dm
Original file line number Diff line number Diff line change
@@ -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: <a href='?src=\ref[src];select_psi_threat_level=1'><b>[pref.psi_threat_level]</b></a><br>"

if(pref.psi_threat_level)
. += "Psionic status: <a href='?src=\ref[src];select_psi_status=1'><b>[GLOB.psi_status2text[pref.psi_status]]</b></a><br>"
. += "Openness: <a href='?src=\ref[src];toggle_psi_openness=1'><b>[pref.psi_openness ? "Yes" : "No"]</b></a><br>"

. = 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 ..()
117 changes: 117 additions & 0 deletions code/modules/client/preference_setup/psionics/02_abilities.dm
Original file line number Diff line number Diff line change
@@ -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()

. += "<style>"
. += ".Current{background: #2f943c}"
. += ".Unavailable{background: #404040}"
. += ".Selectable, a.Selectable{float:none; border:none; margin:none !important; padding:none !important}"
. += ".center { margin: auto; }"
. += ".candystripe { background-color: rgba(148, 148, 148, 0.25);}"
. += ".candystripe:nth-child(odd) {background-color: rgba(0, 0, 0, 0.16);}"

. += "</style>"

. += "<tt><center>"

. += FONT_LARGE("<b>Points remaining: [calculate_free_points()]</b>")

. += "<table style='width: 100%' style='font-size: 15px; text-align: center' class='table'>"

for(var/faculty in pref.psi_abilities)
. += "<tr class='candystripe'>"
. += "<th><div class='average' style='color: [GLOB.psi_faculty2color[faculty]]'>[faculty]:</div></th>"

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)
. += "<td class='Current'><div class='center'>[level_name]</div></td>"
else if(can_select_level(faculty, level_index))
. += "<td class style='background: #40628a;'><div class='center'><a class='Selectable' href='?src=\ref[src];select=[level_index];faculty=[faculty]'>[level_name]</a></div></td>"
else
. += "<td class='Unavailable'><div class='center'>[level_name]</div></td>"

. += "</tr>"

. += "</table>"

. += "</center></tt>"

. = 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
7 changes: 3 additions & 4 deletions mods/_fd/backgrounds/code/factions_ipc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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("<table><tr><td>")
/obj/item/card/id/extra_dat()
. = ..()
if(ipc_gen)
dat += text("Registration: []</A><BR>\n", ipc_gen)
..()
. += "Registration: [ipc_gen]<br>"

/singleton/cultural_info/faction/ipc
economic_power = 0.1
Expand Down

0 comments on commit 2bbd69f

Please sign in to comment.