Ling datum antag standarization. (#32183)

* Ling datum standarization.

* Removal of redundant file

* Ok
This commit is contained in:
AnturK
2017-11-06 02:32:37 +01:00
committed by Jordan Brown
parent f6e7a7f249
commit 70d0357b33
38 changed files with 707 additions and 655 deletions

View File

@@ -282,10 +282,12 @@
return
/mob/living/carbon/MiddleClickOn(atom/A)
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (iscarbon(A)) && (A != src))
if(!stat && mind && iscarbon(A) && A != src)
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
mind.changeling.chosen_sting.try_to_sting(src, A)
else
return
swap_hand()
/mob/living/simple_animal/drone/MiddleClickOn(atom/A)
@@ -344,10 +346,12 @@
return
/mob/living/carbon/AltClickOn(atom/A)
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (iscarbon(A)) && (A != src))
if(!stat && mind && iscarbon(A) && A != src)
var/datum/antagonist/changeling/C = mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.chosen_sting)
C.chosen_sting.try_to_sting(src,A)
next_click = world.time + 5
mind.changeling.chosen_sting.try_to_sting(src, A)
else
return
..()
/atom/proc/AltClick(mob/user)

View File

@@ -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(FALSE)
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(keep_free_powers=0)
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
for(var/obj/effect/proc_holder/changeling/p in purchasedpowers)
if((p.dna_cost == 0 && keep_free_powers) || 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(TRUE)
//Purchase 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, "<span class='danger'>We can't remove our evolutions in this form!</span>")
return
if(canrespec)
to_chat(owner.current, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
reset_powers()
canrespec = 0
SSblackbox.add_details("changeling_power_purchase","Readapt")
return 1
else
to_chat(owner.current, "<span class='danger'>You lack the power to readapt your evolutions!</span>")
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, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
if(!target)
return
if(NO_DNA_COPY in target.dna.species.species_traits)
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
if(verbose)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
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, "<span class='warning'>We could gain no benefit from absorbing a lesser creature.</span>")
return
if(has_dna(target.dna))
if(verbose)
to_chat(user, "<span class='warning'>We already have this DNA in storage!</span>")
return
if(!target.has_dna())
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
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, "<span class='boldannounce'>You are [changelingID], a changeling! You have absorbed and taken the form of a human.</span>")
to_chat(owner.current, "<span class='boldannounce'>Use say \":g message\" to communicate with your fellow changelings.</span>")
to_chat(owner.current, "<b>You must complete the following tasks:</b>")
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

View File

@@ -187,15 +187,10 @@
qdel(O)
/datum/mind/proc/remove_changeling()
if(src in SSticker.mode.changelings)
SSticker.mode.changelings -= src
current.remove_changeling_powers()
if(changeling)
qdel(changeling)
changeling = null
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
remove_antag_datum(/datum/antagonist/changeling)
special_role = null
remove_antag_equip()
SSticker.mode.update_changeling_icons_removed(src)
/datum/mind/proc/remove_traitor()
if(src in SSticker.mode.traitors)
@@ -251,7 +246,6 @@
remove_wizard()
remove_cultist()
remove_rev()
SSticker.mode.update_changeling_icons_removed(src)
SSticker.mode.update_traitor_icons_removed(src)
SSticker.mode.update_cult_icons_removed(src)
@@ -444,17 +438,12 @@
if (SSticker.mode.config_tag=="changeling" || SSticker.mode.config_tag=="traitorchan")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in SSticker.mode.changelings) && special_role)
text += "<b>YES</b> | <a href='?src=[REF(src)];changeling=clear'>no</a>"
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
text += "<b>[C.name]</b> | <a href='?src=[REF(src)];changeling=clear'>No</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=[REF(src)];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=[REF(src)];changeling=initialdna'>Transform to initial appearance.</a>"
else if(src in SSticker.mode.changelings) //Station Aligned Changeling
text += "<b>YES (but not an antag)</b> | <a href='?src=[REF(src)];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=[REF(src)];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
if(C.stored_profiles.len && (current.real_name != C.first_prof.name) )
text += "<br><a href='?src=[REF(src)];changeling=initialdna'>Transform to initial appearance.</a>"
else
text += "<a href='?src=[REF(src)];changeling=changeling'>yes</a> | <b>NO</b>"
@@ -1040,30 +1029,29 @@
else if (href_list["changeling"])
switch(href_list["changeling"])
if("clear")
remove_changeling()
remove_antag_datum(/datum/antagonist/changeling)
special_role = null
to_chat(current, "<span class='userdanger'>You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!</span>")
message_admins("[key_name_admin(usr)] has de-changeling'ed [current].")
log_admin("[key_name(usr)] has de-changeling'ed [current].")
if("changeling")
if(!(src in SSticker.mode.changelings))
SSticker.mode.changelings += src
current.make_changeling()
special_role = "Changeling"
to_chat(current, "<span class='boldannounce'>Your powers are awoken. A flash of memory returns to us...we are [changeling.changelingID], a changeling!</span>")
var/datum/antagonist/changeling/C = make_Changling()
to_chat(current, "<span class='boldannounce'>Your powers are awoken. A flash of memory returns to us...we are [C.changelingID], a changeling!</span>")
message_admins("[key_name_admin(usr)] has changeling'ed [current].")
log_admin("[key_name(usr)] has changeling'ed [current].")
SSticker.mode.update_changeling_icons_added(src)
if("autoobjectives")
SSticker.mode.forge_changeling_objectives(src)
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(C)
C.forge_objectives()
to_chat(usr, "<span class='notice'>The objectives for changeling [key] have been generated. You can edit them and anounce manually.</span>")
if("initialdna")
if( !changeling || !changeling.stored_profiles.len || !iscarbon(current))
var/datum/antagonist/changeling/ling = has_antag_datum(/datum/antagonist/changeling)
if( !ling || !ling.stored_profiles.len || !iscarbon(current))
to_chat(usr, "<span class='danger'>Resetting DNA failed!</span>")
else
var/mob/living/carbon/C = current
changeling.first_prof.dna.transfer_identity(C, transfer_SE=1)
C.real_name = changeling.first_prof.name
ling.first_prof.dna.transfer_identity(C, transfer_SE=1)
C.real_name = ling.first_prof.name
C.updateappearance(mutcolor_update=1)
C.domutcheck()
@@ -1398,13 +1386,11 @@
current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
/datum/mind/proc/make_Changling()
if(!(src in SSticker.mode.changelings))
SSticker.mode.changelings += src
current.make_changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(!C)
C = add_antag_datum(/datum/antagonist/changeling)
special_role = "Changeling"
SSticker.mode.forge_changeling_objectives(src)
SSticker.mode.greet_changeling(src)
SSticker.mode.update_changeling_icons_added(src)
return C
/datum/mind/proc/make_Wizard()
if(!has_antag_datum(/datum/antagonist/wizard))

View File

@@ -3,7 +3,7 @@
/datum/cellular_emporium
var/name = "cellular emporium"
var/datum/changeling/changeling
var/datum/antagonist/changeling/changeling
/datum/cellular_emporium/New(my_changeling)
. = ..()
@@ -32,7 +32,7 @@
var/list/abilities = list()
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
for(var/path in changeling.all_powers)
var/obj/effect/proc_holder/changeling/ability = path
var/dna_cost = initial(ability.dna_cost)
@@ -61,10 +61,10 @@
switch(action)
if("readapt")
if(changeling.canrespec)
changeling.lingRespec(usr)
changeling.readapt()
if("evolve")
var/sting_name = params["name"]
changeling.purchasePower(usr, sting_name)
changeling.purchase_power(sting_name)
/datum/action/innate/cellular_emporium
name = "Cellular Emporium"

View File

@@ -1,15 +1,8 @@
#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
GLOBAL_LIST_INIT(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"))
GLOBAL_LIST_INIT(slots, list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store"))
GLOBAL_LIST_INIT(slot2slot, list("head" = slot_head, "wear_mask" = slot_wear_mask, "neck" = slot_neck, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store))
GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "wear_mask" = /obj/item/clothing/mask/changeling, "back" = /obj/item/changeling, "wear_suit" = /obj/item/clothing/suit/changeling, "w_uniform" = /obj/item/clothing/under/changeling, "shoes" = /obj/item/clothing/shoes/changeling, "belt" = /obj/item/changeling, "gloves" = /obj/item/clothing/gloves/changeling, "glasses" = /obj/item/clothing/glasses/changeling, "ears" = /obj/item/changeling, "wear_id" = /obj/item/changeling, "s_store" = /obj/item/changeling))
/datum/game_mode
var/list/datum/mind/changelings = list()
GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our this objective to all lings
/datum/game_mode/changeling
@@ -29,26 +22,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
<span class='green'>Changelings</span>: Accomplish the objectives assigned to you.\n\
<span class='notice'>Crew</span>: Root out and eliminate the changeling menace."
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target
var/const/prob_int_item = 50 // intercept names the theft target half the time
var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target
var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target
var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time
var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target
var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target
var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative
var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative
var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly
var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly
var/const/changeling_amount = 4 //hard limit on changelings if scaling is turned off
var/changeling_team_objective_type = null //If this is not null, we hand our this objective to all lings
var/list/changelings = list()
/datum/game_mode/changeling/pre_setup()
@@ -80,7 +55,6 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
return 0
/datum/game_mode/changeling/post_setup()
//Decide if it's ok for the lings to have a team objective
//And then set it up to be handed out in forge_changeling_objectives
var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective)
@@ -92,116 +66,27 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
possible_team_objectives += T
if(possible_team_objectives.len && prob(20*changelings.len))
changeling_team_objective_type = pick(possible_team_objectives)
GLOB.changeling_team_objective_type = pick(possible_team_objectives)
for(var/datum/mind/changeling in changelings)
log_game("[changeling.key] (ckey) has been selected as a changeling")
changeling.current.make_changeling()
forge_changeling_objectives(changeling)
greet_changeling(changeling)
SSticker.mode.update_changeling_icons_added(changeling)
var/datum/antagonist/changeling/new_antag = new(changeling)
new_antag.team_mode = TRUE
changeling.add_antag_datum(new_antag)
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
/datum/game_mode/proc/forge_changeling_objectives(datum/mind/changeling, var/team_mode = 0)
//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 changeling.objectives)
if(!CTO.escape_objective_compatible)
escape_objective_possible = FALSE
break
var/datum/objective/absorb/absorb_objective = new
absorb_objective.owner = changeling
absorb_objective.gen_amount_goal(6, 8)
changeling.objectives += absorb_objective
if(prob(60))
if(prob(85))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
else
var/datum/objective/download/download_objective = new
download_objective.owner = changeling
download_objective.gen_amount_goal()
changeling.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 = changeling
destroy_objective.find_target()
changeling.objectives += destroy_objective
else
if(prob(70))
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = changeling
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()
changeling.objectives += kill_objective
else
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = changeling
if(team_mode)
maroon_objective.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
else
maroon_objective.find_target()
changeling.objectives += maroon_objective
if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible)
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = changeling
identity_theft.target = maroon_objective.target
identity_theft.update_explanation_text()
changeling.objectives += identity_theft
escape_objective_possible = FALSE
if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible)
if(prob(50))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = changeling
changeling.objectives += escape_objective
else
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = changeling
if(team_mode)
identity_theft.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
else
identity_theft.find_target()
changeling.objectives += identity_theft
escape_objective_possible = FALSE
/datum/game_mode/changeling/forge_changeling_objectives(datum/mind/changeling)
if(changeling_team_objective_type)
var/datum/objective/changeling_team_objective/team_objective = new changeling_team_objective_type
team_objective.owner = changeling
changeling.objectives += team_objective
..(changeling,1)
else
..(changeling,0)
changelings += character.mind
/datum/game_mode/changeling/generate_report()
return "The Gorlex Marauders have announced the successful raid and destruction of Central Command containment ship #S-[rand(1111, 9999)]. This ship housed only a single prisoner - \
@@ -209,29 +94,12 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
as paranoia may spread and inhibit workplace efficiency."
/datum/game_mode/proc/greet_changeling(datum/mind/changeling, you_are=1)
if (you_are)
to_chat(changeling.current, "<span class='boldannounce'>You are [changeling.changeling.changelingID], a changeling! You have absorbed and taken the form of a human.</span>")
to_chat(changeling.current, "<span class='boldannounce'>Use say \":g message\" to communicate with your fellow changelings.</span>")
to_chat(changeling.current, "<b>You must complete the following tasks:</b>")
changeling.current.playsound_local(get_turf(changeling.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
if (changeling.current.mind)
var/mob/living/carbon/human/H = changeling.current
if(H.mind.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)
var/obj_count = 1
for(var/datum/objective/objective in changeling.objectives)
to_chat(changeling.current, "<b>Objective #[obj_count]</b>: [objective.explanation_text]")
obj_count++
return
/datum/game_mode/proc/auto_declare_completion_changeling()
var/list/changelings = get_antagonists(/datum/antagonist/changeling,TRUE) //Only real lings get a mention
if(changelings.len)
var/text = "<br><font size=3><b>The changelings were:</b></font>"
for(var/datum/mind/changeling in changelings)
var/datum/antagonist/changeling/ling = changeling.has_antag_datum(/datum/antagonist/changeling)
var/changelingwin = 1
if(!changeling.current)
changelingwin = 0
@@ -239,8 +107,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
text += printplayer(changeling)
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
text += "<br><b>Changeling ID:</b> [changeling.changeling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [changeling.changeling.absorbedcount]"
text += "<br><b>Changeling ID:</b> [ling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [ling.absorbedcount]"
if(changeling.objectives.len)
var/count = 1
@@ -264,176 +132,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
to_chat(world, text)
return 1
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
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
/datum/changeling/New(var/gender=FEMALE)
..()
var/honorific
if(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)]"
cellular_emporium = new(src)
emporium_action = new(cellular_emporium)
/datum/changeling/Destroy()
qdel(cellular_emporium)
cellular_emporium = null
qdel(emporium_action)
emporium_action = null
. = ..()
/datum/changeling/proc/regenerate(var/mob/living/carbon/the_ling)
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/changeling/proc/get_dna(dna_owner)
for(var/datum/changelingprofile/prof in stored_profiles)
if(dna_owner == prof.name)
return prof
/datum/changeling/proc/has_dna(datum/dna/tDNA)
for(var/datum/changelingprofile/prof in stored_profiles)
if(tDNA.is_same_as(prof.dna))
return 1
return 0
/datum/changeling/proc/can_absorb_dna(mob/living/carbon/user, mob/living/carbon/human/target, var/verbose=1)
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, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
if(!target)
return
if(NO_DNA_COPY in target.dna.species.species_traits)
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
if(verbose)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
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, "<span class='warning'>We could gain no benefit from absorbing a lesser creature.</span>")
return
if(has_dna(target.dna))
if(verbose)
to_chat(user, "<span class='warning'>We already have this DNA in storage!</span>")
return
if(!target.has_dna())
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
return 1
/datum/changeling/proc/create_profile(mob/living/carbon/human/H, mob/living/carbon/human/user, 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/changeling/proc/add_profile(datum/changelingprofile/prof)
if(stored_profiles.len > dna_max)
if(!push_out_profile())
return
stored_profiles += prof
absorbedcount++
/datum/changeling/proc/add_new_profile(mob/living/carbon/human/H, mob/living/carbon/human/user, protect = 0)
var/datum/changelingprofile/prof = create_profile(H, protect)
add_profile(prof)
return prof
/datum/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/changeling/proc/get_profile_to_remove()
for(var/datum/changelingprofile/prof in stored_profiles)
if(!prof.protected)
return prof
/datum/changeling/proc/push_out_profile()
var/datum/changelingprofile/removeprofile = get_profile_to_remove()
if(removeprofile)
stored_profiles -= removeprofile
return 1
return 0
/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof)
var/datum/dna/chosen_dna = chosen_prof.dna
user.real_name = chosen_prof.name
@@ -474,49 +174,3 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
user.equip_to_slot_or_del(C, GLOB.slot2slot[slot])
user.regenerate_icons()
/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/game_mode/proc/update_changeling_icons_added(datum/mind/changling_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.join_hud(changling_mind.current)
set_antag_hud(changling_mind.current, "changling")
/datum/game_mode/proc/update_changeling_icons_removed(datum/mind/changling_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.leave_hud(changling_mind.current)
set_antag_hud(changling_mind.current, null)

View File

@@ -26,14 +26,14 @@
/obj/effect/proc_holder/changeling/Click()
var/mob/user = usr
if(!user || !user.mind || !user.mind.changeling)
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
return
try_to_sting(user)
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
if(!can_sting(user, target))
return
var/datum/changeling/c = user.mind.changeling
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(sting_action(user, target))
SSblackbox.add_details("changeling_powers",name)
sting_feedback(user, target)
@@ -52,7 +52,7 @@
if(req_human && !ishuman(user))
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
return 0
var/datum/changeling/c = user.mind.changeling
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(c.chem_charges < chemical_cost)
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
return 0

View File

@@ -1,112 +0,0 @@
/datum/changeling/proc/purchasePower(mob/living/carbon/user, sting_name)
var/obj/effect/proc_holder/changeling/thepower = null
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
var/obj/effect/proc_holder/changeling/S = path
if(initial(S.name) == sting_name)
thepower = new path()
break
if(!thepower)
to_chat(user, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
return
if(absorbedcount < thepower.req_dna)
to_chat(user, "We lack the energy to evolve this ability!")
return
if(has_sting(thepower))
to_chat(user, "We have already evolved this ability!")
return
if(thepower.dna_cost < 0)
to_chat(user, "We cannot evolve this ability.")
return
if(geneticpoints < thepower.dna_cost)
to_chat(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.
to_chat(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(mob/user)
if(!ishuman(user))
to_chat(user, "<span class='danger'>We can't remove our evolutions in this form!</span>")
return
if(canrespec)
to_chat(user, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
user.remove_changeling_powers(1)
canrespec = 0
user.make_changeling(TRUE)
return 1
else
to_chat(user, "<span class='danger'>You lack the power to readapt your evolutions!</span>")
return 0
/mob/proc/make_changeling(is_respec)
if(!mind)
return
if(!ishuman(src) && !ismonkey(src))
return
if(!mind.changeling)
mind.changeling = new /datum/changeling(gender)
if(mind.changeling.purchasedpowers)
remove_changeling_powers(1)
// purchase free powers.
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
var/obj/effect/proc_holder/changeling/S = new path()
if(!S.dna_cost)
if(!mind.changeling.has_sting(S))
mind.changeling.purchasedpowers+=S
S.on_purchase(src, is_respec)
if(is_respec)
SSblackbox.add_details("changeling_power_purchase","Readapt")
var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
if(ishuman(C))
var/datum/changelingprofile/prof = mind.changeling.add_new_profile(C, src)
mind.changeling.first_prof = prof
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B)
B.vital = FALSE
B.decoy_override = TRUE
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(keep_free_powers=0)
if(ishuman(src) || ismonkey(src))
if(mind && mind.changeling)
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) || p.always_keep)
continue
mind.changeling.purchasedpowers -= p
p.on_refund(src)
if(hud_used)
hud_used.lingstingdisplay.icon_state = null
hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
/datum/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 1
return 0

View File

@@ -9,7 +9,7 @@
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.isabsorbing)
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
return
@@ -22,12 +22,12 @@
return
var/mob/living/carbon/target = user.pulling
return changeling.can_absorb_dna(user,target)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/mob/living/carbon/human/target = user.pulling
changeling.isabsorbing = 1
for(var/i in 1 to 3)
@@ -52,7 +52,7 @@
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
if(!changeling.has_dna(target.dna))
changeling.add_new_profile(target, user)
changeling.add_new_profile(target)
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
@@ -84,12 +84,14 @@
user.mind.store_memory("<B>We have no more knowledge of [target]'s speech patterns.</B>")
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
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.stored_profiles.len = 1
target.mind.changeling.absorbedcount = 0
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
changeling.absorbedcount += (target_ling.absorbedcount)
target_ling.stored_profiles.len = 1
target_ling.absorbedcount = 0
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)

View File

@@ -20,9 +20,11 @@
return TRUE
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers)
if(user && user.mind)
var/datum/antagonist/changeling/C = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.purchasedpowers)
to_chat(user, "<span class='notice'>We are ready to revive.</span>")
user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
C.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/user)
if(user.status_flags & FAKEDEATH)

View File

@@ -8,7 +8,7 @@
/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec)
..()
var/datum/changeling/changeling=user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.changeling_speak = 1
to_chat(user, "<i><font color=#800080>Use say \":g message\" to communicate with the other changelings.</font></i>")
var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new
@@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
dna_cost = -1
/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
if(!(prof in GLOB.hivemind_bank))
@@ -61,7 +61,7 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
/obj/effect/proc_holder/changeling/hivemind_download/can_sting(mob/living/carbon/user)
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/datum/changelingprofile/first_prof = changeling.stored_profiles[1]
if(first_prof.name == user.real_name)//If our current DNA is the stalest, we gotta ditch it.
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
@@ -69,7 +69,7 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
return 1
/obj/effect/proc_holder/changeling/hivemind_download/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in GLOB.hivemind_bank)
if(!(prof in changeling.stored_profiles))

View File

@@ -6,7 +6,7 @@
//Transform into a human.
/obj/effect/proc_holder/changeling/humanform/sting_action(mob/living/carbon/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
names += "[prof.name]"

View File

@@ -8,7 +8,7 @@
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.islinking)
to_chat(user, "<span class='warning'>We have already formed a link with the victim!</span>")
return
@@ -19,22 +19,23 @@
to_chat(user, "<span class='warning'>We cannot link with this creature!</span>")
return
var/mob/living/carbon/target = user.pulling
if(!target.mind)
to_chat(user, "<span class='warning'>The victim has no mind to link to!</span>")
return
if(target.stat == DEAD)
to_chat(user, "<span class='warning'>The victim is dead, you cannot link to a dead mind!</span>")
return
if(target.mind.changeling)
if(target.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='warning'>The victim is already a part of the hivemind!</span>")
return
if(user.grab_state <= GRAB_AGGRESSIVE)
to_chat(user, "<span class='warning'>We must have a tighter grip to link with this creature!</span>")
return
return changeling.can_absorb_dna(user,target)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/linglink/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/mob/living/carbon/human/target = user.pulling
changeling.islinking = 1
for(var/i in 1 to 3)

View File

@@ -9,7 +9,7 @@
// Fake Voice
/obj/effect/proc_holder/changeling/mimicvoice/sting_action(mob/user)
var/datum/changeling/changeling=user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.mimicing)
changeling.mimicing = ""
changeling.chem_recharge_slowdown -= 0.5

View File

@@ -83,7 +83,7 @@
//checks if we already have an organic suit and casts it off.
/obj/effect/proc_holder/changeling/suit/proc/check_suit(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!ishuman(user) || !changeling)
return 1
var/mob/living/carbon/human/H = user
@@ -122,7 +122,7 @@
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
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chem_recharge_slowdown += recharge_slowdown
return TRUE
@@ -385,7 +385,7 @@
weapon_name_simple = "shield"
/obj/effect/proc_holder/changeling/weapon/shield/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling //So we can read the absorbedcount.
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) //So we can read the absorbedcount.
if(!changeling)
return

View File

@@ -25,11 +25,13 @@
user.regenerate_limbs(0, list("head"))
user.regenerate_organs()
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
user.mind.changeling.purchasedpowers -= src
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
return TRUE
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/user)
if((user.stat != DEAD) && !(user.status_flags & FAKEDEATH))
user.mind.changeling.purchasedpowers -= src
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
return 0
. = ..()

View File

@@ -11,7 +11,7 @@
for(var/mob/living/M in get_hearers_in_view(4, user))
if(iscarbon(M))
var/mob/living/carbon/C = M
if(!C.mind || !C.mind.changeling)
if(!C.mind || !C.mind.has_antag_datum(/datum/antagonist/changeling))
C.adjustEarDamage(0, 30)
C.confused += 25
C.Jitter(50)

View File

@@ -5,9 +5,12 @@
/obj/effect/proc_holder/changeling/sting/Click()
var/mob/user = usr
if(!user || !user.mind || !user.mind.changeling)
if(!user || !user.mind)
return
if(!(user.mind.changeling.chosen_sting))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling)
return
if(!changeling.chosen_sting)
set_sting(user)
else
unset_sting(user)
@@ -15,41 +18,48 @@
/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
to_chat(user, "<span class='notice'>We prepare our sting, use alt+click or middle mouse button on target to sting them.</span>")
user.mind.changeling.chosen_sting = src
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = src
user.hud_used.lingstingdisplay.icon_state = sting_icon
user.hud_used.lingstingdisplay.invisibility = 0
/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
to_chat(user, "<span class='warning'>We retract our sting, we can't sting anyone for now.</span>")
user.mind.changeling.chosen_sting = null
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = null
user.hud_used.lingstingdisplay.icon_state = null
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
/mob/living/carbon/proc/unset_sting()
if(mind && mind.changeling && mind.changeling.chosen_sting)
src.mind.changeling.chosen_sting.unset_sting(src)
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling && changeling.chosen_sting)
changeling.chosen_sting.unset_sting(src)
/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
if(!..())
return
if(!user.mind.changeling.chosen_sting)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling.chosen_sting)
to_chat(user, "We haven't prepared our sting yet!")
if(!iscarbon(target))
return
if(!isturf(user.loc))
return
if(!AStar(user, target.loc, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0))
if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
return
if(target.mind && target.mind.changeling)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
sting_feedback(user, target)
user.mind.changeling.chem_charges -= chemical_cost
changeling.chem_charges -= chemical_cost //??
return 1
/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
if(!target)
return
to_chat(user, "<span class='notice'>We stealthily sting [target.name].</span>")
if(target.mind && target.mind.changeling)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(target, "<span class='warning'>You feel a tiny prick.</span>")
return 1
@@ -65,7 +75,7 @@
/obj/effect/proc_holder/changeling/sting/transformation/Click()
var/mob/user = usr
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.chosen_sting)
unset_sting(user)
return
@@ -163,12 +173,14 @@
/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(mob/user, mob/target)
if(..())
return user.mind.changeling.can_absorb_dna(user, target)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target)
add_logs(user, target, "stung", "extraction sting")
if(!(user.mind.changeling.has_dna(target.dna)))
user.mind.changeling.add_new_profile(target, user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!(changeling.has_dna(target.dna)))
changeling.add_new_profile(target)
return TRUE
/obj/effect/proc_holder/changeling/sting/mute

View File

@@ -11,7 +11,7 @@
flags_1 = NODROP_1
/obj/item/clothing/glasses/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -22,7 +22,7 @@
flags_1 = NODROP_1
/obj/item/clothing/under/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -34,7 +34,7 @@
allowed = list(/obj/item/changeling)
/obj/item/clothing/suit/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -45,7 +45,7 @@
flags_1 = NODROP_1
/obj/item/clothing/head/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -56,7 +56,7 @@
flags_1 = NODROP_1
/obj/item/clothing/shoes/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -67,7 +67,7 @@
flags_1 = NODROP_1
/obj/item/clothing/gloves/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -78,7 +78,7 @@
flags_1 = NODROP_1
/obj/item/clothing/mask/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -91,7 +91,7 @@
allowed = list(/obj/item/changeling)
/obj/item/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
@@ -99,8 +99,8 @@
//Change our DNA to that of somebody we've absorbed.
/obj/effect/proc_holder/changeling/transform/sting_action(mob/living/carbon/human/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/changelingprofile/chosen_prof = changeling.select_dna("Select the target DNA: ", "Target DNA", user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/datum/changelingprofile/chosen_prof = changeling.select_dna("Select the target DNA: ", "Target DNA")
if(!chosen_prof)
return
@@ -108,7 +108,10 @@
changeling_transform(user, chosen_prof)
return TRUE
/datum/changeling/proc/select_dna(var/prompt, var/title, var/mob/living/carbon/user)
/datum/antagonist/changeling/proc/select_dna(var/prompt, var/title)
var/mob/living/carbon/user = owner.current
if(!istype(user))
return
var/list/names = list("Drop Flesh Disguise")
for(var/datum/changelingprofile/prof in stored_profiles)
names += "[prof.name]"

View File

@@ -10,6 +10,7 @@
reroll_friendly = 1
var/list/possible_changelings = list()
var/list/changelings = list()
var/const/changeling_amount = 1 //hard limit on changelings if scaling is turned off
/datum/game_mode/traitor/changeling/announce()
@@ -57,25 +58,22 @@
/datum/game_mode/traitor/changeling/post_setup()
for(var/datum/mind/changeling in changelings)
changeling.current.make_changeling()
forge_changeling_objectives(changeling)
greet_changeling(changeling)
SSticker.mode.update_changeling_icons_added(changeling)
..()
return
changeling.add_antag_datum(/datum/antagonist/changeling)
return ..()
/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2)))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
changelings += character.mind
..()
/datum/game_mode/traitor/changeling/generate_report()

View File

@@ -477,7 +477,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
if(ishuman(L))
var/mob/living/carbon/human/H = L
species = "<span class='notice'>[H.dna.species.name]</span>"
if(L.mind && L.mind.changeling)
if(L.mind && L.mind.has_antag_datum(/datum/antagonist/changeling))
species = "<span class='warning'>Changeling lifeform</span>"
var/obj/item/organ/heart/gland/temp = locate() in H.internal_organs
if(temp)

View File

@@ -586,7 +586,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
n_p ++
else if (SSticker.IsRoundInProgress())
for(var/mob/living/carbon/human/P in GLOB.player_list)
if(P.client && !(P.mind in SSticker.mode.changelings) && !(P.mind in owners))
if(P.client && !(P.mind.has_antag_datum(/datum/antagonist/changeling)) && !(P.mind in owners))
n_p ++
target_amount = min(target_amount, n_p)
@@ -597,9 +597,12 @@ GLOBAL_LIST_EMPTY(possible_items_special)
var/list/datum/mind/owners = get_owners()
var/absorbedcount = 0
for(var/datum/mind/M in owners)
if(!owner || !owner.changeling || !owner.changeling.stored_profiles)
if(!M)
continue
absorbedcount += M.changeling.absorbedcount
var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling)
if(!changeling || !changeling.stored_profiles)
continue
absorbedcount += changeling.absorbedcount
return absorbedcount >= target_amount
@@ -696,10 +699,11 @@ GLOBAL_LIST_EMPTY(possible_items_special)
if("Chief Medical Officer")
department_string = "medical"
var/ling_count = SSticker.mode.changelings
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
var/ling_count = lings.len
for(var/datum/mind/M in SSticker.minds)
if(M in SSticker.mode.changelings)
if(M in lings)
continue
if(department_head in get_department_heads(M.assigned_role))
if(ling_count)
@@ -723,13 +727,13 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Needed heads is between min_lings and the maximum possible amount of command roles
//So at the time of writing, rand(3,6), it's also capped by the amount of lings there are
//Because you can't fill 6 head roles with 3 lings
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
var/needed_heads = rand(min_lings,GLOB.command_positions.len)
needed_heads = min(SSticker.mode.changelings.len,needed_heads)
needed_heads = min(lings.len,needed_heads)
var/list/heads = SSjob.get_living_heads()
for(var/datum/mind/head in heads)
if(head in SSticker.mode.changelings) //Looking at you HoP.
if(head in lings) //Looking at you HoP.
continue
if(needed_heads)
department_minds += head
@@ -789,7 +793,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Check each department member's mind to see if any of them made it to centcom alive, if they did it's an automatic fail
for(var/datum/mind/M in department_minds)
if(M in SSticker.mode.changelings) //Lings aren't picked for this, but let's be safe
if(M.has_antag_datum(/datum/antagonist/changeling)) //Lings aren't picked for this, but let's be safe
continue
if(M.current)
@@ -800,7 +804,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Check each staff member has been replaced, by cross referencing changeling minds, changeling current dna, the staff minds and their original DNA names
var/success = 0
changelings:
for(var/datum/mind/changeling in SSticker.mode.changelings)
for(var/datum/mind/changeling in get_antagonists(/datum/antagonist/changeling,TRUE))
if(success >= department_minds.len) //We did it, stop here!
return 1
if(ishuman(changeling.current))

View File

@@ -162,11 +162,6 @@
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
if(clonemind.changeling)
var/obj/item/organ/brain/B = H.getorganslot(ORGAN_SLOT_BRAIN)
B.vital = FALSE
B.decoy_override = TRUE
H.hardset_dna(ui, se, H.real_name, null, mrace, features)
if(efficiency > 2)

View File

@@ -442,12 +442,15 @@
dat += "<td><A href='?priv_msg=[N.key]'>PM</A></td></tr>"
dat += "</table>"
if(SSticker.mode.changelings.len > 0)
var/list/lings = get_antagonists(/datum/antagonist/changeling)
if(lings.len > 0)
dat += "<br><table cellspacing=5><tr><td><B>Changelings</B></td><td></td><td></td></tr>"
for(var/datum/mind/changeling in SSticker.mode.changelings)
for(var/datum/mind/changeling in lings)
var/datum/antagonist/changeling/lingantag = changeling.has_antag_datum(/datum/antagonist/changeling)
var/mob/M = changeling.current
if(M)
dat += "<tr><td>[M.mind.changeling.changelingID] as <a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
dat += "<tr><td>[lingantag.changelingID]([lingantag.name]) as <a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
dat += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>"
dat += "<td><A href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a></td>"
dat += "<td><A HREF='?_src_=holder;[HrefToken()];traitor=[REF(M)]'>Show Objective</A></td></tr>"

View File

@@ -106,8 +106,6 @@
/obj/item/clothing/Destroy()
if(isliving(loc))
dropped(loc)
if(pockets)
qdel(pockets)
pockets = null

View File

@@ -23,7 +23,7 @@
name = "brain"
if(C.mind && C.mind.changeling && !no_id_transfer) //congrats, you're trapped in a body you don't control
if(C.mind && C.mind.has_antag_datum(/datum/antagonist/changeling) && !no_id_transfer) //congrats, you're trapped in a body you don't control
if(brainmob && !(C.stat == DEAD || (C.status_flags & FAKEDEATH)))
to_chat(brainmob, "<span class = danger>You can't feel your body! You're still just a brain!</span>")
loc = C

View File

@@ -770,7 +770,7 @@
/mob/living/carbon/can_be_revived()
. = ..()
if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.changeling))
if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
return 0
/mob/living/carbon/harvest(mob/living/user)

View File

@@ -56,9 +56,10 @@
stat("Distribution Pressure", internal.distribute_pressure)
if(mind)
if(mind.changeling)
stat("Chemical Storage", "[mind.changeling.chem_charges]/[mind.changeling.chem_storage]")
stat("Absorbed DNA", mind.changeling.absorbedcount)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
stat("Absorbed DNA", changeling.absorbedcount)
//NINJACODE

View File

@@ -39,8 +39,10 @@
return real_name
else
return real_name
if(mind && mind.changeling && mind.changeling.mimicing)
return mind.changeling.mimicing
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling && changeling.mimicing )
return changeling.mimicing
if(GetSpecialVoice())
return GetSpecialVoice()
return real_name

View File

@@ -251,12 +251,14 @@
if(stat != DEAD)
D.stage_act()
//todo generalize this and move hud out
/mob/living/carbon/proc/handle_changeling()
if(mind && hud_used && hud_used.lingchemdisplay)
if(mind.changeling)
mind.changeling.regenerate(src)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
changeling.regenerate()
hud_used.lingchemdisplay.invisibility = 0
hud_used.lingchemdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[round(mind.changeling.chem_charges)]</font></div>"
hud_used.lingchemdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[round(changeling.chem_charges)]</font></div>"
else
hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT

View File

@@ -74,9 +74,10 @@
stat(null, "Intent: [a_intent]")
stat(null, "Move Mode: [m_intent]")
if(client && mind)
if(mind.changeling)
stat("Chemical Storage", "[mind.changeling.chem_charges]/[mind.changeling.chem_storage]")
stat("Absorbed DNA", mind.changeling.absorbedcount)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
stat("Absorbed DNA", changeling.absorbedcount)
return

View File

@@ -336,8 +336,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(prob(40))
to_chat(M, "<i><font color=#800080>We can faintly sense an outsider trying to communicate through the hivemind...</font></i>")
if(2)
var/msg = "<i><font color=#800080><b>[mind.changeling.changelingID]:</b> [message]</font></i>"
log_talk(src,"[mind.changeling.changelingID]/[key] : [message]",LOGSAY)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
var/msg = "<i><font color=#800080><b>[changeling.changelingID]:</b> [message]</font></i>"
log_talk(src,"[changeling.changelingID]/[key] : [message]",LOGSAY)
for(var/_M in GLOB.mob_list)
var/mob/M = _M
if(M in GLOB.dead_mob_list)
@@ -413,8 +414,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 0
/mob/living/lingcheck() //1 is ling w/ no hivemind. 2 is ling w/hivemind. 3 is ling victim being linked into hivemind.
if(mind && mind.changeling)
if(mind.changeling.changeling_speak)
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
if(changeling.changeling_speak)
return 2
return 1
if(mind && mind.linglink)

View File

@@ -485,7 +485,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
if(guardians.len && !allowmultiple)
to_chat(user, "<span class='holoparasite'>You already have a [mob_name]!</span>")
return
if(user.mind && user.mind.changeling && !allowling)
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling) && !allowling)
to_chat(user, "[ling_failure]")
return
if(used == TRUE)

View File

@@ -74,12 +74,13 @@
if(origin && origin.current && (origin.current.stat == DEAD))
origin.transfer_to(M)
if(!origin.changeling)
M.make_changeling()
if(origin.changeling.can_absorb_dna(M, owner))
origin.changeling.add_new_profile(owner, M)
var/datum/antagonist/changeling/C = origin.has_antag_datum(/datum/antagonist/changeling)
if(!C)
C = origin.add_antag_datum(/datum/antagonist/changeling/xenobio)
if(C.can_absorb_dna(owner))
C.add_new_profile(owner)
origin.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
C.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
M.key = origin.key
owner.gib()

View File

@@ -644,8 +644,9 @@
if(mind)
add_spells_to_statpanel(mind.spell_list)
if(mind.changeling)
add_stings_to_statpanel(mind.changeling.purchasedpowers)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
add_stings_to_statpanel(changeling.purchasedpowers)
add_spells_to_statpanel(mob_spell_list)
/mob/proc/add_spells_to_statpanel(list/spells)

View File

@@ -365,7 +365,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if(M.mind in SSticker.mode.syndicates)
return 2
if("changeling")
if(M.mind in SSticker.mode.changelings)
if(M.mind.has_antag_datum(/datum/antagonist/changeling,TRUE))
return 2
if("wizard")
if(iswizard(M))

View File

@@ -94,8 +94,9 @@
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
var/datum/antagonist/changeling/changeling = O.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
for(var/X in internal_organs)
var/obj/item/organ/I = X
@@ -118,7 +119,7 @@
for(var/X in O.internal_organs)
var/obj/item/organ/G = X
if(BP.body_zone == check_zone(G.zone))
if(mind && mind.changeling && istype(G, /obj/item/organ/brain))
if(mind && mind.has_antag_datum(/datum/antagonist/changeling) && istype(G, /obj/item/organ/brain))
continue //so headless changelings don't lose their brain when transforming
qdel(G) //we lose the organs in the missing limbs
qdel(BP)
@@ -126,8 +127,9 @@
//transfer mind if we didn't yet
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
var/datum/antagonist/changeling/changeling = O.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
if (tr_flags & TR_DEFAULTMSG)
@@ -248,9 +250,10 @@
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
for(var/obj/effect/proc_holder/changeling/humanform/HF in O.mind.changeling.purchasedpowers)
O.mind.changeling.purchasedpowers -= HF
var/datum/antagonist/changeling/changeling = O.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
for(var/obj/effect/proc_holder/changeling/humanform/HF in changeling.purchasedpowers)
changeling.purchasedpowers -= HF
for(var/X in internal_organs)
var/obj/item/organ/I = X
@@ -274,16 +277,17 @@
for(var/X in O.internal_organs)
var/obj/item/organ/G = X
if(BP.body_zone == check_zone(G.zone))
if(mind && mind.changeling && istype(G, /obj/item/organ/brain))
if(mind && mind.has_antag_datum(/datum/antagonist/changeling) && istype(G, /obj/item/organ/brain))
continue //so headless changelings don't lose their brain when transforming
qdel(G) //we lose the organs in the missing limbs
qdel(BP)
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
for(var/obj/effect/proc_holder/changeling/humanform/HF in O.mind.changeling.purchasedpowers)
O.mind.changeling.purchasedpowers -= HF
var/datum/antagonist/changeling/changeling = O.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
for(var/obj/effect/proc_holder/changeling/humanform/HF in changeling.purchasedpowers)
changeling.purchasedpowers -= HF
O.a_intent = INTENT_HELP
if (tr_flags & TR_DEFAULTMSG)

View File

@@ -957,9 +957,11 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "A stingy drink."
/datum/reagent/consumable/ethanol/changelingsting/on_mob_life(mob/living/M)
if(M.mind && M.mind.changeling) //Changeling Sting assists in the recharging of changeling chemicals.
M.mind.changeling.chem_charges += metabolization_rate
M.mind.changeling.chem_charges = Clamp(M.mind.changeling.chem_charges, 0, M.mind.changeling.chem_storage)
if(M.mind) //Changeling Sting assists in the recharging of changeling chemicals.
var/datum/antagonist/changeling/changeling = M.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
changeling.chem_charges += metabolization_rate
changeling.chem_charges = Clamp(changeling.chem_charges, 0, changeling.chem_storage)
return ..()
/datum/reagent/consumable/ethanol/irishcarbomb

View File

@@ -266,6 +266,7 @@
#include "code\datums\antagonists\abductor.dm"
#include "code\datums\antagonists\antag_datum.dm"
#include "code\datums\antagonists\brother.dm"
#include "code\datums\antagonists\changeling.dm"
#include "code\datums\antagonists\clockcult.dm"
#include "code\datums\antagonists\cult.dm"
#include "code\datums\antagonists\datum_traitor.dm"
@@ -426,7 +427,6 @@
#include "code\game\gamemodes\changeling\cellular_emporium.dm"
#include "code\game\gamemodes\changeling\changeling.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\adrenaline.dm"