var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega") /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) var/list/datum/absorbed_dna/absorbed_dna = list() var/list/absorbed_languages = list() var/list/hivemind_members = list() var/absorbedcount = 0 var/chem_charges = 20 var/chem_recharge_rate = 0.5 var/chem_storage = 50 var/sting_range = 1 var/changelingID = "Changeling" var/geneticdamage = 0 var/isabsorbing = 0 var/geneticpoints = 5 var/list/purchasedpowers = list() var/mimicing = "" var/mimiced_accent = "Biesellite" var/justate /datum/changeling/New(var/gender=FEMALE) ..() var/honorific = (gender == FEMALE) ? "Ms." : "Mr." if(possible_changeling_IDs.len) changelingID = pick(possible_changeling_IDs) possible_changeling_IDs -= changelingID changelingID = "[honorific] [changelingID]" else changelingID = "[honorific] [rand(1,999)]" /datum/changeling/proc/regenerate() chem_charges = min(max(0, chem_charges + chem_recharge_rate), chem_storage) geneticdamage = max(0, geneticdamage - 1) /datum/changeling/proc/GetDNA(var/dna_owner) for(var/datum/absorbed_dna/DNA in absorbed_dna) if(dna_owner == DNA.name) return DNA /mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA) var/datum/changeling/changeling = null if(src.mind && src.mind.changeling) changeling = src.mind.changeling if(!changeling) return for(var/language in newDNA.languages) changeling.absorbed_languages |= language changeling_update_languages(changeling.absorbed_languages) if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite changeling.absorbed_dna += newDNA //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) verbs += /datum/changeling/proc/EvolutionMenu add_language("Changeling") 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 for(var/language in languages) mind.changeling.absorbed_languages |= language var/mob/living/carbon/human/H = src if(istype(H)) var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.get_cloning_variant(), H.languages) absorbDNA(newDNA) mind.changeling.mimiced_accent = H.accent return TRUE //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) log_and_message_admins("has the changeling_transform() verb but is not a changeling.", src, get_turf(src)) return if(src.stat > max_stat) to_chat(src, "We are incapacitated.") return if(changeling.absorbed_dna.len < required_dna) to_chat(src, "We require at least [required_dna] samples of compatible DNA.") return if(changeling.chem_charges < required_chems) to_chat(src, "We require at least [required_chems] units of chemicals to do that!") return if(changeling.geneticdamage > max_genetic_damage) to_chat(src, "Our genomes 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 //This isn't strictly necessary but just to be safe... add_language("Changeling") return //DNA related datums /datum/absorbed_dna var/name var/datum/dna/dna var/speciesName var/list/languages /datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages) ..() name = newName dna = newDNA speciesName = newSpecies languages = newLanguages //Helper for stingcode /mob/proc/sting_can_reach(mob/M as mob, sting_range = 1) if(M.loc == src.loc) return TRUE //target and source are in the same thing if(!isturf(src.loc) || !isturf(M.loc)) to_chat(src, "We cannot reach \the [M] with a sting!") return FALSE //One is inside, the other is outside something. // Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail to_chat(src, "We cannot find a path to sting \the [M] by!") return FALSE return TRUE