diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index bb288fc7d48..6db47b0c09f 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -209,6 +209,13 @@ A.point() return +/mob/living/carbon/MiddleClickOn(var/atom/A) + if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src)) + next_click = world.time + 5 + mind.changeling.chosen_sting.try_to_sting(src, A) + else + A.point() + // In case of use break glass /* /atom/proc/MiddleClick(var/mob/M as mob) @@ -251,6 +258,13 @@ A.AltClick(src) return +/mob/living/carbon/AltClickOn(var/atom/A) + if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src)) + next_click = world.time + 5 + mind.changeling.chosen_sting.try_to_sting(src, A) + else + ..() + /atom/proc/AltClick(var/mob/user) var/turf/T = get_turf(src) if(T && user.TurfAdjacent(T)) @@ -273,16 +287,16 @@ return /atom/proc/CtrlShiftClick(var/mob/user) - return + return /mob/proc/AltShiftClickOn(var/atom/A) A.AltShiftClick(src) return /atom/proc/AltShiftClick(var/mob/user) - return - - + return + + /* Misc helpers diff --git a/code/datums/mind.dm b/code/datums/mind.dm index d03909fefbe..3ab2bdb0ca8 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -70,11 +70,6 @@ datum/mind if(!istype(new_character)) world.log << "## DEBUG: 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 - if(changeling) - current.remove_changeling_powers() - current.verbs -= /datum/changeling/proc/EvolutionMenu - if(vampire) - current.remove_vampire_powers() current.mind = null if(new_character.mind) //remove any mind currently in our new body's mind variable @@ -85,10 +80,6 @@ datum/mind current = new_character //link ourself to our new body new_character.mind = src //and link our new body to ourself - if(changeling) - new_character.make_changeling() - if(vampire) - new_character.make_vampire() if(active) new_character.key = key //now transfer the key to link the client to our new body @@ -475,7 +466,7 @@ datum/mind if(!def_value)//If it's a custom objective, it will be an empty string. def_value = "custom" - var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "speciesist", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "custom") + var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "speciesist", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "identity theft", "custom") if (!new_obj_type) return var/datum/objective/new_objective = null @@ -588,6 +579,11 @@ datum/mind new_objective.owner = src new_objective.target_amount = target_number + if("identity theft") + new_objective = new /datum/objective/escape/escape_with_identity + new_objective.owner = src + new_objective.find_target() + if ("custom") var/expl = copytext(sanitize(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null),1,MAX_MESSAGE_LEN) if (!expl) return @@ -843,7 +839,6 @@ datum/mind ticker.mode.changelings -= src special_role = null current.remove_changeling_powers() - current.verbs -= /datum/changeling/proc/EvolutionMenu if(changeling) del(changeling) current << "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!" log_admin("[key_name_admin(usr)] has de-changeling'ed [current].") diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index d4b1a0d44a6..e028702a44e 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -163,7 +163,7 @@ var/global/list/bad_blocks[0] // Set a DNA UI block's raw value. /datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0) if (block<=0) return - ASSERT(value>=0) + ASSERT(value>0) ASSERT(value<=4095) UI[block]=value dirtyUI=1 @@ -178,7 +178,10 @@ var/global/list/bad_blocks[0] // Set a DNA UI block's value, given a value and a max possible value. // Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list) /datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) - if (block<=0) return + if (block<=0) + return + if(value == 0) + value = 1 ASSERT(maxvalue<=4095) var/range = (4095 / maxvalue) if(value) diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 27bae141374..971fb7f5706 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -90,31 +90,53 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" var/datum/objective/absorb/absorb_objective = new absorb_objective.owner = changeling - absorb_objective.gen_amount_goal(2, 3) + absorb_objective.gen_amount_goal(6, 8) changeling.objectives += absorb_objective - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = changeling - kill_objective.find_target() - changeling.objectives += kill_objective + if(prob(60)) + var/datum/objective/steal/steal_objective = new + steal_objective.owner = changeling + steal_objective.find_target() + changeling.objectives += steal_objective + else + var/datum/objective/debrain/debrain_objective = new + debrain_objective.owner = changeling + debrain_objective.find_target() + changeling.objectives += debrain_objective - var/datum/objective/steal/steal_objective = new - steal_objective.owner = changeling - steal_objective.find_target() - changeling.objectives += steal_objective + var/list/active_ais = active_ais() + if(active_ais.len && prob(100/num_players())) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = changeling + destroy_objective.find_target() + changeling.objectives += destroy_objective + else + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = changeling + kill_objective.find_target() + changeling.objectives += kill_objective + if (!(locate(/datum/objective/escape) in changeling.objectives)) + var/datum/objective/escape/escape_with_identity/identity_theft = new + identity_theft.owner = changeling + identity_theft.target = kill_objective.target + if(identity_theft.target && identity_theft.target.current) + var/target_real_name = identity_theft.target.current.real_name + identity_theft.explanation_text = "Escape on the shuttle or an escape pod with the identity of [target_real_name], the [identity_theft.target.assigned_role] while wearing their identification card." + else + identity_theft.explanation_text = "Free objective" + changeling.objectives += identity_theft - switch(rand(1,100)) - if(1 to 80) - if (!(locate(/datum/objective/escape) in changeling.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = changeling - changeling.objectives += escape_objective + if (!(locate(/datum/objective/escape) in changeling.objectives)) + if(prob(70)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = changeling + changeling.objectives += escape_objective else - if (!(locate(/datum/objective/survive) in changeling.objectives)) - var/datum/objective/survive/survive_objective = new - survive_objective.owner = changeling - changeling.objectives += survive_objective + var/datum/objective/escape/escape_with_identity/identity_theft = new + identity_theft.owner = changeling + identity_theft.find_target() + changeling.objectives += identity_theft return /datum/game_mode/proc/greet_changeling(var/datum/mind/changeling, var/you_are=1) @@ -162,7 +184,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/game_mode/proc/auto_declare_completion_changeling() if(changelings.len) - var/text = "The changelings were:" + var/text = "The changelings were:" for(var/datum/mind/changeling in changelings) var/changelingwin = 1 @@ -181,7 +203,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed. text += "
Changeling ID: [changeling.changeling.changelingID]." - text += "
Genomes Absorbed: [changeling.changeling.absorbedcount]" + text += "
Genomes Extracted: [changeling.changeling.absorbedcount]" if(changeling.objectives.len) var/count = 1 @@ -209,19 +231,25 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) var/list/absorbed_dna = list() - var/list/absorbed_species = list() var/list/absorbed_languages = list() - var/absorbedcount = 0 + var/list/protected_dna = list() //DNA that is not lost when capacity is otherwise full. + var/dna_max = 4 //How many extra DNA strands the changeling can store for transformation. + var/absorbedcount = 1 //Would require at least 1 sample to take on the form of a human var/chem_charges = 20 var/chem_recharge_rate = 0.5 + var/chem_recharge_slowdown = 0 var/chem_storage = 50 - var/sting_range = 1 + var/sting_range = 2 var/changelingID = "Changeling" var/geneticdamage = 0 var/isabsorbing = 0 - var/geneticpoints = 5 + var/geneticpoints = 10 var/purchasedpowers = list() var/mimicing = "" + var/canrespec = 0 + var/changeling_speak = 0 + var/datum/dna/chosen_dna + var/obj/effect/proc_holder/changeling/sting/chosen_sting /datum/changeling/New(var/gender=FEMALE) ..() @@ -234,16 +262,61 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" changelingID = "[honorific] [changelingID]" else changelingID = "[honorific] [rand(1,999)]" + absorbed_dna.len = dna_max /datum/changeling/proc/regenerate() - chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage) + chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), chem_storage) geneticdamage = max(0, geneticdamage-1) /datum/changeling/proc/GetDNA(var/dna_owner) - var/datum/dna/chosen_dna - for(var/datum/dna/DNA in absorbed_dna) + for(var/datum/dna/DNA in (absorbed_dna + protected_dna)) if(dna_owner == DNA.real_name) - chosen_dna = DNA - break - return chosen_dna + return DNA + +/datum/changeling/proc/has_dna(var/datum/dna/tDNA) + for(var/datum/dna/D in (absorbed_dna + protected_dna)) + if(tDNA.unique_enzymes == D.unique_enzymes && tDNA.uni_identity == D.uni_identity && tDNA.species == D.species) + return 1 + return 0 + +/datum/changeling/proc/can_absorb_dna(var/mob/living/carbon/user, var/mob/living/carbon/target) + if(absorbed_dna[1] == user.dna)//If our current DNA is the stalest, we gotta ditch it. + user << "We have reached our capacity to store genetic information! We must transform before absorbing more." + return + + if(!target || !target.dna) + user << "This creature does not have any DNA." + return + + var/mob/living/carbon/human/T = target + if(!istype(T)) + user << "[T] is not compatible with our biology." + return + + if((M_NOCLONE || SKELETON || M_HUSK) in T.mutations) + user << "DNA of [target] is ruined beyond usability!" + return + + if(T.species.flags & IS_SYNTHETIC) + user << "This creature does not have DNA!" + return + + if(T.species.flags & NO_SCAN) + user << "We do not know how to parse this creature's DNA!" + return + + if(has_dna(target.dna)) + user << "We already have this DNA in storage!" + + return 1 + +//More snowflake stuff, but for languages. +/datum/changeling/proc/changeling_update_languages(var/updated_languages, var/mob/living/carbon/user) + if(!istype(user) || !user) + return + user.languages = list() + for(var/language in updated_languages) + user.languages += language + + return \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm new file mode 100644 index 00000000000..36df179ae32 --- /dev/null +++ b/code/game/gamemodes/changeling/changeling_power.dm @@ -0,0 +1,79 @@ +/* + * Don't use the apostrophe in name or desc. Causes script errors. + * TODO: combine atleast some of the functionality with /proc_holder/spell + */ + +/obj/effect/proc_holder/changeling + panel = "Changeling" + name = "Prototype Sting" + desc = "" // Fluff + var/helptext = "" // Details + var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands) + var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased + var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1 + var/req_human = 0 //if you need to be human to use this ability + var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD + var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss. + var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet. + +/obj/effect/proc_holder/changeling/proc/on_purchase(var/mob/user) + return + +/obj/effect/proc_holder/changeling/Click() + var/mob/user = usr + if(!user || !user.mind || !user.mind.changeling) + return + try_to_sting(user) + +/obj/effect/proc_holder/changeling/proc/try_to_sting(var/mob/user, var/mob/target) + if(!user.mind || !user.mind.changeling) + return + if(!can_sting(user, target)) + return + var/datum/changeling/c = user.mind.changeling + if(sting_action(user, target)) + sting_feedback(user, target) + take_chemical_cost(c) + +/obj/effect/proc_holder/changeling/proc/sting_action(var/mob/user, var/mob/target) + return 0 + +/obj/effect/proc_holder/changeling/proc/sting_feedback(var/mob/user, var/mob/target) + return 0 + +/obj/effect/proc_holder/changeling/proc/take_chemical_cost(var/datum/changeling/changeling) + changeling.chem_charges -= chemical_cost + changeling.geneticdamage += genetic_damage + +//Fairly important to remember to return 1 on success >.< +/obj/effect/proc_holder/changeling/proc/can_sting(var/mob/user, var/mob/target) + if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards + return 0 + if(req_human && !ishuman(user)) + user << "We cannot do that in this form!" + return 0 + var/datum/changeling/c = user.mind.changeling + if(c.chem_chargesWe require at least [chemical_cost] unit\s of chemicals to do that!" + return 0 + if(c.absorbedcountWe require at least [req_dna] sample\s of compatible DNA." + return 0 + if(req_stat < user.stat) + user << "We are incapacitated." + return 0 + if((user.status_flags & FAKEDEATH) && name!="Regenerate") + user << "We are incapacitated." + return 0 + if(c.geneticdamage > max_genetic_damage) + user << "Our genomes are still reassembling. We need time to recover first." + return 0 + return 1 + +//used in /mob/Stat() +/obj/effect/proc_holder/changeling/proc/can_be_used_by(var/mob/user) + if(!ishuman(user) && !ismonkey(user)) + return 0 + if(req_human && !ishuman(user)) + return 0 + return 1 diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm deleted file mode 100644 index c6df778144d..00000000000 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ /dev/null @@ -1,944 +0,0 @@ -//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human -/mob/proc/make_changeling() - - if(!mind) return - if(!mind.changeling) mind.changeling = new /datum/changeling(gender) - if(!ishuman(src) && !ismonkey(src)) return - verbs += /datum/changeling/proc/EvolutionMenu - - var/lesser_form = !ishuman(src) - - if(!powerinstances.len) - for(var/P in powers) - powerinstances += new P() - - // Code to auto-purchase free powers. - for(var/datum/power/changeling/P in powerinstances) - if(!P.genomecost) // Is it free? - if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already? - mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this. - - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) - if(P.isVerb) - if(lesser_form && !P.allowduringlesserform) continue - if(!(P in src.verbs)) - src.verbs += P.verbpath - - mind.changeling.absorbed_dna |= dna - - var/mob/living/carbon/human/H = src - if(istype(H)) - mind.changeling.absorbed_species += H.species.name - - for(var/language in languages) - if(!(language in mind.changeling.absorbed_languages)) - mind.changeling.absorbed_languages += language - - return 1 - -//removes our changeling verbs -/mob/proc/remove_changeling_powers() - if(!mind || !mind.changeling) return - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) - if(P.isVerb) - verbs -= P.verbpath - - -//Helper proc. Does all the checks and stuff for us to avoid copypasta -/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0) - - if(!src.mind) return - if(!iscarbon(src)) return - - var/datum/changeling/changeling = src.mind.changeling - if(!changeling) - world.log << "[src] has the changeling_transform() verb but is not a changeling." - return - - if(src.stat > max_stat) - src << "We are incapacitated." - return - - if(changeling.absorbed_dna.len < required_dna) - src << "We require at least [required_dna] samples of compatible DNA." - return - - if(changeling.chem_charges < required_chems) - src << "We require at least [required_chems] units of chemicals to do that!" - return - - if(changeling.geneticdamage > max_genetic_damage) - src << "Our geneomes are still reassembling. We need time to recover first." - return - - return changeling - - -//Used to dump the languages from the changeling datum into the actual mob. -/mob/proc/changeling_update_languages(var/updated_languages) - - languages = list() - for(var/language in updated_languages) - languages += language - - return - -//Used to switch species based on the changeling datum. -/mob/proc/changeling_change_species() - - set category = "Changeling" - set name = "Change Species (5)" - - var/mob/living/carbon/human/H = src - if(!istype(H)) - src << "We may only use this power while in humanoid form." - return - - var/datum/changeling/changeling = changeling_power(5,1,0) - if(!changeling) return - - if(changeling.absorbed_species.len < 2) - src << "We do not know of any other species genomes to use." - return - - var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species - if(!S) return - - domutcheck(src, null) - - changeling.chem_charges -= 5 - changeling.geneticdamage = 30 - - src.visible_message("[src] transforms!") - - src.verbs -= /mob/proc/changeling_change_species - H.set_species(S,null,1) //Until someone moves body colour into DNA, they're going to have to use the default. - - spawn(10) - src.verbs += /mob/proc/changeling_change_species - src.regenerate_icons() - - changeling_update_languages(changeling.absorbed_languages) - feedback_add_details("changeling_powers","TR") - - return 1 - -//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. -//Doesn't cost anything as it's the most basic ability. -/mob/proc/changeling_absorb_dna() - set category = "Changeling" - set name = "Absorb DNA" - - var/datum/changeling/changeling = changeling_power(0,0,100) - if(!changeling) return - - var/obj/item/weapon/grab/G = src.get_active_hand() - if(!istype(G)) - src << "We must be grabbing a creature in our active hand to absorb them." - return - - var/mob/living/carbon/human/T = G.affecting - if(!istype(T)) - src << "[T] is not compatible with our biology." - return - - if(T.species.flags & NO_SCAN) - src << "We do not know how to parse this creature's DNA!" - return - - if((M_NOCLONE || SKELETON) in T.mutations) - src << "This creature's DNA is ruined beyond useability!" - return - - if(!G.state == GRAB_KILL) - src << "We must have a tighter grip to absorb this creature." - return - - if(changeling.isabsorbing) - src << "We are already absorbing!" - return - - changeling.isabsorbing = 1 - for(var/stage = 1, stage<=3, stage++) - switch(stage) - if(1) - src << "This creature is compatible. We must hold still..." - if(2) - src << "We extend a proboscis." - src.visible_message("[src] extends a proboscis!") - if(3) - src << "We stab [T] with the proboscis." - src.visible_message("[src] stabs [T] with the proboscis!") - T << "You feel a sharp stabbing pain!" - var/datum/organ/external/affecting = T.get_organ(src.zone_sel.selecting) - if(affecting.take_damage(39,0,1,0,"large organic needle")) - T:UpdateDamageIcon() - continue - - feedback_add_details("changeling_powers","A[stage]") - if(!do_mob(src, T, 150)) - src << "Our absorption of [T] has been interrupted!" - changeling.isabsorbing = 0 - return - - src << "We have absorbed [T]!" - src.visible_message("[src] sucks the fluids from [T]!") - T << "You have been absorbed by the changeling!" - - T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. - changeling.absorbed_dna |= T.dna - if(src.nutrition < 400) src.nutrition = min((src.nutrition + T.nutrition), 400) - - changeling.chem_charges += 10 - changeling.geneticpoints += 2 - - //Steal all of their languages! - for(var/language in T.languages) - if(!(language in changeling.absorbed_languages)) - changeling.absorbed_languages += language - - changeling_update_languages(changeling.absorbed_languages) - - //Steal their species! - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name - - if(T.mind && T.mind.changeling) - if(T.mind.changeling.absorbed_dna) - for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot - if(dna_data in changeling.absorbed_dna) - continue - changeling.absorbed_dna += dna_data - changeling.absorbedcount++ - T.mind.changeling.absorbed_dna.len = 1 - - if(T.mind.changeling.purchasedpowers) - for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers) - if(Tp in changeling.purchasedpowers) - continue - else - changeling.purchasedpowers += Tp - - if(!Tp.isVerb) - call(Tp.verbpath)() - else - changeling.purchasedpowers += Tp - - if(!Tp.isVerb) - call(Tp.verbpath)() - else - src.make_changeling() - - changeling.chem_charges += T.mind.changeling.chem_charges - changeling.geneticpoints += T.mind.changeling.geneticpoints - T.mind.changeling.chem_charges = 0 - T.mind.changeling.geneticpoints = 0 - T.mind.changeling.absorbedcount = 0 - - changeling.absorbedcount++ - changeling.isabsorbing = 0 - - T.death(0) - T.Drain() - return 1 - - -//Change our DNA to that of somebody we've absorbed. -/mob/proc/changeling_transform() - set category = "Changeling" - set name = "Transform (5)" - - var/datum/changeling/changeling = changeling_power(5,1,0) - if(!changeling) return - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" - - var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names - if(!S) return - - var/datum/dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - changeling.chem_charges -= 5 - src.visible_message("[src] transforms!") - changeling.geneticdamage = 30 - src.dna = chosen_dna.Clone() - src.real_name = chosen_dna.real_name - src.flavor_text = "" - if(ishuman(src)) - var/mob/living/carbon/human/H = src - H.set_species() - src.UpdateAppearance() - domutcheck(src, null) - - src.verbs -= /mob/proc/changeling_transform - spawn(10) src.verbs += /mob/proc/changeling_transform - - feedback_add_details("changeling_powers","TR") - return 1 - - -//Transform into a monkey. -/mob/proc/changeling_lesser_form() - set category = "Changeling" - set name = "Lesser Form (1)" - - var/datum/changeling/changeling = changeling_power(1,0,0) - if(!changeling) return - - if(src.has_brain_worms()) - src << "We cannot perform this ability at the present time!" - return - - var/mob/living/carbon/C = src - changeling.chem_charges-- - C.remove_changeling_powers() - C.visible_message("[C] transforms!") - changeling.geneticdamage = 30 - C << "Our genes cry out!" - - //TODO replace with monkeyize proc - var/list/implants = list() //Try to preserve implants. - for(var/obj/item/weapon/implant/W in C) - implants += W - - C.monkeyizing = 1 - C.canmove = 0 - C.icon = null - C.overlays.Cut() - C.invisibility = 101 - - var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("h2monkey", animation) - sleep(48) - del(animation) - - var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) - O.dna = C.dna.Clone() - C.dna = null - - for(var/obj/item/W in C) - C.drop_from_inventory(W) - for(var/obj/T in C) - del(T) - - O.loc = C.loc - O.name = "monkey ([copytext(md5(C.real_name), 2, 6)])" - O.setToxLoss(C.getToxLoss()) - O.adjustBruteLoss(C.getBruteLoss()) - O.setOxyLoss(C.getOxyLoss()) - O.adjustFireLoss(C.getFireLoss()) - O.stat = C.stat - O.a_intent = "harm" - for(var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - - C.mind.transfer_to(O) - - O.make_changeling(1) - O.verbs += /mob/proc/changeling_lesser_transform - O.changeling_update_languages(changeling.absorbed_languages) - - feedback_add_details("changeling_powers","LF") - del(C) - return 1 - - -//Transform into a human -/mob/proc/changeling_lesser_transform() - set category = "Changeling" - set name = "Transform (1)" - - var/datum/changeling/changeling = changeling_power(1,1,0) - if(!changeling) return - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" - - var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names - if(!S) return - - var/datum/dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - var/mob/living/carbon/C = src - - changeling.chem_charges-- - C.remove_changeling_powers() - C.visible_message("[C] transforms!") - C.dna = chosen_dna.Clone() - - var/list/implants = list() - for (var/obj/item/weapon/implant/I in C) //Still preserving implants - implants += I - - C.monkeyizing = 1 - C.canmove = 0 - C.icon = null - C.overlays.Cut() - C.invisibility = 101 - var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - flick("monkey2h", animation) - sleep(48) - del(animation) - - for(var/obj/item/W in src) - C.u_equip(W) - if (C.client) - C.client.screen -= W - if (W) - W.loc = C.loc - W.dropped(C) - W.layer = initial(W.layer) - - var/mob/living/carbon/human/O = new /mob/living/carbon/human( src, delay_ready_dna=1 ) - if (C.dna.GetUIState(DNA_UI_GENDER)) - O.gender = FEMALE - else - O.gender = MALE - O.dna = C.dna.Clone() - C.dna = null - O.real_name = chosen_dna.real_name - O.set_species() - for(var/obj/T in C) - del(T) - - O.loc = C.loc - - O.UpdateAppearance() - domutcheck(O, null) - O.setToxLoss(C.getToxLoss()) - O.adjustBruteLoss(C.getBruteLoss()) - O.setOxyLoss(C.getOxyLoss()) - O.adjustFireLoss(C.getFireLoss()) - O.stat = C.stat - for (var/obj/item/weapon/implant/I in implants) - I.loc = O - I.implanted = O - - C.mind.transfer_to(O) - O.make_changeling() - O.changeling_update_languages(changeling.absorbed_languages) - - feedback_add_details("changeling_powers","LFT") - del(C) - return 1 - - -//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. -/* -/mob/verb/honk() - set name = "OH HOLY FUCK" - set category = "Debug" - var/yes = 0 - if(src in mob_list) - yes = 1 - else - var/mob/M = locate(src) in mob_list - if(M == src) - yes = 1 - usr << "[yes ? "\blue" : "\red"] You are [yes ? "" : "not "]in the mob list" -*/ -/mob/proc/changeling_returntolife() - set category = "Changeling" - set name = "Return To Life (20)" - var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) - if(!changeling) return - - var/mob/living/carbon/C = src - if(changeling_power(20,1,100,DEAD)) - changeling.chem_charges -= 20 - dead_mob_list -= C - living_mob_list |= C - C.stat = CONSCIOUS - C.tod = null - C.setToxLoss(0) - C.setOxyLoss(0) - C.setCloneLoss(0) - C.setBrainLoss(0) - C.SetParalysis(0) - C.SetStunned(0) - C.SetWeakened(0) - C.radiation = 0 - C.heal_overall_damage(C.getBruteLoss(), C.getFireLoss()) - C.reagents.clear_reagents() - C.germ_level = 0 - C.next_pain_time = 0 - C.traumatic_shock = 0 - if(ishuman(C)) - var/mob/living/carbon/human/H = C - H.vessel.reagent_list = list() - H.vessel.add_reagent("blood",560) - H.shock_stage = 0 - spawn(1) - H.fixblood() - for(var/organ_name in H.organs_by_name) - var/datum/organ/external/O = H.organs_by_name[organ_name] - for(var/obj/item/weapon/shard/shrapnel/s in O.implants) - if(istype(s)) - O.implants -= s - H.contents -= s - del(s) - O.amputated = 0 - O.brute_dam = 0 - O.burn_dam = 0 - O.damage_state = "00" - O.germ_level = 0 - O.hidden = null - O.number_wounds = 0 - O.open = 0 - O.perma_injury = 0 - O.stage = 0 - O.status = 0 - O.trace_chemicals = list() - O.wounds = list() - O.wound_update_accuracy = 1 - for(var/n in H.internal_organs_by_name) - var/datum/organ/internal/IO = H.internal_organs_by_name[n] - IO.damage = 0 - IO.trace_chemicals = list() - H.updatehealth() - C << "We have regenerated." - C.visible_message("[src] appears to wake from the dead, having healed all wounds.") - C.status_flags &= ~(FAKEDEATH) - C.update_canmove() - C.make_changeling() - src.verbs -= /mob/proc/changeling_returntolife - feedback_add_details("changeling_powers","RJ") - -/mob/proc/changeling_fakedeath() - set category = "Changeling" - set name = "Regenerative Stasis (20)" - - var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) - if(!changeling) return - - var/mob/living/carbon/C = src - if(!C.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death - return - C << "We will attempt to regenerate our form." - - C.status_flags |= FAKEDEATH //play dead - C.update_canmove() - C.remove_changeling_powers() - - C.emote("deathgasp") - C.tod = worldtime2text() - - spawn(rand(800,1200)) - src << "We are now ready to regenerate." - src.verbs += /mob/proc/changeling_returntolife - feedback_add_details("changeling_powers","FD") - return 1 - - -//Boosts the range of your next sting attack by 1 -/mob/proc/changeling_boost_range() - set category = "Changeling" - set name = "Ranged Sting (10)" - set desc="Your next sting ability can be used against targets 2 squares away." - - var/datum/changeling/changeling = changeling_power(10,0,100) - if(!changeling) return 0 - changeling.chem_charges -= 10 - src << "Your throat adjusts to launch the sting." - changeling.sting_range = 2 - src.verbs -= /mob/proc/changeling_boost_range - spawn(5) src.verbs += /mob/proc/changeling_boost_range - feedback_add_details("changeling_powers","RS") - return 1 - - -//Recover from stuns. -/mob/proc/changeling_unstun() - set category = "Changeling" - set name = "Epinephrine Sacs (45)" - set desc = "Removes all stuns" - - var/datum/changeling/changeling = changeling_power(45,0,100,UNCONSCIOUS) - if(!changeling) return 0 - changeling.chem_charges -= 45 - - var/mob/living/carbon/human/C = src - C.stat = 0 - C.SetParalysis(0) - C.SetStunned(0) - C.SetWeakened(0) - C.adjustStaminaLoss(-75) - C.reagents.add_reagent("synaptizine", 20) - C.lying = 0 - C.update_canmove() - - src.verbs -= /mob/proc/changeling_unstun - spawn(5) src.verbs += /mob/proc/changeling_unstun - feedback_add_details("changeling_powers","UNS") - return 1 - - -//Speeds up chemical regeneration -/mob/proc/changeling_fastchemical() - src.mind.changeling.chem_recharge_rate *= 2 - return 1 - -//Increases macimum chemical storage -/mob/proc/changeling_engorgedglands() - src.mind.changeling.chem_storage += 25 - return 1 - - -//Prevents AIs tracking you but makes you easily detectable to the human-eye. -/mob/proc/changeling_digitalcamo() - set category = "Changeling" - set name = "Toggle Digital Camoflague" - set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active." - - var/datum/changeling/changeling = changeling_power() - if(!changeling) return 0 - - var/mob/living/carbon/human/C = src - if(C.digitalcamo) C << "We return to normal." - else C << "We distort our form to prevent AI-tracking." - C.digitalcamo = !C.digitalcamo - - spawn(0) - while(C && C.digitalcamo && C.mind && C.mind.changeling) - C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0) - sleep(40) - - src.verbs -= /mob/proc/changeling_digitalcamo - spawn(5) src.verbs += /mob/proc/changeling_digitalcamo - feedback_add_details("changeling_powers","CAM") - return 1 - - -//Starts healing you every second for 10 seconds. Can be used whilst unconscious. -/mob/proc/changeling_rapidregen() - set category = "Changeling" - set name = "Rapid Regeneration (30)" - set desc = "Begins rapidly regenerating. Does not effect stuns or chemicals." - - var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS) - if(!changeling) return 0 - src.mind.changeling.chem_charges -= 30 - - var/mob/living/carbon/human/C = src - if(ishuman(src)) - var/mob/living/carbon/human/H=src - if(H.said_last_words) - H.said_last_words=0 - - spawn(0) - for(var/i = 0, i<10,i++) - if(C) - C.adjustBruteLoss(-10) - C.adjustToxLoss(-10) - C.adjustOxyLoss(-10) - C.adjustFireLoss(-10) - sleep(10) - - src.verbs -= /mob/proc/changeling_rapidregen - spawn(5) src.verbs += /mob/proc/changeling_rapidregen - feedback_add_details("changeling_powers","RR") - return 1 - -// HIVE MIND UPLOAD/DOWNLOAD DNA - -var/list/datum/dna/hivemind_bank = list() - -/mob/proc/changeling_hiveupload() - set category = "Changeling" - set name = "Hive Channel (10)" - set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it." - - var/datum/changeling/changeling = changeling_power(10,1) - if(!changeling) return - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - if(!(DNA in hivemind_bank)) - names += DNA.real_name - - if(names.len <= 0) - src << "The airwaves already have all of our DNA." - return - - var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names - if(!S) return - - var/datum/dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - changeling.chem_charges -= 10 - hivemind_bank += chosen_dna - src << "We channel the DNA of [S] to the air." - feedback_add_details("changeling_powers","HU") - return 1 - -/mob/proc/changeling_hivedownload() - set category = "Changeling" - set name = "Hive Absorb (20)" - set desc = "Allows you to absorb DNA that is being channelled in the airwaves." - - var/datum/changeling/changeling = changeling_power(20,1) - if(!changeling) return - - var/list/names = list() - for(var/datum/dna/DNA in hivemind_bank) - if(!(DNA in changeling.absorbed_dna)) - names[DNA.real_name] = DNA - - if(names.len <= 0) - src << "There's no new DNA to absorb from the air." - return - - var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names - if(!S) return - var/datum/dna/chosen_dna = names[S] - if(!chosen_dna) - return - - changeling.chem_charges -= 20 - changeling.absorbed_dna += chosen_dna - src << "We absorb the DNA of [S] from the air." - feedback_add_details("changeling_powers","HD") - return 1 - -// Fake Voice - -/mob/proc/changeling_mimicvoice() - set category = "Changeling" - set name = "Mimic Voice" - set desc = "Shape our vocal glands to form a voice of someone we choose. We cannot regenerate chemicals when mimicing." - - - var/datum/changeling/changeling = changeling_power() - if(!changeling) return - - if(changeling.mimicing) - changeling.mimicing = "" - src << "We return our vocal glands to their original location." - return - - var/mimic_voice = stripped_input(usr, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN) - if(!mimic_voice) - return - - changeling.mimicing = mimic_voice - - src << "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active." - src << "Use this power again to return to our original voice and reproduce chemicals again." - - feedback_add_details("changeling_powers","MV") - - spawn(0) - while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing) - src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0) - sleep(40) - if(src && src.mind && src.mind.changeling) - src.mind.changeling.mimicing = "" - ////////// - //STINGS// //They get a pretty header because there's just so fucking many of them ;_; - ////////// - -/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1) - if(M.loc == src.loc) return 1 //target and source are in the same thing - if(!isturf(src.loc) || !isturf(M.loc)) return 0 //One is inside, the other is outside something. - if(AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, sting_range)) //If a path exists, good! - return 1 - return 0 - -//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities) -/mob/proc/changeling_sting(var/required_chems=0, var/verb_path) - var/datum/changeling/changeling = changeling_power(required_chems) - if(!changeling) return - - var/list/victims = list() - for(var/mob/living/carbon/C in oview(changeling.sting_range)) - victims += C - var/mob/living/carbon/T = input(src, "Who will we sting?") as null|anything in victims - - if(!T) return - if(!(T in view(changeling.sting_range))) return - if(!sting_can_reach(T, changeling.sting_range)) return - if(!changeling_power(required_chems)) return - - if(ishuman(T)) - var/mob/living/carbon/human/H = T - if(H.species.flags & IS_SYNTHETIC) - src << "This won't work on synthetics." - return - - changeling.chem_charges -= required_chems - changeling.sting_range = 1 - src.verbs -= verb_path - spawn(10) src.verbs += verb_path - - src << "We stealthily sting [T]." - if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting - T << "You feel a tiny prick." - return - - -/mob/proc/changeling_lsdsting() - set category = "Changeling" - set name = "Hallucination Sting (15)" - set desc = "Causes terror in the target." - - var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting) - if(!T) return 0 - spawn(rand(300,600)) - if(T) T.hallucination += 400 - feedback_add_details("changeling_powers","HS") - return 1 - -/mob/proc/changeling_silence_sting() - set category = "Changeling" - set name = "Silence sting (10)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting) - if(!T) return 0 - T.silent += 30 - feedback_add_details("changeling_powers","SS") - return 1 - -/mob/proc/changeling_blind_sting() - set category = "Changeling" - set name = "Blind sting (20)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting) - if(!T) return 0 - T << "Your eyes burn horrificly!" - T.disabilities |= NEARSIGHTED - spawn(300) T.disabilities &= ~NEARSIGHTED - T.eye_blind = 10 - T.eye_blurry = 20 - feedback_add_details("changeling_powers","BS") - return 1 - -/mob/proc/changeling_deaf_sting() - set category = "Changeling" - set name = "Deaf sting (5)" - set desc="Sting target:" - - var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting) - if(!T) return 0 - T << "Your ears pop and begin ringing loudly!" - T.sdisabilities |= DEAF - spawn(300) T.sdisabilities &= ~DEAF - feedback_add_details("changeling_powers","DS") - return 1 - -/mob/proc/changeling_paralysis_sting() - set category = "Changeling" - set name = "Paralysis sting (30)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting) - if(!T) return 0 - T << "Your muscles begin to painfully tighten." - T.Weaken(20) - feedback_add_details("changeling_powers","PS") - return 1 - -/mob/proc/changeling_transformation_sting() - set category = "Changeling" - set name = "Transformation sting (40)" - set desc="Sting target" - - var/datum/changeling/changeling = changeling_power(40) - if(!changeling) return 0 - - - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" - - var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names - if(!S) return - - var/datum/dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting) - if(!T) return 0 - if((M_HUSK in T.mutations) || (!ishuman(T) && !ismonkey(T))) - src << "Our sting appears ineffective against its DNA." - return 0 - T.visible_message("[T] transforms!") - T.dna = chosen_dna.Clone() - T.real_name = chosen_dna.real_name - T.UpdateAppearance() - domutcheck(T, null) - feedback_add_details("changeling_powers","TS") - return 1 - -/mob/proc/changeling_unfat_sting() - set category = "Changeling" - set name = "Unfat sting (5)" - set desc = "Sting target" - - var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting) - if(!T) return 0 - T << "You feel a small prick as stomach churns violently and you become to feel skinnier." - T.overeatduration = 0 - T.nutrition -= 100 - feedback_add_details("changeling_powers","US") - return 1 - -/mob/proc/changeling_DEATHsting() - set category = "Changeling" - set name = "Death Sting (40)" - set desc = "Causes spasms onto death." - - var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting) - if(!T) return 0 - T << "You feel a small prick and your chest becomes tight." - T.silent = 10 - T.Paralyse(10) - T.Jitter(1000) - if(T.reagents) T.reagents.add_reagent("lexorin", 40) - feedback_add_details("changeling_powers","DTHS") - return 1 - -/mob/proc/changeling_extract_dna_sting() - set category = "Changeling" - set name = "Extract DNA Sting (40)" - set desc="Stealthily sting a target to extract their DNA." - - var/datum/changeling/changeling = null - if(src.mind && src.mind.changeling) - changeling = src.mind.changeling - if(!changeling) - return 0 - - var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting) - if(!T) return 0 - if(T.species.flags & NO_SCAN) // Yeah, this needs the same protection, otherwise you can steal DNA from Slime People and then blood overdose when you turn into one. - src << "We do not know how to parse this creature's DNA!" - changeling.chem_charges += 40 - return 0 - - T.dna.real_name = T.real_name - changeling.absorbed_dna |= T.dna - if(T.species && !(T.species.name in changeling.absorbed_species)) - changeling.absorbed_species += T.species.name - - feedback_add_details("changeling_powers","ED") - return 1 diff --git a/code/game/gamemodes/changeling/evolution_menu.dm b/code/game/gamemodes/changeling/evolution_menu.dm new file mode 100644 index 00000000000..370a65d42a0 --- /dev/null +++ b/code/game/gamemodes/changeling/evolution_menu.dm @@ -0,0 +1,404 @@ +var/list/sting_paths +// totally stolen from the new player panel. YAYY + +/obj/effect/proc_holder/changeling/evolution_menu + name = "-Evolution Menu-" //Dashes are so it's listed before all the other abilities. + desc = "Choose our method of subjugation." + dna_cost = 0 + +/obj/effect/proc_holder/changeling/evolution_menu/Click() + if(!usr || !usr.mind || !usr.mind.changeling) + return + var/datum/changeling/changeling = usr.mind.changeling + + if(!sting_paths) + sting_paths = init_subtypes(/obj/effect/proc_holder/changeling) + + var/dat = create_menu(changeling) + usr << browse(dat, "window=powers;size=600x700")//900x480 + + +/obj/effect/proc_holder/changeling/evolution_menu/proc/create_menu(var/datum/changeling/changeling) + var/dat + dat +="Changling Evolution Menu" + + //javascript, the part that does most of the work~ + dat += {" + + + + + + + "} + + //body tag start + onload and onkeypress (onkeyup) javascript event calls + dat += "" + + //title + search bar + dat += {" + + + + + + + + +
+ Changeling Evolution Menu
+ Hover over a power to see more information
+ Current ability choices remaining: [changeling.geneticpoints]
+ By rendering a lifeform to a husk, we gain enough power to alter and adapt our evolutions.
+ (Readapt)
+

+

+ Search: +
+ + "} + + //player table header + dat += {" + + "} + + var/i = 1 + for(var/obj/effect/proc_holder/changeling/cling_power in sting_paths) + + if(cling_power.dna_cost <= 0) //Let's skip the crap we start with. Keeps the evolution menu uncluttered. + continue + + var/ownsthis = changeling.has_sting(cling_power) + + var/color + if(ownsthis) + if(i%2 == 0) + color = "#d8ebd8" + else + color = "#c3dec3" + else + if(i%2 == 0) + color = "#f2f2f2" + else + color = "#e6e6e6" + + + dat += {" + + + + + + "} + + i++ + + + //player table ending + dat += {" +
+ + + Evolve [cling_power][ownsthis ? " - Purchased" : (cling_power.req_dna>changeling.absorbedcount ? " - Requires [cling_power.req_dna] absorptions" : " - Cost: [cling_power.dna_cost]")] + +
+
+
+ + + + "} + return dat + + +/obj/effect/proc_holder/changeling/evolution_menu/Topic(href, href_list) + ..() + if(!(iscarbon(usr) && usr.mind && usr.mind.changeling)) + return + + if(href_list["P"]) + usr.mind.changeling.purchasePower(usr, href_list["P"]) + else if(href_list["readapt"]) + usr.mind.changeling.lingRespec(usr) + var/dat = create_menu(usr.mind.changeling) + usr << browse(dat, "window=powers;size=600x700") +///// + +/datum/changeling/proc/purchasePower(var/mob/living/carbon/user, var/sting_name) + + var/obj/effect/proc_holder/changeling/thepower = null + + if(!sting_paths) + sting_paths = init_subtypes(/obj/effect/proc_holder/changeling) + for(var/obj/effect/proc_holder/changeling/cling_sting in sting_paths) + if(cling_sting.name == sting_name) + thepower = cling_sting + + if(thepower == null) + user << "This is awkward. Changeling power purchase failed, please report this bug to a coder!" + return + + if(absorbedcount < thepower.req_dna) + user << "We lack the energy to evolve this ability!" + return + + if(has_sting(thepower)) + user << "We have already evolved this ability!" + return + + if(thepower.dna_cost < 0) + user << "We cannot evolve this ability." + return + + if(geneticpoints < thepower.dna_cost) + user << "We have reached our capacity for abilities." + return + + if(user.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist. + user << "We lack the energy to evolve new abilities right now." + return + + geneticpoints -= thepower.dna_cost + purchasedpowers += thepower + thepower.on_purchase(user) + +//Reselect powers +/datum/changeling/proc/lingRespec(var/mob/user) + if(!ishuman(user)) + user << "We can't remove our evolutions in this form!" + return + if(canrespec) + user << "We have removed our evolutions from this form, and are now ready to readapt." + user.remove_changeling_powers(1) + canrespec = 0 + user.make_changeling() + return 1 + else + user << "You lack the power to readapt your evolutions!" + return 0 + +/mob/proc/make_changeling() + if(!mind) + return + if(!ishuman(src) && !ismonkey(src)) + return + if(!mind.changeling) + mind.changeling = new /datum/changeling(gender) + if(!sting_paths) + sting_paths = init_subtypes(/obj/effect/proc_holder/changeling) + if(mind.changeling.purchasedpowers) + remove_changeling_powers(1) + + for(var/language in languages) + if(!(language in mind.changeling.absorbed_languages)) + mind.changeling.absorbed_languages += language + + // purchase free powers. + for(var/obj/effect/proc_holder/changeling/path in sting_paths) + //var/obj/effect/proc_holder/changeling/S = new path() + if(!path.dna_cost) + if(!mind.changeling.has_sting(path)) + mind.changeling.purchasedpowers += path + path.on_purchase(src) + + var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste + mind.changeling.absorbed_dna |= C.dna + return 1 + +/datum/changeling/proc/reset() + chosen_sting = null + geneticpoints = initial(geneticpoints) + sting_range = initial(sting_range) + chem_storage = initial(chem_storage) + chem_recharge_rate = initial(chem_recharge_rate) + chem_charges = min(chem_charges, chem_storage) + chem_recharge_slowdown = initial(chem_recharge_slowdown) + mimicing = "" + +/mob/proc/remove_changeling_powers(var/keep_free_powers=0) + if(ishuman(src) || ismonkey(src)) + if(mind && mind.changeling) + digitalcamo = 0 + mind.changeling.changeling_speak = 0 + mind.changeling.reset() + for(var/obj/effect/proc_holder/changeling/p in mind.changeling.purchasedpowers) + if(!(p.dna_cost == 0 && keep_free_powers)) + mind.changeling.purchasedpowers -= p + +/datum/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power) + for(var/obj/effect/proc_holder/changeling/P in purchasedpowers) + if(power.name == P.name) + return 1 + return 0 diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm deleted file mode 100644 index 68458760855..00000000000 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ /dev/null @@ -1,506 +0,0 @@ -// READ: Don't use the apostrophe in name or desc. Causes script errors. - -var/list/powers = typesof(/datum/power/changeling) - /datum/power/changeling //needed for the badmin verb for now -var/list/datum/power/changeling/powerinstances = list() - -/datum/power //Could be used by other antags too - var/name = "Power" - 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. - -/datum/power/changeling - var/allowduringlesserform = 0 - var/genomecost = 500000 // Cost for the changling to evolve this power. - -/datum/power/changeling/absorb_dna - 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/proc/changeling_absorb_dna - -/datum/power/changeling/transform - name = "Transform" - desc = "We take on the apperance and voice of one we have absorbed." - genomecost = 0 - verbpath = /mob/proc/changeling_transform - -/datum/power/changeling/change_species - name = "Change Species" - desc = "We take on the apperance of a species that we have absorbed." - genomecost = 0 - verbpath = /mob/proc/changeling_change_species - -/datum/power/changeling/fakedeath - name = "Regenerative Stasis" - desc = "We become weakened to a death-like state, where we will rise again from death." - helptext = "Can be used before or after death. Duration varies greatly." - genomecost = 0 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_fakedeath - -// Hivemind - -/datum/power/changeling/hive_upload - name = "Hive Channel" - 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/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/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/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/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/proc/changeling_blind_sting - -/datum/power/changeling/silence_sting - name = "Silence Sting" - desc = "We silently sting a human, completely silencing them for a short time." - helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." - genomecost = 3 - allowduringlesserform = 1 - verbpath = /mob/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/proc/changeling_mimicvoice - -/datum/power/changeling/extractdna - name = "Extract DNA" - desc = "We stealthily sting a target and extract the DNA from them." - 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/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/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 = 4 - verbpath = /mob/proc/changeling_paralysis_sting - -/datum/power/changeling/LSDSting - name = "Hallucination Sting" - desc = "We evolve the ability to sting a target with a powerful hallunicationary chemical." - helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." - genomecost = 3 - verbpath = /mob/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/proc/changeling_DEATHsting - -/datum/power/changeling/unfat_sting - name = "Unfat Sting" - desc = "We silently sting a human, forcing them to rapidly metobolize their fat." - genomecost = 1 - verbpath = /mob/proc/changeling_unfat_sting - -/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/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/proc/changeling_unstun - -/datum/power/changeling/ChemicalSynth - name = "Rapid Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 4 - isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical -/* -/datum/power/changeling/AdvChemicalSynth - name = "Advanced Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 8 - isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical -*/ -/datum/power/changeling/EngorgedGlands - name = "Engorged Chemical Glands" - desc = "Our chemical glands swell, permitting us to store more chemicals inside of them." - helptext = "Allows us to store an extra 25 units of chemicals." - genomecost = 4 - isVerb = 0 - verbpath = /mob/proc/changeling_engorgedglands - -/datum/power/changeling/DigitalCamoflague - name = "Digital Camoflauge" - desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras." - 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/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/proc/changeling_rapidregen - - - -// Modularchangling, totally stolen from the new player panel. YAYY -/datum/changeling/proc/EvolutionMenu()//The new one - set category = "Changeling" - set desc = "Level up!" - - if(!usr || !usr.mind || !usr.mind.changeling) return - src = usr.mind.changeling - - if(!powerinstances.len) - for(var/P in powers) - powerinstances += new P() - - var/dat = "Changling Evolution Menu" - - //javascript, the part that does most of the work~ - dat += {" - - - - - - - "} - - //body tag start + onload and onkeypress (onkeyup) javascript event calls - dat += "" - - //title + search bar - dat += {" - - - - - - - - -
- Changling Evolution Menu
- Hover over a power to see more information
- Current evolution points left to evolve with: [geneticpoints]
- Absorb genomes to acquire more evolution points -

-

- Search: -
- - "} - - //player table header - dat += {" - - "} - - var/i = 1 - for(var/datum/power/changeling/P in powerinstances) - var/ownsthis = 0 - - if(P in purchasedpowers) - ownsthis = 1 - - - var/color = "#e6e6e6" - if(i%2 == 0) - color = "#f2f2f2" - - - dat += {" - - - - - - "} - - i++ - - - //player table ending - dat += {" -
- - - Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost] - -
-
-
- - - - "} - - usr << browse(dat, "window=powers;size=900x480") - - -/datum/changeling/Topic(href, href_list) - ..() - if(!ismob(usr)) - return - - if(href_list["P"]) - var/datum/mind/M = usr.mind - if(!istype(M)) - return - purchasePower(M, href_list["P"]) - call(/datum/changeling/proc/EvolutionMenu)() - - - -/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1) - if(!M || !M.changeling) - return - - var/datum/power/changeling/Thepower = Pname - - - for (var/datum/power/changeling/P in powerinstances) - //world << "[P] - [Pname] = [P.name == Pname ? "True" : "False"]" - if(P.name == Pname) - Thepower = P - break - - - if(Thepower == null) - M.current << "This is awkward. Changeling power purchase failed, please report this bug to a coder!" - return - - if(Thepower in purchasedpowers) - M.current << "We have already evolved this ability!" - return - - - if(geneticpoints < Thepower.genomecost) - M.current << "We cannot evolve this... yet. We must acquire more DNA." - return - - geneticpoints -= Thepower.genomecost - - purchasedpowers += Thepower - - if(!Thepower.isVerb && Thepower.verbpath) - call(M.current, Thepower.verbpath)() - else if(remake_verbs) - M.current.make_changeling() - diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm new file mode 100644 index 00000000000..6acb6e5a66d --- /dev/null +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -0,0 +1,107 @@ +/obj/effect/proc_holder/changeling/absorbDNA + name = "Absorb DNA" + desc = "Absorb the DNA of our victim." + chemical_cost = 0 + dna_cost = 0 + req_human = 1 + max_genetic_damage = 100 + +/obj/effect/proc_holder/changeling/absorbDNA/can_sting(var/mob/living/carbon/user) + if(!..()) + return + + var/datum/changeling/changeling = user.mind.changeling + if(changeling.isabsorbing) + user << "We are already absorbing!" + return + + var/obj/item/weapon/grab/G = user.get_active_hand() + if(!istype(G)) + user << "We must be grabbing a creature in our active hand to absorb them." + return + if(G.state <= GRAB_NECK) + user << "We must have a tighter grip to absorb this creature." + return + + var/mob/living/carbon/target = G.affecting + return changeling.can_absorb_dna(user,target) + + + +/obj/effect/proc_holder/changeling/absorbDNA/sting_action(var/mob/user) + var/datum/changeling/changeling = user.mind.changeling + var/obj/item/weapon/grab/G = user.get_active_hand() + var/mob/living/carbon/human/target = G.affecting + changeling.isabsorbing = 1 + for(var/stage = 1, stage<=3, stage++) + switch(stage) + if(1) + user << "This creature is compatible. We must hold still..." + if(2) + user << "We extend a proboscis." + user.visible_message("[user] extends a proboscis!") + if(3) + user << "We stab [target] with the proboscis." + user.visible_message("[user] stabs [target] with the proboscis!") + target << "You feel a sharp stabbing pain!" + target.take_overall_damage(40) + feedback_add_details("changeling_powers","A[stage]") + if(!do_mob(user, target, 150)) + user << "Our absorption of [target] has been interrupted!" + changeling.isabsorbing = 0 + return + + user << "We have absorbed [target]!" + user.visible_message("[user] sucks the fluids from [target]!") + target << "You have been absorbed by the changeling!" + + if(!changeling.has_dna(target.dna)) + changeling.absorb_dna(target, user) + + if(user.nutrition < 450) // Nutrition level before overeat_duration starts ticking for you to become obese. + user.nutrition = min((user.nutrition + target.nutrition), 450) + + if(target.mind)//if the victim has got a mind + + target.mind.show_memory(src, 0) //I can read your mind, kekeke. Output all their notes. + + if(target.mind.changeling)//If the target was a changeling, suck out their extra juice and objective points! + changeling.chem_charges += min(target.mind.changeling.chem_charges, changeling.chem_storage) + changeling.absorbedcount += (target.mind.changeling.absorbedcount) + + target.mind.changeling.absorbed_dna.len = 1 + target.mind.changeling.absorbedcount = 0 + + + changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage) + + changeling.isabsorbing = 0 + changeling.canrespec = 1 + + target.death(0) + target.Drain() + return 1 + + + +//Absorbs the target DNA. +/datum/changeling/proc/absorb_dna(mob/living/carbon/T, var/mob/user) + if(absorbed_dna.len) + absorbed_dna.Cut(1,2) + T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. + var/datum/dna/new_dna = T.dna.Clone() + //Steal all of their languages! + for(var/language in T.languages) + if(!(language in absorbed_languages)) + absorbed_languages += language + changeling_update_languages(absorbed_languages, user) + + absorbedcount++ + store_dna(new_dna, user) + +/datum/changeling/proc/store_dna(var/datum/dna/new_dna, var/mob/user) + for(var/datum/objective/escape/escape_with_identity/E in user.mind.objectives) + if(E.target_real_name == new_dna.real_name) + protected_dna |= new_dna + return + absorbed_dna |= new_dna diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm new file mode 100644 index 00000000000..e2f88ac9d9f --- /dev/null +++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm @@ -0,0 +1,24 @@ +//Augmented Eyesight: Gives you thermal and night vision - bye bye, flashlights. Also, high DNA cost because of how powerful it is. +//Possible todo: make a custom message for directing a penlight/flashlight at the eyes - not sure what would display though. + +/obj/effect/proc_holder/changeling/augmented_eyesight + name = "Augmented Eyesight" + desc = "Creates heat receptors in our eyes and dramatically increases light sensing ability." + helptext = "Grants us night vision and thermal vision. It may be toggled on or off." + chemical_cost = 0 + dna_cost = 2 //Would be 1 without thermal vision + var/active = 0 //Whether or not vision is enhanced + +/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(var/mob/user) + active = !active + if(active) + user << "We feel a minute twitch in our eyes, and darkness creeps away." + else + user << "Our vision dulls. Shadows gather." + user.sight -= SEE_MOBS + while(active) + user.see_in_dark = 8 + user.see_invisible = 2 + user.sight |= SEE_MOBS + sleep(1) //BAD THINGS HAPPEN WITHOUT THIS. + return 1 diff --git a/code/game/gamemodes/changeling/powers/digitalcamo.dm b/code/game/gamemodes/changeling/powers/digitalcamo.dm new file mode 100644 index 00000000000..92ae8e7781e --- /dev/null +++ b/code/game/gamemodes/changeling/powers/digitalcamo.dm @@ -0,0 +1,17 @@ +/obj/effect/proc_holder/changeling/digitalcamo + name = "Digital Camouflage" + desc = "By evolving the ability to distort our form and proprotions, we defeat common altgorithms used to detect lifeforms on cameras." + helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us... uncanny." + dna_cost = 1 + +//Prevents AIs tracking you but makes you easily detectable to the human-eye. +/obj/effect/proc_holder/changeling/digitalcamo/sting_action(var/mob/user) + + if(user.digitalcamo) + user << "We return to normal." + else + user << "We distort our form to prevent AI-tracking." + user.digitalcamo = !user.digitalcamo + + feedback_add_details("changeling_powers","CAM") + return 1 diff --git a/code/game/gamemodes/changeling/powers/epinephrine.dm b/code/game/gamemodes/changeling/powers/epinephrine.dm new file mode 100644 index 00000000000..55ce85cf88d --- /dev/null +++ b/code/game/gamemodes/changeling/powers/epinephrine.dm @@ -0,0 +1,27 @@ +/obj/effect/proc_holder/changeling/epinephrine + name = "Epinephrine Overdose" + desc = "We evolve additional sacs of adrenaline throughout our body." + helptext = "Removes all stuns instantly and adds a short-term reduction in further stuns. Can be used while unconscious. Continued use poisons the body." + chemical_cost = 30 + dna_cost = 2 + req_human = 1 + req_stat = UNCONSCIOUS + +//Recover from stuns. +/obj/effect/proc_holder/changeling/epinephrine/sting_action(var/mob/living/user) + + if(user.lying) + user << "We arise." + else + user << "Adrenaline rushes through us." + user.stat = 0 + user.SetParalysis(0) + user.SetStunned(0) + user.SetWeakened(0) + user.lying = 0 + user.update_canmove() + user.reagents.add_reagent("synaptizine", 20) + user.adjustStaminaLoss(-75) + + feedback_add_details("changeling_powers","UNS") + return 1 diff --git a/code/game/gamemodes/changeling/powers/fakedeath.dm b/code/game/gamemodes/changeling/powers/fakedeath.dm new file mode 100644 index 00000000000..9a4b144cc71 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/fakedeath.dm @@ -0,0 +1,36 @@ +/obj/effect/proc_holder/changeling/fakedeath + name = "Regenerative Stasis" + desc = "We fall into a stasis, allowing us to regenerate." + chemical_cost = 15 + dna_cost = 0 + req_dna = 1 + req_stat = DEAD + max_genetic_damage = 100 + + +//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. +/obj/effect/proc_holder/changeling/fakedeath/sting_action(var/mob/living/user) + + user << "We begin our stasis, preparing energy to arise once more." + + user.status_flags |= FAKEDEATH //play dead + user.update_canmove() + + if(user.stat != DEAD) + user.emote("deathgasp") + user.tod = worldtime2text() + + spawn(800) + if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers) + user << "We are ready to regenerate." + user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null) + + feedback_add_details("changeling_powers","FD") + return 1 + +/obj/effect/proc_holder/changeling/fakedeath/can_sting(var/mob/user) + if(user.status_flags & FAKEDEATH) + return + if(!user.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death + return + return ..() \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/fleshmend.dm b/code/game/gamemodes/changeling/powers/fleshmend.dm new file mode 100644 index 00000000000..97889d1c9e3 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/fleshmend.dm @@ -0,0 +1,25 @@ +/obj/effect/proc_holder/changeling/fleshmend + name = "Fleshmend" + desc = "Our flesh rapidly regenerates, healing our wounds." + helptext = "Heals a moderate amount of damage over a short period of time. Can be used while unconscious." + chemical_cost = 25 + dna_cost = 2 + req_stat = UNCONSCIOUS + +//Starts healing you every second for 10 seconds. Can be used whilst unconscious. +/obj/effect/proc_holder/changeling/fleshmend/sting_action(var/mob/living/user) + user << "We begin to heal rapidly." + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.restore_blood() + H.shock_stage = 0 + spawn(1) + H.fixblood() + spawn(0) + for(var/i = 0, i<10,i++) + user.heal_overall_damage(10, 10) + user.adjustOxyLoss(-10) + sleep(10) + + feedback_add_details("changeling_powers","RR") + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/glands.dm b/code/game/gamemodes/changeling/powers/glands.dm new file mode 100644 index 00000000000..d08bd3021aa --- /dev/null +++ b/code/game/gamemodes/changeling/powers/glands.dm @@ -0,0 +1,13 @@ +/obj/effect/proc_holder/changeling/glands + name = "Engorged Chemical Glands" + desc = "Our chemical glands swell, permitting us to store more chemicals inside of them." + helptext = "Allows us to store an extra 25 units of chemicals, and doubles production rate." + dna_cost = 2 + chemical_cost = -1 + +/obj/effect/proc_holder/changeling/glands/on_purchase(var/mob/user) + ..() + var/datum/changeling/changeling=user.mind.changeling + changeling.chem_storage += 25 + changeling.chem_recharge_rate *=2 + return \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/game/gamemodes/changeling/powers/hivemind.dm new file mode 100644 index 00000000000..853b7081fed --- /dev/null +++ b/code/game/gamemodes/changeling/powers/hivemind.dm @@ -0,0 +1,92 @@ +//HIVEMIND COMMUNICATION (:g) +/obj/effect/proc_holder/changeling/hivemind_comms + name = "Hivemind Communication" + desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings." + helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives." + dna_cost = 0 + chemical_cost = -1 + +/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(var/mob/user) + ..() + var/datum/changeling/changeling=user.mind.changeling + changeling.changeling_speak = 1 + user << "Use say \":g message\" to communicate with the other changelings." + var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new + if(!changeling.has_sting(S1)) + changeling.purchasedpowers+=S1 + var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new + if(!changeling.has_sting(S2)) + changeling.purchasedpowers+=S2 + return + +// HIVE MIND UPLOAD/DOWNLOAD DNA +var/list/datum/dna/hivemind_bank = list() + +/obj/effect/proc_holder/changeling/hivemind_upload + name = "Hive Channel DNA" + desc = "Allows us to channel DNA in the airwaves to allow other changelings to absorb it." + chemical_cost = 10 + dna_cost = -1 + +/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user) + var/datum/changeling/changeling = user.mind.changeling + var/list/names = list() + for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna)) + if(!(DNA in hivemind_bank)) + names += DNA.real_name + + if(names.len <= 0) + user << "The airwaves already have all of our DNA." + return + + var/chosen_name = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names + if(!chosen_name) + return + + var/datum/dna/chosen_dna = changeling.GetDNA(chosen_name) + if(!chosen_dna) + return + + hivemind_bank += chosen_dna + user << "We channel the DNA of [chosen_name] to the air." + feedback_add_details("changeling_powers","HU") + return 1 + +/obj/effect/proc_holder/changeling/hivemind_download + name = "Hive Absorb DNA" + desc = "Allows us to absorb DNA that has been channeled to the airwaves. Does not count towards absorb objectives." + chemical_cost = 10 + dna_cost = -1 + +/obj/effect/proc_holder/changeling/hivemind_download/can_sting(var/mob/living/carbon/user) + if(!..()) + return + var/datum/changeling/changeling = user.mind.changeling + if(changeling.absorbed_dna[1] == user.dna)//If our current DNA is the stalest, we gotta ditch it. + user << "We have reached our capacity to store genetic information! We must transform before absorbing more." + return + return 1 + +/obj/effect/proc_holder/changeling/hivemind_download/sting_action(var/mob/user) + var/datum/changeling/changeling = user.mind.changeling + var/list/names = list() + for(var/datum/dna/DNA in hivemind_bank) + if(!(DNA in changeling.absorbed_dna)) + names[DNA.real_name] = DNA + + if(names.len <= 0) + user << "There's no new DNA to absorb from the air." + return + + var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names + if(!S) return + var/datum/dna/chosen_dna = names[S] + if(!chosen_dna) + return + + if(changeling.absorbed_dna.len) + changeling.absorbed_dna.Cut(1,2) + changeling.store_dna(chosen_dna, user) + user << "We absorb the DNA of [S] from the air." + feedback_add_details("changeling_powers","HD") + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm new file mode 100644 index 00000000000..b50c23197c4 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/humanform.dm @@ -0,0 +1,74 @@ +/obj/effect/proc_holder/changeling/humanform + name = "Human form" + desc = "We change into a human." + chemical_cost = 5 + genetic_damage = 3 + req_dna = 1 + max_genetic_damage = 3 + + +//Transform into a human. +/obj/effect/proc_holder/changeling/humanform/sting_action(var/mob/living/carbon/user) + var/datum/changeling/changeling = user.mind.changeling + var/list/names = list() + for(var/datum/dna/DNA in (changeling.absorbed_dna+changeling.protected_dna)) + names += "[DNA.real_name]" + + var/chosen_name = input("Select the target DNA: ", "Target DNA", null) as null|anything in names + if(!chosen_name) + return + + var/datum/dna/chosen_dna = changeling.GetDNA(chosen_name) + if(!chosen_dna) + return + if(!user) + return 0 + user << "We transform our appearance." + user.dna = chosen_dna + + var/list/implants = list() + for (var/obj/item/weapon/implant/I in user) //Still preserving implants + implants += I + + for(var/obj/item/W in src) + user.u_equip(W) + if (user.client) + user.client.screen -= W + if (W) + W.loc = user.loc + W.dropped(user) + W.layer = initial(W.layer) + + var/mob/living/carbon/human/O = new /mob/living/carbon/human( user, delay_ready_dna=1 ) + if (user.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + O.dna = user.dna.Clone() + user.dna = null + O.real_name = chosen_dna.real_name + O.set_species() + for(var/obj/T in user) + del(T) + + O.loc = user.loc + + O.UpdateAppearance() + domutcheck(O, null) + O.setToxLoss(user.getToxLoss()) + O.adjustBruteLoss(user.getBruteLoss()) + O.setOxyLoss(user.getOxyLoss()) + O.adjustFireLoss(user.getFireLoss()) + O.stat = user.stat + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + + user.mind.transfer_to(O) + O.mind.changeling.changeling_update_languages(changeling.absorbed_languages) + O.mind.changeling.purchasedpowers -= src + //O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/lesserform(null) + feedback_add_details("changeling_powers","LFT") + qdel(user) + return 1 + diff --git a/code/game/gamemodes/changeling/powers/lesserform.dm b/code/game/gamemodes/changeling/powers/lesserform.dm new file mode 100644 index 00000000000..0069b7cbfd2 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/lesserform.dm @@ -0,0 +1,67 @@ +/obj/effect/proc_holder/changeling/lesserform + name = "Lesser form" + desc = "We debase ourselves and become lesser. We become a monkey." + chemical_cost = 5 + dna_cost = 1 + genetic_damage = 3 + req_human = 1 + +//Transform into a monkey. +/obj/effect/proc_holder/changeling/lesserform/sting_action(var/mob/living/carbon/human/user) + var/datum/changeling/changeling = user.mind.changeling + if(!user) + return 0 + if(user.has_brain_worms()) + user << "We cannot perform this ability at the present time!" + return + user << "Our genes cry out!" + + var/mob/living/carbon/C = user + + //TODO replace with monkeyize proc + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/implant/W in C) + implants += W + + C.monkeyizing = 1 + C.canmove = 0 + C.icon = null + C.overlays.Cut() + C.invisibility = 101 + + var/atom/movable/overlay/animation = new /atom/movable/overlay( C.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(30) + del(animation) + + var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) + O.dna = C.dna.Clone() + C.dna = null + + for(var/obj/item/W in C) + C.drop_from_inventory(W) + for(var/obj/T in C) + del(T) + + O.loc = C.loc + O.name = "monkey ([copytext(md5(C.real_name), 2, 6)])" + O.setToxLoss(C.getToxLoss()) + O.adjustBruteLoss(C.getBruteLoss()) + O.setOxyLoss(C.getOxyLoss()) + O.adjustFireLoss(C.getFireLoss()) + O.stat = C.stat + O.a_intent = "harm" + for(var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O + + C.mind.transfer_to(O) + O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null) + O.mind.changeling.changeling_update_languages(changeling.absorbed_languages) + + feedback_add_details("changeling_powers","LF") + qdel(C) + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/mimic_voice.dm b/code/game/gamemodes/changeling/powers/mimic_voice.dm new file mode 100644 index 00000000000..9d637245196 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/mimic_voice.dm @@ -0,0 +1,28 @@ +/obj/effect/proc_holder/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." + chemical_cost = 0 //constant chemical drain hardcoded + dna_cost = 1 + req_human = 1 + + +// Fake Voice +/obj/effect/proc_holder/changeling/mimicvoice/sting_action(var/mob/user) + var/datum/changeling/changeling=user.mind.changeling + if(changeling.mimicing) + changeling.mimicing = "" + changeling.chem_recharge_slowdown -= 0.5 + user << "We return our vocal glands to their original position." + return + + var/mimic_voice = stripped_input(user, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN) + if(!mimic_voice) + return + + changeling.mimicing = mimic_voice + changeling.chem_recharge_slowdown += 0.5 + user << "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active." + user << "Use this power again to return to our original voice and reproduce chemicals again." + + feedback_add_details("changeling_powers","MV") diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm new file mode 100644 index 00000000000..31fd7c577dd --- /dev/null +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -0,0 +1,339 @@ +/* + Changeling Mutations! ~By Miauw (ALL OF IT :V) + Contains: + Arm Blade + Space Suit + Shield + Armor +*/ + + +//Parent to shields and blades because muh copypasted code. +/obj/effect/proc_holder/changeling/weapon + name = "Organic Weapon" + desc = "Go tell a coder if you see this" + helptext = "Yell at coderbus" + chemical_cost = 1000 + dna_cost = -1 + genetic_damage = 1000 + + var/weapon_type + var/weapon_name_simple + +/obj/effect/proc_holder/changeling/weapon/try_to_sting(var/mob/user, var/mob/target) + if(istype(user.l_hand, weapon_type)) //Not the nicest way to do it, but eh + qdel(user.l_hand) + user.visible_message("With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "[H] casts off their [suit_name_simple]!", "We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]", "You hear the organic matter ripping and tearing!") + qdel(H.wear_suit) + qdel(H.head) + H.update_inv_wear_suit() + H.update_inv_head() + H.update_hair() + + if(blood_on_castoff) + var/turf/simulated/T = get_turf(H) + if(istype(T)) + T.add_blood(H) //So real blood decals + playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds + + changeling.geneticdamage += genetic_damage //Casting off a space suit leaves you weak for a few seconds. + changeling.chem_recharge_slowdown -= recharge_slowdown + return + ..(H, target) + +/obj/effect/proc_holder/changeling/suit/sting_action(var/mob/living/carbon/human/user) + if(user.wear_suit && !user.wear_suit.canremove) + user << "\the [user.wear_suit] is stuck to your body, you cannot grow a [suit_name_simple] over it!" + return + if(user.head && !user.head.canremove) + user << "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!" + return + + user.u_equip(user.head) + user.u_equip(user.wear_suit) + + user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1) + user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1) + + var/datum/changeling/changeling = user.mind.changeling + changeling.chem_recharge_slowdown += recharge_slowdown + return 1 + + +//fancy headers yo +/***************************************\ +|***************ARM BLADE***************| +\***************************************/ +/obj/effect/proc_holder/changeling/weapon/arm_blade + name = "Arm Blade" + desc = "We reform one of our arms into a deadly blade." + helptext = "Cannot be used while in lesser form." + chemical_cost = 20 + dna_cost = 2 + genetic_damage = 10 + req_human = 1 + max_genetic_damage = 20 + weapon_type = /obj/item/weapon/melee/arm_blade + weapon_name_simple = "blade" + +/obj/item/weapon/melee/arm_blade + name = "arm blade" + desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter" + icon = 'icons/obj/weapons.dmi' + icon_state = "arm_blade" + item_state = "arm_blade" + icon_override = 'icons/mob/in-hand/changeling.dmi' + w_class = 5.0 + sharp = 1 + edge = 1 + canremove = 0 + force = 25 + throwforce = 0 //Just to be on the safe side + throw_range = 0 + throw_speed = 0 + +/obj/item/weapon/melee/arm_blade/New() + ..() + if(ismob(loc)) + loc.visible_message("A grotesque blade forms around [loc.name]\'s arm!", "Our arm twists and mutates, transforming it into a deadly blade.", "You hear organic matter ripping and tearing!") + +/obj/item/weapon/melee/arm_blade/dropped(mob/user) + user.visible_message("With a sickening crunch, [user] reforms his blade into an arm!", "We assimilate the blade back into our body.", "" + return + + else if(A.locked) + user << "The airlock's bolts prevent it from being forced." + return + + else + //user.say("Heeeeeeeeeerrre's Johnny!") + user.visible_message("[user] forces the door to open with \his [src]!", "We force the door to open.", "You hear a metal screeching sound.") + A.open(1) + + +/***************************************\ +|****************SHIELD*****************| +\***************************************/ +/obj/effect/proc_holder/changeling/weapon/shield + name = "Organic Shield" + desc = "We reform one of our arms into a hard shield." + helptext = "Organic tissue cannot resist damage forever, the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form." + chemical_cost = 20 + dna_cost = 1 + genetic_damage = 12 + req_human = 1 + max_genetic_damage = 20 + + weapon_type = /obj/item/weapon/shield/changeling + weapon_name_simple = "shield" + +/obj/effect/proc_holder/changeling/weapon/shield/sting_action(var/mob/user) + var/datum/changeling/changeling = user.mind.changeling //So we can read the absorbedcount. + if(!changeling) + return + + var/obj/item/weapon/shield/changeling/S = ..(user) + S.remaining_uses = round(changeling.absorbedcount * 3) + return 1 + +/obj/item/weapon/shield/changeling + name = "shield-like mass" + desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield." + canremove = 0 + icon = 'icons/obj/weapons.dmi' + icon_state = "ling_shield" + icon_override = 'icons/mob/in-hand/changeling.dmi' + + var/remaining_uses //Set by the changeling ability. + +/obj/item/weapon/shield/changeling/New() + ..() + if(ismob(loc)) + loc.visible_message("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!", "We inflate our hand into a strong shield.", "You hear organic matter ripping and tearing!") + +/obj/item/weapon/shield/changeling/dropped() + qdel(src) + +/obj/item/weapon/shield/changeling/IsShield() + if(remaining_uses < 1) + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + H.visible_message("With a sickening crunch, [H] reforms his shield into an arm!", "We assimilate our shield into our body", "[loc.name]\'s flesh rapidly inflates, forming a bloated mass around their body!", "We inflate our flesh, creating a spaceproof suit!", "You hear organic matter ripping and tearing!") + processing_objects += src + +/obj/item/clothing/suit/space/changeling/dropped() + qdel(src) + +/obj/item/clothing/suit/space/changeling/process() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + H.reagents.add_reagent("dexalinp", REAGENTS_METABOLISM) + +/obj/item/clothing/head/helmet/space/changeling + name = "flesh mass" + icon_state = "lingspacehelmet" + desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front." + flags = HEADCOVERSEYES | BLOCKHAIR | HEADCOVERSMOUTH | STOPSPRESSUREDMAGE + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + canremove = 0 + +/obj/item/clothing/head/helmet/space/changeling/dropped() + qdel(src) + + +/***************************************\ +|*****************ARMOR*****************| +\***************************************/ +/obj/effect/proc_holder/changeling/suit/armor + name = "Chitinous Armor" + desc = "We turn our skin into tough chitin to protect us from damage." + helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Retreating the armor damages our genomes. Cannot be used in lesser form." + chemical_cost = 20 + dna_cost = 2 + genetic_damage = 11 + req_human = 1 + max_genetic_damage = 20 + + suit_type = /obj/item/clothing/suit/armor/changeling + helmet_type = /obj/item/clothing/head/helmet/changeling + suit_name_simple = "armor" + helmet_name_simple = "helmet" + recharge_slowdown = 0.25 + +/obj/item/clothing/suit/armor/changeling + name = "chitinous mass" + desc = "A tough, hard covering of black chitin." + icon_state = "lingarmor" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + slowdown = 2 + armor = list(melee = 65, bullet = 20, laser = 10, energy = 13, bomb = 0, bio = 0, rad = 0) + canremove = 0 + flags_inv = HIDEJUMPSUIT + cold_protection = 0 + heat_protection = 0 + +/obj/item/clothing/suit/armor/changeling/New() + ..() + if(ismob(loc)) + loc.visible_message("[loc.name]\'s flesh turns black, quickly transforming into a hard, chitinous mass!", "We harden our flesh, creating a suit of armor!", "You hear organic matter ripping and tearing!") + +/obj/item/clothing/suit/armor/changeling/dropped() + qdel(src) + +/obj/item/clothing/head/helmet/changeling + name = "chitinous mass" + desc = "A tough, hard covering of black chitin with transparent chitin in front." + icon_state = "lingarmorhelmet" + flags = HEADCOVERSEYES | BLOCKHAIR + armor = list(melee = 70, bullet = 15, laser = 7,energy = 10, bomb = 5, bio = 2, rad = 0) + canremove = 0 + flags_inv = HIDEEARS + +/obj/item/clothing/head/helmet/changeling/dropped() + qdel(src) diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/game/gamemodes/changeling/powers/panacea.dm new file mode 100644 index 00000000000..f6721af7f47 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/panacea.dm @@ -0,0 +1,25 @@ +/obj/effect/proc_holder/changeling/panacea + name = "Anatomic Panacea" + desc = "Expels impurifications from our form; curing diseases, removing toxins and radiation, and resetting our genetic code completely." + helptext = "Can be used while unconscious." + chemical_cost = 20 + dna_cost = 1 + req_stat = UNCONSCIOUS + +//Heals the things that the other regenerative abilities don't. +/obj/effect/proc_holder/changeling/panacea/sting_action(var/mob/user) + + user << "We cleanse impurities from our form." + user.reagents.add_reagent("ryetalyn", 10) + user.reagents.add_reagent("hyronalin", 10) + user.reagents.add_reagent("anti_toxin", 20) + + if(istype(user, /mob/living/carbon)) + var/mob/living/carbon/C = user + if(C.virus2.len) + for (var/ID in C.virus2) + var/datum/disease2/disease/V = C.virus2[ID] + C.antibodies |= V.antigen + + feedback_add_details("changeling_powers","AP") + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm new file mode 100644 index 00000000000..526172fdf38 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/revive.dm @@ -0,0 +1,73 @@ +/obj/effect/proc_holder/changeling/revive + name = "Regenerate" + desc = "We regenerate, healing all damage from our form." + req_stat = DEAD + +//Revive from regenerative stasis +/obj/effect/proc_holder/changeling/revive/sting_action(var/mob/living/carbon/user) + + if(user.stat == DEAD) + dead_mob_list -= user + living_mob_list += user + user.stat = CONSCIOUS + user.tod = null + user.setToxLoss(0) + user.setOxyLoss(0) + user.setCloneLoss(0) + user.setBrainLoss(0) + user.SetParalysis(0) + user.SetStunned(0) + user.SetWeakened(0) + user.radiation = 0 + user.eye_blind = 0 + user.eye_blurry = 0 + user.ear_deaf = 0 + user.ear_damage = 0 + user.heal_overall_damage(user.getBruteLoss(), user.getFireLoss()) + user.reagents.clear_reagents() + user.germ_level = 0 + user.next_pain_time = 0 + user.traumatic_shock = 0 + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.restore_blood() + H.shock_stage = 0 + spawn(1) + H.fixblood() + for(var/organ_name in H.organs_by_name) + var/datum/organ/external/O = H.organs_by_name[organ_name] + for(var/obj/item/weapon/shard/shrapnel/s in O.implants) + if(istype(s)) + O.implants -= s + H.contents -= s + del(s) + O.amputated = 0 + O.brute_dam = 0 + O.burn_dam = 0 + O.damage_state = "00" + O.germ_level = 0 + O.hidden = null + O.number_wounds = 0 + O.open = 0 + O.perma_injury = 0 + O.stage = 0 + O.status = 0 + O.trace_chemicals = list() + O.wounds = list() + O.wound_update_accuracy = 1 + for(var/n in H.internal_organs_by_name) + var/datum/organ/internal/IO = H.internal_organs_by_name[n] + IO.damage = 0 + IO.trace_chemicals = list() + H.updatehealth() + user << "We have regenerated." + + user.regenerate_icons() + user.hud_updateflag |= 1 << HEALTH_HUD + user.hud_updateflag |= 1 << STATUS_HUD + + user.status_flags &= ~(FAKEDEATH) + user.update_canmove() + user.mind.changeling.purchasedpowers -= src + feedback_add_details("changeling_powers","CR") + return 1 diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm new file mode 100644 index 00000000000..cb9cc06c62b --- /dev/null +++ b/code/game/gamemodes/changeling/powers/shriek.dm @@ -0,0 +1,46 @@ +/obj/effect/proc_holder/changeling/resonant_shriek + name = "Resonant Shriek" + desc = "Our lungs and vocal chords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded." + helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors." + chemical_cost = 20 + dna_cost = 1 + req_human = 1 + +//A flashy ability, good for crowd control and sewing chaos. +/obj/effect/proc_holder/changeling/resonant_shriek/sting_action(var/mob/user) + for(var/mob/living/M in get_mobs_in_view(4, user)) + if(iscarbon(M)) + if(!M.mind || !M.mind.changeling) + M.ear_deaf = max(0, M.ear_deaf + 30) + M.ear_damage = max(0, M.ear_damage) + M.confused += 20 + M.Jitter(50) + else + M << sound('sound/effects/screech.ogg') + + if(issilicon(M)) + M << sound('sound/weapons/flash.ogg') + M.Weaken(rand(5,10)) + + for(var/obj/machinery/light/L in range(4, user)) + L.on = 1 + L.broken() + + feedback_add_details("changeling_powers","RS") + return 1 + +/obj/effect/proc_holder/changeling/dissonant_shriek + name = "Dissonant Shriek" + desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics." + chemical_cost = 20 + dna_cost = 1 + +//A flashy ability, good for crowd control and sewing chaos. +/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(var/mob/user) + for(var/obj/machinery/light/L in range(5, usr)) + L.on = 1 + L.broken() + empulse(get_turf(user), 2, 5, 1) + return 1 + + diff --git a/code/game/gamemodes/changeling/powers/spiders.dm b/code/game/gamemodes/changeling/powers/spiders.dm new file mode 100644 index 00000000000..52f8ecd31bd --- /dev/null +++ b/code/game/gamemodes/changeling/powers/spiders.dm @@ -0,0 +1,16 @@ +/obj/effect/proc_holder/changeling/spiders + name = "Spread Infestation" + desc = "Our form divides, creating arachnids which will grow into deadly beasts." + helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 5 DNA absorptions." + chemical_cost = 45 + dna_cost = 1 + req_dna = 5 + +//Makes some spiderlings. Good for setting traps and causing general trouble. +/obj/effect/proc_holder/changeling/spiders/sting_action(var/mob/user) + for(var/i=0, i<4, i++) + var/obj/effect/spider/spiderling/S = new(user.loc) + S.grow_as = /mob/living/simple_animal/hostile/giant_spider/hunter + + feedback_add_details("changeling_powers","SI") + return 1 diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm new file mode 100644 index 00000000000..7c5cded0c91 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm @@ -0,0 +1,51 @@ +//Strained Muscles: Temporary speed boost at the cost of rapid damage +//Limited because of hardsuits and such; ideally, used for a quick getaway + +/obj/effect/proc_holder/changeling/strained_muscles + name = "Strained Muscles" + desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster." + helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form." + chemical_cost = 0 + dna_cost = 1 + req_human = 1 + var/stacks = 0 //Increments every 5 seconds; damage increases over time + var/active = 0 //Whether or not you are a hedgehog + +/obj/effect/proc_holder/changeling/strained_muscles/sting_action(var/mob/living/carbon/user) + active = !active + if(active) + user << "Our muscles tense and strengthen." + else + user.status_flags &= ~GOTTAGOFAST + user << "Our muscles relax." + if(stacks >= 10) + user << "We collapse in exhaustion." + user.Weaken(3) + user.emote("gasp") + + while(active) + user.status_flags |= GOTTAGOFAST + if(user.stat || user.staminaloss >= 90) + active = 0 //Let's use something exact instead of !active where we can. + user << "Our muscles relax without the energy to strengthen them." + user.status_flags &= ~GOTTAGOFAST + user.Weaken(2) + user.emote("gasp") + break + + stacks++ + //user.take_organ_damage(stacks * 0.03, 0) + user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack + + if(stacks == 11) //Warning message that the stacks are getting too high + user << "Our legs are really starting to hurt..." + + sleep(40) + + while(!active) //Damage stacks decrease fairly rapidly while not in sanic mode + if(stacks >= 1) + stacks-- + sleep(20) + + feedback_add_details("changeling_powers","SANIC") + return 1 diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm new file mode 100644 index 00000000000..f63fdd6d862 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -0,0 +1,186 @@ +/obj/effect/proc_holder/changeling/sting + name = "Tiny Prick" + desc = "Stabby stabby" + var/sting_icon = null + +/obj/effect/proc_holder/changeling/sting/Click() + var/mob/user = usr + if(!user || !user.mind || !user.mind.changeling) + return + if(!(user.mind.changeling.chosen_sting)) + set_sting(user) + else + unset_sting(user) + return + +/obj/effect/proc_holder/changeling/sting/proc/set_sting(var/mob/user) + user << "We prepare our sting, use alt+click or middle mouse button on target to sting them." + user.mind.changeling.chosen_sting = src + +/obj/effect/proc_holder/changeling/sting/proc/unset_sting(var/mob/user) + user << "We retract our sting, we can't sting anyone for now." + user.mind.changeling.chosen_sting = null + +/mob/living/carbon/proc/unset_sting() + if(mind && mind.changeling && mind.changeling.chosen_sting) + src.mind.changeling.chosen_sting.unset_sting(src) + +/obj/effect/proc_holder/changeling/sting/can_sting(var/mob/user, var/mob/target) + if(!..()) + return + if(!user.mind.changeling.chosen_sting) + user << "We haven't prepared our sting yet!" + if(!iscarbon(target)) + return + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.species.flags & IS_SYNTHETIC) + user << "This won't work on synthetics." + return + if(!isturf(user.loc)) + return + if(get_dist(user, target) > (user.mind.changeling.sting_range)) + return //sanity check as AStar is still throwing insane stunts + if(!AStar(user.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, user.mind.changeling.sting_range)) + return //hope this ancient magic still works + if(target.mind && target.mind.changeling) + sting_feedback(user,target) + take_chemical_cost(user.mind.changeling) + return + return 1 + +/obj/effect/proc_holder/changeling/sting/sting_feedback(var/mob/user, var/mob/target) + if(!target) + return + user << "We stealthily sting [target.name]." + if(target.mind && target.mind.changeling) + target << "You feel a tiny prick." + add_logs(target, user, "unsuccessfully stung") + return 1 + + +/obj/effect/proc_holder/changeling/sting/transformation + name = "Transformation Sting" + desc = "We silently sting a human, injecting a retrovirus that forces them to transform." + helptext = "Does not provide a warning to others. The victim will transform much like a changeling would." + sting_icon = "sting_transform" + chemical_cost = 40 + dna_cost = 2 + var/datum/dna/selected_dna = null + +/obj/effect/proc_holder/changeling/sting/transformation/Click() + var/mob/user = usr + var/datum/changeling/changeling = user.mind.changeling + if(changeling.chosen_sting) + unset_sting(user) + return + selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA") + if(!selected_dna) + return + ..() + +/obj/effect/proc_holder/changeling/sting/transformation/can_sting(var/mob/user, var/mob/target) + if(!..()) + return + if((M_HUSK in target.mutations) || (!ishuman(target) && !ismonkey(target))) + user << "Our sting appears ineffective against its DNA." + return 0 + return 1 + +/obj/effect/proc_holder/changeling/sting/transformation/sting_action(var/mob/user, var/mob/target) + add_logs(target, user, "stung", object="transformation sting", addition=" new identity is [selected_dna.real_name]") + var/datum/dna/NewDNA = selected_dna + if(ismonkey(target)) + user << "We stealthily sting [target.name]." + target.dna = NewDNA.Clone() + target.real_name = NewDNA.real_name + var/mob/living/carbon/human/H = target + if(istype(H)) + H.set_species() + target.UpdateAppearance() + domutcheck(target, null) + feedback_add_details("changeling_powers","TS") + return 1 + +obj/effect/proc_holder/changeling/sting/extract_dna + name = "Extract DNA Sting" + desc = "We stealthily sting a target and extract their DNA." + helptext = "Will give you the DNA of your target, allowing you to transform into them." + sting_icon = "sting_extract" + chemical_cost = 25 + dna_cost = 0 + +/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(var/mob/user, var/mob/target) + if(..()) + return user.mind.changeling.can_absorb_dna(user, target) + +/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(var/mob/user, var/mob/living/carbon/human/target) + add_logs(target, user, "stung", object="extraction sting") + if(!(user.mind.changeling.has_dna(target.dna))) + user.mind.changeling.absorb_dna(target, user) + feedback_add_details("changeling_powers","ED") + return 1 + +obj/effect/proc_holder/changeling/sting/mute + name = "Mute Sting" + desc = "We silently sting a human, completely silencing them for a short time." + helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot." + sting_icon = "sting_mute" + chemical_cost = 20 + dna_cost = 2 + +/obj/effect/proc_holder/changeling/sting/mute/sting_action(var/mob/user, var/mob/living/carbon/target) + add_logs(target, user, "stung", object="mute sting") + target.silent += 30 + feedback_add_details("changeling_powers","MS") + return 1 + +obj/effect/proc_holder/changeling/sting/blind + name = "Blind Sting" + desc = "Temporarily blinds the target." + helptext = "This sting completely blinds a target for a short time." + sting_icon = "sting_blind" + chemical_cost = 25 + dna_cost = 1 + +/obj/effect/proc_holder/changeling/sting/blind/sting_action(var/mob/user, var/mob/target) + add_logs(target, user, "stung", object="blind sting") + target << "Your eyes burn horrifically!" + target.disabilities |= NEARSIGHTED + target.eye_blind = 20 + target.eye_blurry = 40 + feedback_add_details("changeling_powers","BS") + return 1 + +obj/effect/proc_holder/changeling/sting/LSD + name = "Hallucination Sting" + desc = "Causes terror in the target." + helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds." + sting_icon = "sting_lsd" + chemical_cost = 10 + dna_cost = 1 + +/obj/effect/proc_holder/changeling/sting/LSD/sting_action(var/mob/user, var/mob/living/carbon/target) + add_logs(target, user, "stung", object="LSD sting") + spawn(rand(300,600)) + if(target) + target.hallucination = max(400, target.hallucination) + feedback_add_details("changeling_powers","HS") + return 1 +/* +obj/effect/proc_holder/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry. + name = "Cryogenic Sting" + desc = "We silently sting a human with a cocktail of chemicals that freeze them." + helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing." + sting_icon = "sting_cryo" + chemical_cost = 15 + dna_cost = 2 + +/obj/effect/proc_holder/changeling/sting/cryo/sting_action(var/mob/user, var/mob/target) + add_logs(target, user, "stung", object="cryo sting") + if(target.reagents) + target.reagents.add_reagent("frostoil", 30) + target.reagents.add_reagent("ice", 30) + feedback_add_details("changeling_powers","CS") + return 1 +*/ diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm new file mode 100644 index 00000000000..b6a9cf0af30 --- /dev/null +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -0,0 +1,37 @@ +/obj/effect/proc_holder/changeling/transform + name = "Transform" + desc = "We take on the appearance and voice of one we have absorbed." + chemical_cost = 5 + dna_cost = 0 + req_dna = 1 + req_human = 1 + max_genetic_damage = 3 + +//Change our DNA to that of somebody we've absorbed. +/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/human/user) + var/datum/changeling/changeling = user.mind.changeling + var/datum/dna/chosen_dna = changeling.select_dna("Select the target DNA: ", "Target DNA") + + if(!chosen_dna) + return + user.dna = chosen_dna.Clone() + user.real_name = chosen_dna.real_name + user.flavor_text = "" + if(ishuman(user)) + user.set_species() + user.UpdateAppearance() + domutcheck(user, null) + + feedback_add_details("changeling_powers","TR") + return 1 + +/datum/changeling/proc/select_dna(var/prompt, var/title) + var/list/names = list() + for(var/datum/dna/DNA in (absorbed_dna+protected_dna)) + names += "[DNA.real_name]" + + var/chosen_name = input(prompt, title, null) as null|anything in names + if(!chosen_name) + return + var/datum/dna/chosen_dna = GetDNA(chosen_name) + return chosen_dna \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 0f008d9f81a..4daefa505d5 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -898,6 +898,9 @@ var/list/slot_equipment_priority = list( \ continue statpanel(listed_turf.name, null, A) + if(mind && mind.changeling) + add_stings_to_statpanel(mind.changeling.purchasedpowers) + if(spell_list && spell_list.len) for(var/obj/effect/proc_holder/spell/wizard/S in spell_list) switch(S.charge_type) @@ -908,6 +911,11 @@ var/list/slot_equipment_priority = list( \ if("holdervar") statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S) + +/mob/proc/add_stings_to_statpanel(var/list/stings) + for(var/obj/effect/proc_holder/changeling/S in stings) + if(S.chemical_cost >=0 && S.can_be_used_by(src)) + statpanel("[S.panel]",((S.chemical_cost > 0) ? "[S.chemical_cost]" : ""),S) /* // Why have a duplicate set of turfs in the stat panel? if(listed_turf) if(get_dist(listed_turf,src) > 1) diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index f0cc991cef5..a37ad8de5e8 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/in-hand/changeling.dmi b/icons/mob/in-hand/changeling.dmi new file mode 100644 index 00000000000..ab9e0857312 Binary files /dev/null and b/icons/mob/in-hand/changeling.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 254c1abce75..7ec4cacf0d8 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index ab98bbb87be..bf508ef5929 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/paradise.dme b/paradise.dme index 3f3bdb6f14b..5ee05990a7e 100644 --- a/paradise.dme +++ b/paradise.dme @@ -300,9 +300,28 @@ #include "code\game\gamemodes\blob\blobs\shield.dm" #include "code\game\gamemodes\borer\borer.dm" #include "code\game\gamemodes\changeling\changeling.dm" -#include "code\game\gamemodes\changeling\changeling_powers.dm" -#include "code\game\gamemodes\changeling\modularchangling.dm" +#include "code\game\gamemodes\changeling\changeling_power.dm" +#include "code\game\gamemodes\changeling\evolution_menu.dm" #include "code\game\gamemodes\changeling\traitor_chan.dm" +#include "code\game\gamemodes\changeling\powers\absorb.dm" +#include "code\game\gamemodes\changeling\powers\augmented_eyesight.dm" +#include "code\game\gamemodes\changeling\powers\digitalcamo.dm" +#include "code\game\gamemodes\changeling\powers\epinephrine.dm" +#include "code\game\gamemodes\changeling\powers\fakedeath.dm" +#include "code\game\gamemodes\changeling\powers\fleshmend.dm" +#include "code\game\gamemodes\changeling\powers\glands.dm" +#include "code\game\gamemodes\changeling\powers\hivemind.dm" +#include "code\game\gamemodes\changeling\powers\humanform.dm" +#include "code\game\gamemodes\changeling\powers\lesserform.dm" +#include "code\game\gamemodes\changeling\powers\mimic_voice.dm" +#include "code\game\gamemodes\changeling\powers\mutations.dm" +#include "code\game\gamemodes\changeling\powers\panacea.dm" +#include "code\game\gamemodes\changeling\powers\revive.dm" +#include "code\game\gamemodes\changeling\powers\shriek.dm" +#include "code\game\gamemodes\changeling\powers\spiders.dm" +#include "code\game\gamemodes\changeling\powers\strained_muscles.dm" +#include "code\game\gamemodes\changeling\powers\tiny_prick.dm" +#include "code\game\gamemodes\changeling\powers\transform.dm" #include "code\game\gamemodes\cult\cult.dm" #include "code\game\gamemodes\cult\cult_items.dm" #include "code\game\gamemodes\cult\cult_structures.dm"