diff --git a/code/datums/antagonists/changeling.dm b/code/datums/antagonists/changeling.dm
new file mode 100644
index 0000000000..7a3dba2cf3
--- /dev/null
+++ b/code/datums/antagonists/changeling.dm
@@ -0,0 +1,483 @@
+#define LING_FAKEDEATH_TIME 400 //40 seconds
+#define LING_DEAD_GENETICDAMAGE_HEAL_CAP 50 //The lowest value of geneticdamage handle_changeling() can take it to while dead.
+#define LING_ABSORB_RECENT_SPEECH 8 //The amount of recent spoken lines to gain on absorbing a mob
+
+/datum/antagonist/changeling
+ name = "Changeling"
+ job_rank = ROLE_CHANGELING
+
+ var/you_are_greet = TRUE
+ var/give_objectives = TRUE
+ var/list/objectives = list()
+ var/team_mode = FALSE //Should assign team objectives ?
+
+ //Changeling Stuff
+
+ var/list/stored_profiles = list() //list of datum/changelingprofile
+ var/datum/changelingprofile/first_prof = null
+ //var/list/absorbed_dna = list()
+ //var/list/protected_dna = list() //dna that is not lost when capacity is otherwise full
+ var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
+ var/absorbedcount = 0
+ var/chem_charges = 20
+ var/chem_storage = 75
+ var/chem_recharge_rate = 1
+ var/chem_recharge_slowdown = 0
+ var/sting_range = 2
+ var/changelingID = "Changeling"
+ var/geneticdamage = 0
+ var/isabsorbing = 0
+ var/islinking = 0
+ 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
+ var/datum/cellular_emporium/cellular_emporium
+ var/datum/action/innate/cellular_emporium/emporium_action
+
+ // wip stuff
+ var/static/list/all_powers = typecacheof(/obj/effect/proc_holder/changeling,TRUE)
+
+
+/datum/antagonist/changeling/New()
+ . = ..()
+ generate_name()
+ create_actions()
+
+/datum/antagonist/changeling/Destroy()
+ QDEL_NULL(cellular_emporium)
+ QDEL_NULL(emporium_action)
+ . = ..()
+
+/datum/antagonist/changeling/proc/generate_name()
+ var/honorific
+ if(owner.current.gender == FEMALE)
+ honorific = "Ms."
+ else
+ honorific = "Mr."
+ if(GLOB.possible_changeling_IDs.len)
+ changelingID = pick(GLOB.possible_changeling_IDs)
+ GLOB.possible_changeling_IDs -= changelingID
+ changelingID = "[honorific] [changelingID]"
+ else
+ changelingID = "[honorific] [rand(1,999)]"
+
+/datum/antagonist/changeling/proc/create_actions()
+ cellular_emporium = new(src)
+ emporium_action = new(cellular_emporium)
+
+/datum/antagonist/changeling/on_gain()
+ reset_powers()
+ create_initial_profile()
+ if(give_objectives)
+ if(team_mode)
+ forge_team_objectives()
+ forge_objectives()
+ remove_clownmut()
+ . = ..()
+
+/datum/antagonist/changeling/on_removal()
+ remove_changeling_powers()
+ owner.objectives -= objectives
+ . = ..()
+
+/datum/antagonist/changeling/proc/remove_clownmut()
+ if (owner)
+ var/mob/living/carbon/human/H = owner.current
+ if(istype(H) && owner.assigned_role == "Clown")
+ to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
+ H.dna.remove_mutation(CLOWNMUT)
+
+/datum/antagonist/changeling/proc/reset_properties()
+ changeling_speak = 0
+ 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 = ""
+
+/datum/antagonist/changeling/proc/remove_changeling_powers()
+ if(ishuman(owner.current) || ismonkey(owner.current))
+ reset_properties()
+ for(var/obj/effect/proc_holder/changeling/p in purchasedpowers)
+ if(p.always_keep)
+ continue
+ purchasedpowers -= p
+ p.on_refund(owner.current)
+
+ //MOVE THIS
+ if(owner.current.hud_used)
+ owner.current.hud_used.lingstingdisplay.icon_state = null
+ owner.current.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
+
+/datum/antagonist/changeling/proc/reset_powers()
+ if(purchasedpowers)
+ remove_changeling_powers()
+ //Repurchase free powers.
+ for(var/path in all_powers)
+ var/obj/effect/proc_holder/changeling/S = new path()
+ if(!S.dna_cost)
+ if(!has_sting(S))
+ purchasedpowers += S
+ S.on_purchase(owner.current,TRUE)
+
+/datum/antagonist/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power)
+ for(var/obj/effect/proc_holder/changeling/P in purchasedpowers)
+ if(initial(power.name) == P.name)
+ return TRUE
+ return FALSE
+
+
+/datum/antagonist/changeling/proc/purchase_power(sting_name)
+ var/obj/effect/proc_holder/changeling/thepower = null
+
+ for(var/path in all_powers)
+ var/obj/effect/proc_holder/changeling/S = path
+ if(initial(S.name) == sting_name)
+ thepower = new path()
+ break
+
+ if(!thepower)
+ to_chat(owner.current, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
+ return
+
+ if(absorbedcount < thepower.req_dna)
+ to_chat(owner.current, "We lack the energy to evolve this ability!")
+ return
+
+ if(has_sting(thepower))
+ to_chat(owner.current, "We have already evolved this ability!")
+ return
+
+ if(thepower.dna_cost < 0)
+ to_chat(owner.current, "We cannot evolve this ability.")
+ return
+
+ if(geneticpoints < thepower.dna_cost)
+ to_chat(owner.current, "We have reached our capacity for abilities.")
+ return
+
+ if(owner.current.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
+ to_chat(owner.current, "We lack the energy to evolve new abilities right now.")
+ return
+
+ geneticpoints -= thepower.dna_cost
+ purchasedpowers += thepower
+ thepower.on_purchase(owner.current)
+
+/datum/antagonist/changeling/proc/readapt()
+ if(!ishuman(owner.current))
+ to_chat(owner.current, "We can't remove our evolutions in this form!")
+ return
+ if(canrespec)
+ to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.")
+ reset_powers()
+ canrespec = 0
+ SSblackbox.add_details("changeling_power_purchase","Readapt")
+ return 1
+ else
+ to_chat(owner.current, "You lack the power to readapt your evolutions!")
+ return 0
+
+//Called in life()
+/datum/antagonist/changeling/proc/regenerate()
+ var/mob/living/carbon/the_ling = owner.current
+ if(istype(the_ling))
+ emporium_action.Grant(the_ling)
+ if(the_ling.stat == DEAD)
+ chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), (chem_storage*0.5))
+ geneticdamage = max(LING_DEAD_GENETICDAMAGE_HEAL_CAP,geneticdamage-1)
+ else //not dead? no chem/geneticdamage caps.
+ chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), chem_storage)
+ geneticdamage = max(0, geneticdamage-1)
+
+
+/datum/antagonist/changeling/proc/get_dna(dna_owner)
+ for(var/datum/changelingprofile/prof in stored_profiles)
+ if(dna_owner == prof.name)
+ return prof
+
+/datum/antagonist/changeling/proc/has_dna(datum/dna/tDNA)
+ for(var/datum/changelingprofile/prof in stored_profiles)
+ if(tDNA.is_same_as(prof.dna))
+ return TRUE
+ return FALSE
+
+/datum/antagonist/changeling/proc/can_absorb_dna(mob/living/carbon/human/target, var/verbose=1)
+ var/mob/living/carbon/user = owner.current
+ if(!istype(user))
+ return
+ if(stored_profiles.len)
+ var/datum/changelingprofile/prof = stored_profiles[1]
+ if(prof.dna == user.dna && stored_profiles.len >= dna_max)//If our current DNA is the stalest, we gotta ditch it.
+ if(verbose)
+ to_chat(user, "We have reached our capacity to store genetic information! We must transform before absorbing more.")
+ return
+ if(!target)
+ return
+ if(NO_DNA_COPY in target.dna.species.species_traits)
+ if(verbose)
+ to_chat(user, "[target] is not compatible with our biology.")
+ return
+ if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
+ if(verbose)
+ to_chat(user, "DNA of [target] is ruined beyond usability!")
+ return
+ if(!ishuman(target))//Absorbing monkeys is entirely possible, but it can cause issues with transforming. That's what lesser form is for anyway!
+ if(verbose)
+ to_chat(user, "We could gain no benefit from absorbing a lesser creature.")
+ return
+ if(has_dna(target.dna))
+ if(verbose)
+ to_chat(user, "We already have this DNA in storage!")
+ return
+ if(!target.has_dna())
+ if(verbose)
+ to_chat(user, "[target] is not compatible with our biology.")
+ return
+ return 1
+
+
+/datum/antagonist/changeling/proc/create_profile(mob/living/carbon/human/H, protect = 0)
+ var/datum/changelingprofile/prof = new
+
+ H.dna.real_name = H.real_name //Set this again, just to be sure that it's properly set.
+ var/datum/dna/new_dna = new H.dna.type
+ H.dna.copy_dna(new_dna)
+ prof.dna = new_dna
+ prof.name = H.real_name
+ prof.protected = protect
+
+ prof.underwear = H.underwear
+ prof.undershirt = H.undershirt
+ prof.socks = H.socks
+
+ var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store")
+ for(var/slot in slots)
+ if(slot in H.vars)
+ var/obj/item/I = H.vars[slot]
+ if(!I)
+ continue
+ prof.name_list[slot] = I.name
+ prof.appearance_list[slot] = I.appearance
+ prof.flags_cover_list[slot] = I.flags_cover
+ prof.item_color_list[slot] = I.item_color
+ prof.item_state_list[slot] = I.item_state
+ prof.exists_list[slot] = 1
+ else
+ continue
+
+ return prof
+
+/datum/antagonist/changeling/proc/add_profile(datum/changelingprofile/prof)
+ if(stored_profiles.len > dna_max)
+ if(!push_out_profile())
+ return
+
+ if(!first_prof)
+ first_prof = prof
+
+ stored_profiles += prof
+ absorbedcount++
+
+/datum/antagonist/changeling/proc/add_new_profile(mob/living/carbon/human/H, protect = 0)
+ var/datum/changelingprofile/prof = create_profile(H, protect)
+ add_profile(prof)
+ return prof
+
+/datum/antagonist/changeling/proc/remove_profile(mob/living/carbon/human/H, force = 0)
+ for(var/datum/changelingprofile/prof in stored_profiles)
+ if(H.real_name == prof.name)
+ if(prof.protected && !force)
+ continue
+ stored_profiles -= prof
+ qdel(prof)
+
+/datum/antagonist/changeling/proc/get_profile_to_remove()
+ for(var/datum/changelingprofile/prof in stored_profiles)
+ if(!prof.protected)
+ return prof
+
+/datum/antagonist/changeling/proc/push_out_profile()
+ var/datum/changelingprofile/removeprofile = get_profile_to_remove()
+ if(removeprofile)
+ stored_profiles -= removeprofile
+ return 1
+ return 0
+
+
+/datum/antagonist/changeling/proc/create_initial_profile()
+ var/mob/living/carbon/C = owner.current //only carbons have dna now, so we have to typecaste
+ if(ishuman(C))
+ add_new_profile(C)
+
+/datum/antagonist/changeling/apply_innate_effects()
+ //Brains optional.
+ var/mob/living/carbon/C = owner.current
+ if(istype(C))
+ var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
+ if(B)
+ B.vital = FALSE
+ B.decoy_override = TRUE
+ update_changeling_icons_added()
+ return
+
+/datum/antagonist/changeling/remove_innate_effects()
+ update_changeling_icons_removed()
+ return
+
+
+/datum/antagonist/changeling/greet()
+ if (you_are_greet)
+ to_chat(owner.current, "You are [changelingID], a changeling! You have absorbed and taken the form of a human.")
+ to_chat(owner.current, "Use say \":g message\" to communicate with your fellow changelings.")
+ to_chat(owner.current, "You must complete the following tasks:")
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
+
+ owner.announce_objectives()
+
+/datum/antagonist/changeling/proc/forge_team_objectives()
+ if(GLOB.changeling_team_objective_type)
+ var/datum/objective/changeling_team_objective/team_objective = new GLOB.changeling_team_objective_type
+ team_objective.owner = owner
+ objectives += team_objective
+ return
+
+/datum/antagonist/changeling/proc/forge_objectives()
+ //OBJECTIVES - random traitor objectives. Unique objectives "steal brain" and "identity theft".
+ //No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting
+ //If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone
+
+ var/escape_objective_possible = TRUE
+
+ //if there's a team objective, check if it's compatible with escape objectives
+ for(var/datum/objective/changeling_team_objective/CTO in objectives)
+ if(!CTO.escape_objective_compatible)
+ escape_objective_possible = FALSE
+ break
+
+ var/datum/objective/absorb/absorb_objective = new
+ absorb_objective.owner = owner
+ absorb_objective.gen_amount_goal(6, 8)
+ objectives += absorb_objective
+
+ if(prob(60))
+ if(prob(85))
+ var/datum/objective/steal/steal_objective = new
+ steal_objective.owner = owner
+ steal_objective.find_target()
+ objectives += steal_objective
+ else
+ var/datum/objective/download/download_objective = new
+ download_objective.owner = owner
+ download_objective.gen_amount_goal()
+ objectives += download_objective
+
+ var/list/active_ais = active_ais()
+ if(active_ais.len && prob(100/GLOB.joined_player_list.len))
+ var/datum/objective/destroy/destroy_objective = new
+ destroy_objective.owner = owner
+ destroy_objective.find_target()
+ objectives += destroy_objective
+ else
+ if(prob(70))
+ var/datum/objective/assassinate/kill_objective = new
+ kill_objective.owner = owner
+ if(team_mode) //No backstabbing while in a team
+ kill_objective.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
+ else
+ kill_objective.find_target()
+ objectives += kill_objective
+ else
+ var/datum/objective/maroon/maroon_objective = new
+ maroon_objective.owner = owner
+ if(team_mode)
+ maroon_objective.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
+ else
+ maroon_objective.find_target()
+ objectives += maroon_objective
+
+ if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
+ var/datum/objective/escape/escape_with_identity/identity_theft = new
+ identity_theft.owner = owner
+ identity_theft.target = maroon_objective.target
+ identity_theft.update_explanation_text()
+ objectives += identity_theft
+ escape_objective_possible = FALSE
+
+ if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
+ if(prob(50))
+ var/datum/objective/escape/escape_objective = new
+ escape_objective.owner = owner
+ objectives += escape_objective
+ else
+ var/datum/objective/escape/escape_with_identity/identity_theft = new
+ identity_theft.owner = owner
+ if(team_mode)
+ identity_theft.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
+ else
+ identity_theft.find_target()
+ objectives += identity_theft
+ escape_objective_possible = FALSE
+
+ owner.objectives |= objectives
+
+/datum/antagonist/changeling/proc/update_changeling_icons_added()
+ var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
+ hud.join_hud(owner.current)
+ set_antag_hud(owner.current, "changling")
+
+/datum/antagonist/changeling/proc/update_changeling_icons_removed()
+ var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
+ hud.leave_hud(owner.current)
+ set_antag_hud(owner.current, null)
+
+// Profile
+
+/datum/changelingprofile
+ var/name = "a bug"
+
+ var/protected = 0
+
+ var/datum/dna/dna = null
+ var/list/name_list = list() //associative list of slotname = itemname
+ var/list/appearance_list = list()
+ var/list/flags_cover_list = list()
+ var/list/exists_list = list()
+ var/list/item_color_list = list()
+ var/list/item_state_list = list()
+
+ var/underwear
+ var/undershirt
+ var/socks
+
+/datum/changelingprofile/Destroy()
+ qdel(dna)
+ . = ..()
+
+/datum/changelingprofile/proc/copy_profile(datum/changelingprofile/newprofile)
+ newprofile.name = name
+ newprofile.protected = protected
+ newprofile.dna = new dna.type
+ dna.copy_dna(newprofile.dna)
+ newprofile.name_list = name_list.Copy()
+ newprofile.appearance_list = appearance_list.Copy()
+ newprofile.flags_cover_list = flags_cover_list.Copy()
+ newprofile.exists_list = exists_list.Copy()
+ newprofile.item_color_list = item_color_list.Copy()
+ newprofile.item_state_list = item_state_list.Copy()
+ newprofile.underwear = underwear
+ newprofile.undershirt = undershirt
+ newprofile.socks = socks
+
+
+/datum/antagonist/changeling/xenobio
+ name = "Xenobio Changeling"
+ give_objectives = FALSE
+ you_are_greet = FALSE
\ No newline at end of file