From f04f695e316918db550293f511040bf01a6107ca Mon Sep 17 00:00:00 2001 From: dumpdavidson Date: Fri, 31 May 2013 16:18:10 +0200 Subject: [PATCH 01/53] Changeling personal hivemind *Creates new living mobtype: voices who are created inside of other living mobs. They communicate only with other voices in the same mob and the mob itself. *Uses the new mobtype for changelings. Lings now have the option to absorb the "memories" of a target. The memories can ghost on their own accord or be forced out by a changeling to prevent spam or verbal abuse. After ghosting the former voice can re-enter the original body (now probably a husk). *Adds an argument to the ghostize verb to have the ghost refer to a new mind. This was used to have voices be able to enter their own body. - Adds the option for a living mob with voices to talk to them using ":v". (This isn't in the current patch for some reason)] *changeling powers can now have multiple verbs tied to them --- code/datums/mind.dm | 3 + code/game/gamemodes/changeling/changeling.dm | 1 + .../gamemodes/changeling/changeling_powers.dm | 52 ++++++++++++-- .../gamemodes/changeling/modularchangling.dm | 57 ++++++++------- code/modules/mob/dead/observer/observer.dm | 6 +- code/modules/mob/living/say.dm | 21 +++++- code/modules/mob/living/voices/say.dm | 22 ++++++ code/modules/mob/living/voices/voices.dm | 69 +++++++++++++++++++ html/changelog.html | 8 +++ tgstation.dme | 39 +++++++++++ 10 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 code/modules/mob/living/voices/say.dm create mode 100644 code/modules/mob/living/voices/voices.dm diff --git a/code/datums/mind.dm b/code/datums/mind.dm index cbd1d07eade..30627ed8f86 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -59,6 +59,9 @@ datum/mind error("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn") if(current) //remove ourself from our old body's mind variable + for(var/mob/living/voices/V in current.contents) + V.transfer(new_character) + if(changeling) current.remove_changeling_powers() current.verbs -= /datum/changeling/proc/EvolutionMenu diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 1a4a2d58886..265994002f8 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -220,6 +220,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" var/geneticpoints = 5 var/purchasedpowers = list() var/mimicing = "" + var/acceptvoices = 1 /datum/changeling/New(var/gender=FEMALE) ..() diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index 99aaebc39fa..98f89105e42 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -3,7 +3,7 @@ if(!mind) return if(!mind.changeling) mind.changeling = new /datum/changeling(gender) if(!iscarbon(src)) return - + verbs += /datum/changeling/proc/EvolutionMenu var/lesser_form = !ishuman(src) @@ -66,7 +66,7 @@ /mob/living/carbon/proc/changeling_absorb_dna() set category = "Changeling" set name = "Absorb DNA" - + var/datum/changeling/changeling = changeling_power(0,0,100) if(!changeling) return @@ -138,8 +138,8 @@ else changeling.purchasedpowers += Tp - if(!Tp.isVerb) - call(Tp.verbpath)() + if(!Tp.isVerb && (Tp.verbpath.len == 1)) + call(Tp.verbpath[1])() else make_changeling() @@ -152,6 +152,10 @@ changeling.absorbedcount++ changeling.isabsorbing = 0 + if (T.mind && (changeling.acceptvoices == 1)) + var/mob/living/voices/P = T.becomevoice(src, "memory") + src << "The [P.fluff_title] of [P.real_name] is now with us. We can use 'say :v' to communicate with it." + P << "You are now a part of the changeling's mind. Type 'Ghost' to escape this existence." T.death(0) T.Drain() return 1 @@ -739,4 +743,42 @@ var/list/datum/dna/hivemind_bank = list() changeling.absorbed_dna |= T.dna feedback_add_details("changeling_powers","ED") - return 1 \ No newline at end of file + return 1 + +//Voices/living memory related verbs + +/mob/proc/changeling_toggle_memoryabsorb() + set category = "Changeling" + set name = "Toggle Memory Absorption" + set desc="Turns absorbing living memories along with DNA on or off." + + var/datum/changeling/changeling = changeling_power() + changeling.acceptvoices = !(changeling.acceptvoices) + if (changeling.acceptvoices==1) + src << "We will now absorb the memories of our victims." + else + src << "We will no longer absorb the memories of our victims." + return 1 + +/mob/proc/changeling_kickvoice() + set category = "Changeling" + set name = "Purge Memory" + set desc="Remove an unwanted voice from your mind." + + var/list/voices = list() + var/list/voices_ref = list() + for(var/mob/living/voices/V in src.contents) + voices += "[V.real_name]" + voices_ref += V + + var/mob/living/voices/S = input("Select the voice you want to remove: ", "Target voice", null) as null|anything in voices + if(!S) return + var/index = voices.Find(S) + var/mob/living/voices/Svoice = voices_ref[index] + Svoice << "Your memories fade from [src]'s mind!" + call(Svoice,/mob/proc/ghostize)(1,Svoice.old_mind) + del(Svoice) + src << "[S] will no longer bother us." + return 1 + + diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm index ec15b284143..9c4e63eed2d 100644 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -7,7 +7,7 @@ var/list/powerinstances var/desc = "Placeholder" var/helptext = "" var/isVerb = 1 // Is it an active power, or passive? - var/verbpath // Path to a verb that contains the effects. + var/list/verbpath = list() // Pathes to verbs that contain the effects. /datum/power/changeling var/allowduringlesserform = 0 @@ -17,13 +17,13 @@ var/list/powerinstances name = "Absorb DNA" desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger." genomecost = 0 - verbpath = /mob/living/carbon/proc/changeling_absorb_dna + verbpath = list(/mob/living/carbon/proc/changeling_absorb_dna) /datum/power/changeling/transform name = "Transform" desc = "We take on the appearance and voice of one we have absorbed." genomecost = 0 - verbpath = /mob/living/carbon/proc/changeling_transform + verbpath = list(/mob/living/carbon/proc/changeling_transform) /datum/power/changeling/fakedeath name = "Regenerative Stasis" @@ -31,7 +31,14 @@ var/list/powerinstances helptext = "Can be used before or after death. Duration varies greatly." genomecost = 0 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_fakedeath + verbpath = list(/mob/living/carbon/proc/changeling_fakedeath) + +/datum/power/changeling/memoryabsorb + name = "Memory Absorption" + desc = "The memories of our victims join our conciousness after syphoning their DNA." + genomecost = 0 + allowduringlesserform = 1 + verbpath = list(/mob/proc/changeling_toggle_memoryabsorb, /mob/proc/changeling_kickvoice) // Hivemind @@ -40,34 +47,34 @@ var/list/powerinstances desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves." helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives." genomecost = 0 - verbpath = /mob/living/carbon/proc/changeling_hiveupload + verbpath = list(/mob/living/carbon/proc/changeling_hiveupload) /datum/power/changeling/hive_download name = "Hive Absorb" desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings." helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective." genomecost = 0 - verbpath = /mob/living/carbon/proc/changeling_hivedownload + verbpath = list(/mob/living/carbon/proc/changeling_hivedownload) /datum/power/changeling/lesser_form name = "Lesser Form" desc = "We debase ourselves and become lesser. We become a monkey." genomecost = 1 - verbpath = /mob/living/carbon/proc/changeling_lesser_form + verbpath = list(/mob/living/carbon/proc/changeling_lesser_form) /datum/power/changeling/deaf_sting name = "Deaf Sting" desc = "We silently sting a human, completely deafening them for a short time." genomecost = 1 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_deaf_sting + verbpath = list(/mob/living/carbon/proc/changeling_deaf_sting) /datum/power/changeling/blind_sting name = "Blind Sting" desc = "We silently sting a human, completely blinding them for a short time." genomecost = 2 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_blind_sting + verbpath = list(/mob/living/carbon/proc/changeling_blind_sting) /datum/power/changeling/silence_sting name = "Silence Sting" @@ -75,14 +82,14 @@ var/list/powerinstances helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." genomecost = 2 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_silence_sting + verbpath = list(/mob/living/carbon/proc/changeling_silence_sting) /datum/power/changeling/mimicvoice name = "Mimic Voice" desc = "We shape our vocal glands to sound like a desired voice." helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this" genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_mimicvoice + verbpath = list(/mob/living/carbon/proc/changeling_mimicvoice) /datum/power/changeling/extractdna name = "Extract DNA" @@ -90,47 +97,47 @@ var/list/powerinstances helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives." genomecost = 4 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_extract_dna_sting + verbpath = list(/mob/living/carbon/proc/changeling_extract_dna_sting) /datum/power/changeling/transformation_sting name = "Transformation Sting" desc = "We silently sting a human, injecting a retrovirus that forces them to transform into another." helptext = "Does not provide a warning to others. The victim will transform much like a changeling would." genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_transformation_sting + verbpath = list(/mob/living/carbon/proc/changeling_transformation_sting) /datum/power/changeling/paralysis_sting name = "Paralysis Sting" desc = "We silently sting a human, paralyzing them for a short time." genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_paralysis_sting + verbpath = list(/mob/living/carbon/proc/changeling_paralysis_sting) /datum/power/changeling/LSDSting name = "Hallucination Sting" desc = "We evolve the ability to sting a target with a powerful hallucinogenic chemical." helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_lsdsting + verbpath = list(/mob/living/carbon/proc/changeling_lsdsting) /datum/power/changeling/DeathSting name = "Death Sting" desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured." genomecost = 10 - verbpath = /mob/living/carbon/proc/changeling_DEATHsting + verbpath = list(/mob/living/carbon/proc/changeling_DEATHsting) /datum/power/changeling/boost_range name = "Boost Range" desc = "We evolve the ability to shoot our stingers at humans, with some preperation." genomecost = 2 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_boost_range + verbpath = list(/mob/living/carbon/proc/changeling_boost_range) /datum/power/changeling/Epinephrine name = "Epinephrine sacs" desc = "We evolve additional sacs of adrenaline throughout our body." helptext = "Gives the ability to instantly recover from stuns. High chemical cost." genomecost = 4 - verbpath = /mob/living/carbon/proc/changeling_unstun + verbpath = list(/mob/living/carbon/proc/changeling_unstun) /datum/power/changeling/ChemicalSynth name = "Rapid Chemical-Synthesis" @@ -138,7 +145,7 @@ var/list/powerinstances helptext = "Doubles the rate at which we naturally recharge chemicals." genomecost = 4 isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical + verbpath= list(/mob/proc/changeling_fastchemical) /* /datum/power/changeling/AdvChemicalSynth name = "Advanced Chemical-Synthesis" @@ -146,7 +153,7 @@ var/list/powerinstances helptext = "Doubles the rate at which we naturally recharge chemicals." genomecost = 8 isVerb = 0 - verbpath = /mob/living/carbon/proc/changeling_fastchemical + verbpath += /mob/living/carbon/proc/changeling_fastchemical */ /datum/power/changeling/EngorgedGlands name = "Engorged Chemical Glands" @@ -154,7 +161,7 @@ var/list/powerinstances helptext = "Allows us to store an extra 25 units of chemicals." genomecost = 4 isVerb = 0 - verbpath = /mob/proc/changeling_engorgedglands + verbpath = list(/mob/proc/changeling_engorgedglands) /datum/power/changeling/DigitalCamoflague name = "Digital Camoflauge" @@ -162,14 +169,14 @@ var/list/powerinstances helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this." genomecost = 3 allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_digitalcamo + verbpath = list(/mob/living/carbon/proc/changeling_digitalcamo) /datum/power/changeling/rapidregeneration name = "Rapid Regeneration" desc = "We evolve the ability to rapidly regenerate, negating the need for stasis." helptext = "Heals a moderate amount of damage every tick." genomecost = 8 - verbpath = /mob/living/carbon/proc/changeling_rapidregen + verbpath = list(/mob/living/carbon/proc/changeling_rapidregen) @@ -486,8 +493,8 @@ var/list/powerinstances purchasedpowers += Thepower - if(!Thepower.isVerb && Thepower.verbpath) - call(C, Thepower.verbpath)() + if(!Thepower.isVerb && (Thepower.verbpath.len == 1)) + call(C, Thepower.verbpath[1])() else if(remake_verbs) C.make_changeling() diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 09b917bd21f..baacebc76e2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -59,9 +59,11 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body Works together with spawning an observer, noted above. */ -/mob/proc/ghostize(var/can_reenter_corpse = 1) +/mob/proc/ghostize(var/can_reenter_corpse = 1, datum/mind/newmind = null) if(key) - var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc. + var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc + if (newmind) + ghost.mind = newmind ghost.can_reenter_corpse = can_reenter_corpse ghost.key = key return ghost diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 2eda94c37f1..155bb1eb648 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -16,6 +16,7 @@ var/list/department_radio_keys = list( ":u" = "Supply", "#u" = "Supply", ".u" = "Supply", ":v" = "Service", "#v" = "Service", ".v" = "Service", ":g" = "changeling", "#g" = "changeling", ".g" = "changeling", + ":v" = "voices", "#v" = "voices", ".v" = "voices", ":R" = "right hand", "#R" = "right hand", ".R" = "right hand", ":L" = "left hand", "#L" = "left hand", ".L" = "left hand", @@ -33,6 +34,7 @@ var/list/department_radio_keys = list( ":U" = "Supply", "#U" = "Supply", ".U" = "Supply", ":V" = "Service", "#V" = "Service", ".V" = "Service", ":G" = "changeling", "#G" = "changeling", ".G" = "changeling", + ":V" = "voices", "#V" = "voices", ".V" = "voices", //kinda localization -- rastaf0 //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. @@ -51,6 +53,7 @@ var/list/department_radio_keys = list( ":å" = "Syndicate", "#å" = "Syndicate", ".å" = "Syndicate", ":é" = "Supply", "#é" = "Supply", ".é" = "Supply", ":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling" + //":v" = "voices", "#v" = "voices", ".v" = "voices", Needs to be added still ) /mob/living/proc/binarycheck() @@ -132,7 +135,7 @@ var/list/department_radio_keys = list( //world << "channel_prefix=[channel_prefix]; message_mode=[message_mode]" if (message_mode) message = trim(copytext(message, 3)) - if (!(ishuman(src) || istype(src, /mob/living/simple_animal/parrot) || isrobot(src) && (message_mode=="department" || (message_mode in radiochannels)))) + if (!(ishuman(src) || (message_mode=="changeling") || (message_mode=="voices") || istype(src, /mob/living/simple_animal/parrot) || isrobot(src) && (message_mode=="department" || (message_mode in radiochannels)))) message_mode = null //only humans can use headsets // Check changed so that parrots can use headsets. Other simple animals do not have ears and will cause runtimes. // And borgs -Sieve @@ -250,6 +253,22 @@ var/list/department_radio_keys = list( if((Changeling.mind && Changeling.mind.changeling) || istype(Changeling, /mob/dead/observer)) Changeling << "[mind.changeling.changelingID]: [message]" return + + if("voices") + var/saidsomething = 0 + var/formated = "[src.real_name] thinks: [message]" + for(var/mob/living/voices/V in src.contents) // talk to the voices + V << formated + saidsomething = 1 + if (saidsomething) + src << formated // talk to yourself + for(var/mob/M in mob_list) // talk to the ghosts + if (istype(M, /mob/dead/observer)) + M << formated + return + else + src << "There are no voices to talk to." + return ////SPECIAL HEADSETS START else //world << "SPECIAL HEADSETS" diff --git a/code/modules/mob/living/voices/say.dm b/code/modules/mob/living/voices/say.dm new file mode 100644 index 00000000000..f0af9753c4d --- /dev/null +++ b/code/modules/mob/living/voices/say.dm @@ -0,0 +1,22 @@ +/mob/living/voices/say_understands(var/other) + if (!istype(other, /mob/living/voices/)) + return call(src.current_host,/mob/proc/say_understands)(other) // you can understand what you host can, you're sharing a brain + else + return 1 // A voice having multiple voices? let it understand anything + +/mob/living/voices/say(var/message) + message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + var/utitle = capitalize(src.fluff_title) + if (!message) + return + + log_say("Voice/[src.key] inside [src.current_host]: [message]") + var/tdisplay = "[utitle] of [src.real_name]: [message]" + + for(var/mob/M in mob_list) //speak to your host, and dead guys + if ( (M==src.current_host) || (istype(M, /mob/dead/observer)) ) + M << tdisplay + + for (var/mob/living/voices/P in src.current_host) // also speak to all voices in your current host + P << tdisplay + return \ No newline at end of file diff --git a/code/modules/mob/living/voices/voices.dm b/code/modules/mob/living/voices/voices.dm new file mode 100644 index 00000000000..8c304b0b452 --- /dev/null +++ b/code/modules/mob/living/voices/voices.dm @@ -0,0 +1,69 @@ +/mob/living/voices + name = "voice" + desc = "The voice of a deceased person." //should not be needed + layer = 4 + density = 0 + canmove = 0 + blinded = 0 + anchored = 1 + see_in_dark = 0 + mind = null + + var/fluff_title = "voice" //what do you call these things in your specific context (e.g. for changelings: memory) + var/current_host = null + var/old_mind = null + //var/cantalk = 1 //unused right now, intended for a mute verb + +/mob/living/voices/New(mob/body, mob/host, title) + if (title) + fluff_title = title + stat = DEAD + attack_log = body.attack_log //preserve attack log + gender = body.gender + loc = host //new voices go into the host + for(var/mob/living/voices/V in body.contents) //as do voices that belonged to him (e.g. ling absorbing a ling) + V.transfer(host) + if (!mind) + name = body.name + old_mind = body.mind + name = body.mind.name + real_name = name + current_host = host + ..() + +/mob/proc/becomevoice(mob/host, title) + var/mob/living/voices/NP = new(src, host, title) + if(key) + NP.key = key + return NP + +/mob/living/voices/proc/transfer(mob/newhost) + if (newhost && !istype(newhost, /mob/living/voices) ) //don't allow voices to have voices + current_host = newhost + loc = current_host + if (client) + client.eye = current_host + return 1 + else + return 0 + +/mob/living/voices/Del() + ghostize(1, src.old_mind) //they can re-enter their original body + src.current_host << "The [src.fluff_title] of [src.real_name] fades away." // tell the host he ghosted + ..() + +/mob/living/voices/ghost() //a way for a voice to become a ghost + set category = "OOC" + set name = "Ghost" + set desc = "Enter the land of the dead." + + del(src) + return + +/mob/living/voices/add_memory() + set hidden = 1 + src << "\red Your mind is no longer your own!" + return + +/mob/dead/observer/can_use_hands() return 0 +/mob/dead/observer/is_active() return 0 \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 51fe20d5fd8..461cbceac4e 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -52,6 +52,14 @@ should be listed in the changelog upon commit tho. Thanks. -->
+

31 May 2013

+

Dumpdavidson updated:

+ +
+ +

14 May 2013

Ikarrus updated: