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