mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-12 08:27:13 +01:00
052c9a0d53
Commune can now send snapshot popups of paper & photo contents to targets, similar to how Show-Held-Item can let others see the items' contents. This was originally planned for the initial PR and only didn't make it in because I didn't know how to get the functionality. There's more unique psi-sensitivity interactions in this. There is a 45% chance for psi-deaf targets to even get the photo popup. Photo scribbles fittingly appear scrambled to the psi-deaf. <img width="969" height="232" alt="image" src="https://github.com/user-attachments/assets/84105c37-6c1d-4da2-83bb-738ce6651977" /> On the chance psi-deaf even get the photo popup, there is a 60% chance the photo will be in greyscale. <img width="476" height="195" alt="image" src="https://github.com/user-attachments/assets/030407b7-ce51-4b20-a1e2-6eb93fb21be7" /> Psi-sensitive targets receiving a paper popup will have it translated based on what the sender understands. This is a fun form of translation because it's possible for the target to _not_ understand a written language they actually know simply because the sender doesn't. <img width="1411" height="656" alt="image" src="https://github.com/user-attachments/assets/9d4fe196-2593-4535-b062-bbdfa8e1e819" /> There is also a QoL adjacency check for writing scribbles on photos now because it bugged me I needed to use both hands while testing. NEW: If a psi-deaf target doesn't get it in greyscale, they may also get photos with randomized colors <img width="443" height="444" alt="image" src="https://github.com/user-attachments/assets/f9a1f1c0-a6af-4d1e-95e3-260231d57643" /> This can seriously reframe some photos. Lots of fun with possible misunderstandings. Both the above and below are the same photo with Skrell blood, but the above looks like vaurca blood while the below one doesn't look to even have blood at first glance. <img width="444" height="447" alt="image" src="https://github.com/user-attachments/assets/166b40f2-6ed7-49af-95e1-989ffbb69e60" /> --------- Signed-off-by: runecap <43975590+runecap@users.noreply.github.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com>
233 lines
11 KiB
Plaintext
233 lines
11 KiB
Plaintext
/singleton/psionic_power/commune
|
|
name = "Commune"
|
|
desc = "Psionically commune with the target. Use on an adjacent object to store a mental image for sending. Use in hand with a mental image to warp and add to its description, or clear a warped one."
|
|
icon_state = "tech_audibledeception"
|
|
point_cost = 0
|
|
ability_flags = PSI_FLAG_FOUNDATIONAL
|
|
spell_path = /obj/item/spell/commune
|
|
|
|
/obj/item/spell/commune
|
|
name = "commune"
|
|
desc = "Déjà-vu."
|
|
icon_state = "overload"
|
|
item_icons = null
|
|
cast_methods = CAST_RANGED|CAST_MELEE|CAST_USE
|
|
aspect = ASPECT_PSIONIC
|
|
cooldown = 10
|
|
psi_cost = 15
|
|
//For shared/remote-examine Communes, similar to Show-Held-Object
|
|
var/object
|
|
var/note //desc
|
|
var/image //chat icon
|
|
var/warpdesc //Custom text added right after normal note desc
|
|
|
|
var/popup //Remote popups like paper & photos
|
|
var/obj/item/photo/psiphoto
|
|
var/savedscribble
|
|
var/realscribble
|
|
var/obj/item/paper/psipaper
|
|
var/savedinfo
|
|
var/realinfo
|
|
|
|
/obj/item/spell/commune/proc/ShowSavedScribble(mob/target, saved, psi_deaf = FALSE)
|
|
//Likely a better way, but the trick is quickly swapping real and saved
|
|
realscribble = "[psiphoto.scribble]"
|
|
psiphoto.scribble = "[(saved)]"
|
|
if(psi_deaf && prob(60)) //Psi-deaf targets that do receieve a photo, have it in black & white more than not
|
|
var/icon/realimg = icon(psiphoto.img)
|
|
psiphoto.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
|
psiphoto.show(target)
|
|
psiphoto.img = icon(realimg)
|
|
to_chat(target, SPAN_ALIEN("...Even the colors are half-formed."))
|
|
else if(psi_deaf && prob(60)) //Or with random colors
|
|
var/icon/realimg = icon(psiphoto.img)
|
|
psiphoto.img.MapColors(rgb(rand(0,255), rand(0,255), rand(0,255)), rgb(rand(0,255), rand(0, 255), rand(0,255)), rgb(rand(0,255), rand(0,255), rand(0,255)), rgb(rand(0,255), rand(0,255), rand(0,255)))
|
|
psiphoto.show(target)
|
|
psiphoto.img = icon(realimg)
|
|
to_chat(target, SPAN_ALIEN("...Even the colors are off."))
|
|
else if(prob(10) && (SSatlas.current_sector.name in list(SECTOR_LEMURIAN_SEA, SECTOR_LEMURIAN_SEA_FAR))) //Lemurian Sea jumpscare!
|
|
var/icon/realimg = icon(psiphoto.img)
|
|
psiphoto.img.MapColors(rgb(0,0,0), rgb(0,0,0), rgb(0,0,0), rgb(0,0,0))
|
|
target.eye_blind += 20
|
|
psiphoto.show(target)
|
|
psiphoto.img = icon(realimg)
|
|
to_chat(target, SPAN_ALIEN("An eerie void momentarily blanks your perception."))
|
|
sleep(50)
|
|
target.eye_blind -= 20
|
|
else
|
|
psiphoto.show(target)
|
|
psiphoto.scribble = "[realscribble]"
|
|
|
|
/obj/item/spell/commune/proc/ShowSavedInfo(var/mob/target, saved)
|
|
realinfo = "[psipaper.info]"
|
|
psipaper.info = "[(saved)]"
|
|
psipaper.show_content(target)
|
|
psipaper.info = "[realinfo]"
|
|
|
|
/obj/item/spell/commune/proc/TranslateWritten(mob/target, mob/user, can_read = TRUE)
|
|
//This is just parse_languages() & paperwork reuse
|
|
var/regex/written_lang_regex = new(@"(\[lang=([#_a-zA-Z0-9\^]{1})])(.*?)(\[\/lang])", "g")
|
|
while(written_lang_regex.Find(psipaper.info))
|
|
var/datum/language/L = GLOB.language_keys[written_lang_regex.group[2]]
|
|
if(!L || !L.written_style)
|
|
continue
|
|
|
|
var/content = written_lang_regex.group[3]
|
|
var/user_understands = user.say_understands(null, L)
|
|
|
|
if(!user_understands)
|
|
content = L.scramble(content)
|
|
psipaper.info = replacetext(psipaper.info, written_lang_regex.match, "<span class='[L.written_style] [user_understands ? "understood" : "scramble"]'>[L.short && user_understands ? "([L.short]) [content]" : content]</span>")
|
|
|
|
simple_asset_ensure_is_sent(target, /datum/asset/simple/paper)
|
|
var/datum/browser/paper_win = new(target, "Mental Image", null, 450, 500, null, TRUE)
|
|
paper_win.set_content("<head><title>(Mental Image)</title><style>body {background-color: [color];}</style></head><body>[can_read ? psipaper.info : stars(psipaper.info)][psipaper.stamps]</body>")
|
|
paper_win.add_stylesheet("paper_languages", 'html/browser/paper_languages.css')
|
|
paper_win.open()
|
|
|
|
/obj/item/spell/commune/Destroy()
|
|
object = null
|
|
note = null
|
|
psiphoto = null
|
|
psipaper = null
|
|
return ..()
|
|
|
|
/obj/item/spell/commune/on_use_cast(mob/user)
|
|
. = ..()
|
|
if(warpdesc)
|
|
warpdesc = null
|
|
to_chat(user, SPAN_NOTICE("You rein back to your initial mental image of \the [object], clearing the warped additions."))
|
|
else if(warpdesc == null && (object))
|
|
warpdesc = tgui_input_text(user, "How would you warp the mental image of \the [object]? This will only add to its existing description, never override or delete.", "Warp Mental Image", "", MAX_MESSAGE_LEN, TRUE)
|
|
if(!warpdesc)
|
|
warpdesc = null
|
|
return
|
|
to_chat(user, SPAN_NOTICE("You rethink your mental image of \the [object], warping in additions to its details."))
|
|
else return
|
|
|
|
/obj/item/spell/commune/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(object)
|
|
to_chat(user, SPAN_NOTICE("You already have a mental image in mind of \the [object]."))
|
|
return
|
|
else if(istype(hit_atom, /obj/item/photo) && !object)
|
|
psiphoto = hit_atom
|
|
object = "[hit_atom.name]"
|
|
note = ("[hit_atom.desc]" + " [psiphoto.picture_desc]")
|
|
savedscribble = "[psiphoto.scribble]" //To later compare & prevent displaying a new scribble the psion never saved
|
|
image = icon2html(psiphoto, user)
|
|
popup = TRUE
|
|
to_chat(user, SPAN_NOTICE("You note and refine a mental replica of \the [object] for sending."))
|
|
else if(istype(hit_atom, /obj/item/paper) && !object)
|
|
psipaper = hit_atom
|
|
object = "[hit_atom.name]"
|
|
note = "[hit_atom.desc]"
|
|
savedinfo = "[psipaper.info]"
|
|
image = icon2html(psipaper, user)
|
|
popup = TRUE
|
|
to_chat(user, SPAN_NOTICE("You note and refine a mental copy of \the [object] for sending."))
|
|
else if(isobj(hit_atom) && !object)
|
|
object = "[hit_atom.name]" //Save a snapshot of its info so they don't auto-update.
|
|
note = ("[hit_atom.desc]" + " [hit_atom.desc_feedback]")
|
|
image = icon2html(hit_atom, user)
|
|
to_chat(user, SPAN_NOTICE("You note and refine a mental image of \the [object] for sending."))
|
|
|
|
/obj/item/spell/commune/on_ranged_cast(atom/hit_atom, mob/user)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
commune(hit_atom, user)
|
|
|
|
/obj/item/spell/commune/proc/commune(atom/hit_atom, mob/user)
|
|
if(!isliving(hit_atom))
|
|
return
|
|
var/mob/living/target = hit_atom
|
|
if(target.stat == DEAD)
|
|
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
|
return
|
|
|
|
var/psi_blocked = target.is_psi_blocked(user, FALSE)
|
|
if(psi_blocked)
|
|
to_chat(user, psi_blocked)
|
|
return
|
|
|
|
//Checks psi-sensitivity for remote item examines, because normal Commune gets blocked
|
|
if(object)
|
|
to_chat(user, SPAN_CULT("You psionically project to [target]: [image] [object]\n[note]" + " [warpdesc]"))
|
|
var/mob/living/carbon/human/T = target
|
|
var/target_sensitivity = T.check_psi_sensitivity()
|
|
if(target_sensitivity >= 1) //Small detail, psions can subtly tell apart warped descriptions easier with the new line.
|
|
to_chat(T, SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
|
to_chat(T, SPAN_CULT("What must be [user]'s mental image of \a [image] [object] appears in your mind.\n[note]\n[warpdesc]"))
|
|
if(popup)
|
|
if(psipaper)
|
|
realinfo = "[psipaper.info]"
|
|
psipaper.info = "[savedinfo]"
|
|
TranslateWritten(T, user) //High-sensitives get papers translated to what the psion knew
|
|
to_chat(T, SPAN_NOTICE("You sense [user]'s psyche link so well, you understand the sheet just as they do."))
|
|
psipaper.info = "[realinfo]"
|
|
else
|
|
ShowSavedScribble(T, savedscribble)
|
|
else if(target_sensitivity >= 0) //Info span so it feels like an actual examine at a glance
|
|
to_chat(T, SPAN_INFO("<b>A mental image of \a [image] [object] suddenly builds in your mind.</b>\n[note]" + " [warpdesc]"))
|
|
if(popup)
|
|
if(psipaper)
|
|
ShowSavedInfo(T, savedinfo)
|
|
else
|
|
ShowSavedScribble(T, savedscribble)
|
|
else //60% chance low-targets don't even get the icon. 35% (per point) of the object's name is scrambled, but base desc can still clue the item
|
|
var/scrmbldobject = stars(object, (abs(target_sensitivity) * 35))
|
|
var/scrmbldnote = stars(note, (abs(target_sensitivity) * 25))
|
|
var/scrmbldwarp = stars(warpdesc, (abs(target_sensitivity) * 45)) //Warped descriptions are even more abnormal, so extra scrambled
|
|
to_chat(T, SPAN_ALIEN("<b>A mental image of \a [prob(40)?"[image] ":""][scrmbldobject] attempts to form in your mind.</b>\n[scrmbldnote]" + " [scrmbldwarp]"))
|
|
if(prob(45) && popup)
|
|
if(psipaper)
|
|
var/scrmbldinfo = stars(psipaper.info, (abs(target_sensitivity) * 35)) //upped ratio as pencode itself gets scrambled too
|
|
ShowSavedInfo(T, scrmbldinfo) //that technically makes text in other langs slightly decipherable ICly, buuut...
|
|
to_chat(T, SPAN_ALIEN("It's so nonsensical, you can't tell what's even real.")) //plant doubt by saying it's nonsense.
|
|
else
|
|
var/scrmbldscribble = stars(psiphoto.scribble, (abs(target_sensitivity) * 25))
|
|
ShowSavedScribble(T, scrmbldscribble, TRUE)
|
|
|
|
log_say("[key_name(user)] communed to [key_name(target)]: [image] [object]\n[note]" + " [warpdesc]")
|
|
|
|
for(var/mob/M as anything in GLOB.player_list)
|
|
if(M.stat == DEAD && M.client.prefs.toggles & CHAT_GHOSTEARS)
|
|
to_chat(M, "<span class='notice'>[user] psionically says to [target]:</span> [image] [object]\n[note]" + " [warpdesc]")
|
|
return
|
|
var/text = tgui_input_text(user, "What would you like to say?", "Commune", "", MAX_MESSAGE_LEN, TRUE)
|
|
if(!text)
|
|
return
|
|
text = formalize_text(text)
|
|
|
|
if(target.stat == DEAD)
|
|
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
|
return
|
|
|
|
log_say("[key_name(user)] communed to [key_name(target)]: [text]")
|
|
|
|
to_chat(user, SPAN_CULT("You psionically say to [target]: [text]"))
|
|
|
|
for (var/mob/M in GLOB.player_list)
|
|
if (istype(M, /mob/abstract/new_player))
|
|
continue
|
|
else if(M.stat == DEAD && M.client.prefs.toggles & CHAT_GHOSTEARS)
|
|
to_chat(M, "<span class='notice'>[user] psionically says to [target]:</span> [text]")
|
|
|
|
var/mob/living/carbon/human/H = target
|
|
var/target_sensitivity = H.check_psi_sensitivity()
|
|
if(target_sensitivity >= 1)
|
|
// Augmented case for anyone with enhancements to their psi-sensitivity.
|
|
to_chat(H, SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
|
to_chat(H, SPAN_CULT("<b>You instinctively sense [user] passing a thought into your mind:</b> [text]"))
|
|
else if (target_sensitivity >= 0)
|
|
// Standard case for most characters.
|
|
to_chat(H, SPAN_ALIEN("<b>A thought from outside your consciousness slips into your mind:</b> [text]"))
|
|
else
|
|
// Negative sensitivity case, message arrives scrambled.
|
|
// 25% of the message is scrambled per negative point of psi-sensitivity. Allowing fractional points.
|
|
var/scrambled_message = stars(text, (abs(target_sensitivity) * 25))
|
|
to_chat(H, SPAN_ALIEN("<b>A half-formed thought passes through your mind:</b> [scrambled_message]"))
|