/datum/mutation/antenna
name = "Antenna"
desc = "The affected person sprouts an antenna. This is known to allow them to access common radio channels passively."
quality = POSITIVE
text_gain_indication = span_notice("You feel an antenna sprout from your forehead.")
text_lose_indication = span_notice("Your antenna shrinks back down.")
instability = POSITIVE_INSTABILITY_MINOR
difficulty = 8
var/datum/weakref/radio_weakref
/obj/item/implant/radio/antenna
name = "internal antenna organ"
desc = "The internal organ part of the antenna. Science has not yet given it a good name."
icon = 'icons/obj/devices/voice.dmi'//maybe make a unique sprite later. not important
icon_state = "walkietalkie"
/obj/item/implant/radio/antenna/Initialize(mapload)
. = ..()
radio.name = "internal antenna"
/datum/mutation/antenna/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(!.)
return
var/obj/item/implant/radio/antenna/linked_radio = new(owner)
linked_radio.implant(owner, null, TRUE, TRUE)
radio_weakref = WEAKREF(linked_radio)
/datum/mutation/antenna/on_losing(mob/living/carbon/human/owner)
if(..())
return
var/obj/item/implant/radio/antenna/linked_radio = radio_weakref.resolve()
if(linked_radio)
QDEL_NULL(linked_radio)
/datum/mutation/antenna/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))//-MUTATIONS_LAYER+1
/datum/mutation/antenna/get_visual_indicator()
return visual_indicators[type][1]
/datum/mutation/mindreader
name = "Mind Reader"
desc = "The affected person can look into the recent memories of others."
quality = POSITIVE
text_gain_indication = span_notice("You hear distant voices at the corners of your mind.")
text_lose_indication = span_notice("The distant voices fade.")
power_path = /datum/action/cooldown/spell/pointed/mindread
instability = POSITIVE_INSTABILITY_MINOR
difficulty = 8
locked = TRUE
/datum/action/cooldown/spell/pointed/mindread
name = "Mindread"
desc = "Read the target's mind."
button_icon_state = "mindread"
school = SCHOOL_PSYCHIC
cooldown_time = 5 SECONDS
spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC
antimagic_flags = MAGIC_RESISTANCE_MIND
ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi'
/datum/action/cooldown/spell/pointed/mindread/Grant(mob/grant_to)
. = ..()
if (!owner)
return
ADD_TRAIT(grant_to, TRAIT_MIND_READER, GENETIC_MUTATION)
RegisterSignal(grant_to, COMSIG_MOB_EXAMINATE, PROC_REF(on_examining))
/datum/action/cooldown/spell/pointed/mindread/Remove(mob/remove_from)
. = ..()
REMOVE_TRAIT(remove_from, TRAIT_MIND_READER, GENETIC_MUTATION)
UnregisterSignal(remove_from, COMSIG_MOB_EXAMINATE)
/datum/action/cooldown/spell/pointed/mindread/is_valid_target(atom/cast_on)
if(!isliving(cast_on))
return FALSE
var/mob/living/living_cast_on = cast_on
if(!living_cast_on.mind)
to_chat(owner, span_warning("[cast_on] has no mind to read!"))
return FALSE
if(living_cast_on.stat == DEAD)
to_chat(owner, span_warning("[cast_on] is dead!"))
return FALSE
if(living_cast_on.mob_biotypes & MOB_ROBOTIC)
to_chat(owner, span_warning("[cast_on] is robotic, you can't read [cast_on.p_their()] mind!"))
return FALSE
return TRUE
/datum/action/cooldown/spell/pointed/mindread/cast(mob/living/cast_on)
. = ..()
if(cast_on.can_block_magic(antimagic_flags, charge_cost = 0))
to_chat(owner, span_warning("As you reach into [cast_on]'s mind, \
you are stopped by a mental blockage. It seems you've been foiled."))
return
if(cast_on == owner)
to_chat(owner, span_warning("You plunge into your mind... Yep, it's your mind."))
return
if(cast_on.has_status_effect(/datum/status_effect/heretic_passive/moon))
to_chat(owner, span_hypnophrase(span_bolddanger("YOU SEEK THE TRUTH? I WILL SHOW YOU EVERYTHING.")))
if(isliving(owner))
var/mob/living/reader = owner
reader.apply_status_effect(/datum/status_effect/moon_converted)
return
if(HAS_TRAIT(cast_on, TRAIT_EVIL))
to_chat(owner, span_warning("As you reach into [cast_on]'s mind, \
you feel the overwhelming emptiness within. A truly evil being. \
[HAS_TRAIT(owner, TRAIT_EVIL) ? "It's nice to find someone who is like-minded." : "What is wrong with this person?"]"))
var/list/log_info = list()
var/list/discovered_info = list("You plunge into [cast_on]'s mind and discover...")
if(prob(20))
// chance to alert the read-ee
to_chat(cast_on, span_danger("You feel something foreign enter your mind."))
log_info += "Target alerted!"
var/list/recent_speech = cast_on.copy_recent_speech(copy_amount = 3, line_chance = 50)
if(length(recent_speech))
discovered_info += "...Drifting memories of past conversations:"
var/list/speech_block = list()
for(var/spoken_memory in recent_speech)
speech_block += " \"[spoken_memory]\"..."
log_info += "Recent speech: \"[spoken_memory]\""
discovered_info += jointext(speech_block, "
")
if(iscarbon(cast_on))
var/mob/living/carbon/carbon_cast_on = cast_on
discovered_info += "...Intent to [carbon_cast_on.combat_mode ? "harm" : "help"]."
discovered_info += "...True identity of [carbon_cast_on.mind.name]."
log_info += "Intent: \"[carbon_cast_on.combat_mode ? "harm" : "help"]\""
log_info += "Identity: \"[carbon_cast_on.mind.name]\""
to_chat(owner, boxed_message(span_notice(jointext(discovered_info, "
"))))
log_combat(owner, cast_on, "mind read (cast intentionally)", null, "info: [english_list(log_info, and_text = ", ")]")
/datum/action/cooldown/spell/pointed/mindread/proc/on_examining(mob/examiner, atom/examining)
SIGNAL_HANDLER
if(!isliving(examining) || examiner == examining)
return
INVOKE_ASYNC(src, PROC_REF(read_mind), examiner, examining)
/datum/action/cooldown/spell/pointed/mindread/proc/read_mind(mob/living/examiner, mob/living/examined)
if(examined.stat >= UNCONSCIOUS || isnull(examined.mind) || (examined.mob_biotypes & MOB_ROBOTIC))
return
var/antimagic = examined.can_block_magic(antimagic_flags, charge_cost = 0)
var/read_text = ""
if(!antimagic)
read_text = examined.get_typing_text()
if(!read_text)
return
sleep(0.5 SECONDS) // small pause so it comes after all examine text and effects
if(QDELETED(examiner))
return
if(antimagic)
to_chat(examiner, boxed_message(span_warning("You attempt to analyze [examined]'s current thoughts, but fail to penetrate [examined.p_their()] mind - It seems you've been foiled.")))
return
var/list/log_info = list()
if(prob(10))
to_chat(examined, span_danger("You feel something foreign enter your mind."))
log_info += "Target alerted!"
to_chat(examiner, boxed_message(span_notice("You analyze [examined]'s current thoughts...
\"[read_text]\"...")))
log_info += "Current thought: \"[read_text]\""
log_combat(examiner, examined, "mind read (triggered on examine)", null, "info: [english_list(log_info, and_text = ", ")]")
/datum/mutation/mindreader/New(datum/mutation/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/mob/effects/genetics.dmi', "antenna", -FRONT_MUTATIONS_LAYER+1))
/datum/mutation/mindreader/get_visual_indicator()
return visual_indicators[type][1]