mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
[MIRROR] Changing changeling (Refactor) (#11142)
Co-authored-by: Cameron Lennox <killer65311@gmail.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
9feb91ec4c
commit
a0c273ce1f
@@ -368,6 +368,8 @@
|
||||
#define REAGENT_ID_SUPERMATTER "supermatter"
|
||||
#define REAGENT_ADRENALINE "Adrenaline"
|
||||
#define REAGENT_ID_ADRENALINE "adrenaline"
|
||||
#define REAGENT_EPINEPHRINE "Epinephrine"
|
||||
#define REAGENT_ID_EPINEPHRINE "epinephrine"
|
||||
#define REAGENT_HOLYWATER "Holy Water"
|
||||
#define REAGENT_ID_HOLYWATER "holywater"
|
||||
#define REAGENT_AMMONIA "Ammonia"
|
||||
|
||||
5
code/__defines/changeling.dm
Normal file
5
code/__defines/changeling.dm
Normal file
@@ -0,0 +1,5 @@
|
||||
#define CRYO_STING "cryo_sting"
|
||||
#define ESCAPE_RESTRAINTS "escape_restraints"
|
||||
#define CHANGELING_SCREECH "changeling_screech" //Used for all shriek powers.
|
||||
#define FAKE_DEATH "fake_death"
|
||||
#define FLESHMEND "flesh_mend"
|
||||
31
code/datums/components/antags/antag.dm
Normal file
31
code/datums/components/antags/antag.dm
Normal file
@@ -0,0 +1,31 @@
|
||||
///Component that holds the antag trait. This is the base version.
|
||||
/datum/component/antag
|
||||
var/mob/living/owner
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE //Only one type.
|
||||
|
||||
/datum/component/antag/Initialize()
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
owner = parent
|
||||
|
||||
///Should never be destroyed as these are applied to the mind.
|
||||
/datum/component/antag/Destroy(force = FALSE)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
owner = null
|
||||
. = ..()
|
||||
|
||||
///Antag datum that is held on /datum/mind. Holds all the antag data.
|
||||
/datum/antag_holder
|
||||
var/datum/component/antag/changeling/changeling
|
||||
var/is_antag = FALSE
|
||||
|
||||
/datum/antag_holder/proc/apply_antags(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
if(changeling)
|
||||
M.make_changeling()
|
||||
is_antag = TRUE
|
||||
|
||||
/datum/antag_holder/proc/is_antag()
|
||||
return is_antag
|
||||
474
code/datums/components/antags/changeling/changeling.dm
Normal file
474
code/datums/components/antags/changeling/changeling.dm
Normal file
@@ -0,0 +1,474 @@
|
||||
///Changeling component.
|
||||
///Stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
|
||||
GLOBAL_LIST_INIT(possible_changeling_IDs,list("Alpha","Beta","Chi","Delta","Epsilon","Eta","Gamma","Iota","Kappa","Lambda","Mu","Nu","Omega","Omicron","Phi","Pi","Psi","Rho","Sigma","Tau","Theta","Upsilon","Xi","Zeta")) //ALPHABETICAL ORDER.
|
||||
//Needs cleanup
|
||||
var/list/powers = subtypesof(/datum/power/changeling) //needed for the badmin verb for now
|
||||
var/list/datum/power/changeling/powerinstances = list()
|
||||
/datum/power //Could be used by other antags too
|
||||
var/name = "Power"
|
||||
var/desc = "Placeholder"
|
||||
var/helptext = ""
|
||||
var/enhancedtext = ""
|
||||
var/isVerb = 1 // Is it an active power, or passive?
|
||||
var/verbpath // Path to a verb that contains the effects.
|
||||
var/make_hud_button = TRUE // Is this ability significant enough to dedicate screen space for a HUD button?
|
||||
var/ability_icon_state = null // icon_state for icons for the ability HUD. Must be in screen_spells.dmi.
|
||||
|
||||
/datum/power/changeling
|
||||
var/allowduringlesserform = FALSE
|
||||
var/genomecost = 500000 // Cost for the changeling to evolve this power.
|
||||
|
||||
/datum/component/antag/changeling
|
||||
var/list/datum/absorbed_dna/absorbed_dna = list()
|
||||
var/list/absorbed_languages = list() // Necessary because of set_species stuff
|
||||
var/absorbedcount = 0
|
||||
var/lingabsorbedcount = 1 //Starts at one, because that's us
|
||||
var/chem_charges = 20
|
||||
var/chem_recharge_rate = 0.5
|
||||
var/chem_storage = 50
|
||||
var/sting_range = 1
|
||||
var/changelingID = "Changeling"
|
||||
var/geneticdamage = 0
|
||||
var/isabsorbing = FALSE
|
||||
var/geneticpoints = 7
|
||||
var/max_geneticpoints = 7
|
||||
var/readapts = 1
|
||||
var/max_readapts = 2
|
||||
var/list/purchased_powers = list()
|
||||
var/mimicing = ""
|
||||
var/cloaked = FALSE
|
||||
var/is_reviving = FALSE
|
||||
var/armor_deployed = FALSE //This is only used for changeling_generic_equip_all_slots() at the moment.
|
||||
var/recursive_enhancement = FALSE //Used to power up other abilities from the ling power with the same name.
|
||||
var/list/purchased_powers_history = list() //Used for round-end report, includes respec uses too.
|
||||
var/thermal_sight = FALSE // Is our Vision Augmented? With thermals?
|
||||
var/datum/changeling_panel/power_panel //Our changeling eveolution panel. Generated the first time we try to open the panel.
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE //Only the first changeling application survives!
|
||||
var/cooldown_time = 1 SECOND // Sting anti-spam.
|
||||
var/last_used_sting_time = 0 // world.time when we used last used a power.
|
||||
var/list/changeling_cooldowns = list(
|
||||
CRYO_STING = 0,
|
||||
ESCAPE_RESTRAINTS = 0,
|
||||
FAKE_DEATH = 0,
|
||||
FLESHMEND = 0,
|
||||
CHANGELING_SCREECH = 0
|
||||
)
|
||||
|
||||
///Checks if a mind or a mob is a changeling.
|
||||
///Checks to see if the thing fed to it is a changeling first, then does some deeper searching.
|
||||
/proc/is_changeling(mob/M)
|
||||
var/datum/component/antag/changeling/changeling = (M.GetComponent(/datum/component/antag/changeling))
|
||||
if(changeling) // Whatever we fed it is a changeling. Return it.
|
||||
return changeling
|
||||
|
||||
//The below is what happens if we fail the above. We do some deeper searching.
|
||||
if(istype(M, /datum/mind)) //Fed a mind and we failed.
|
||||
var/datum/mind/our_mind = M
|
||||
if(our_mind.current)
|
||||
changeling = (our_mind.current.GetComponent(/datum/component/antag/changeling)) //Check to see if the mob we are currently inhabiting is a changeling.
|
||||
else //Fed it a mob and we failed
|
||||
if(M.mind)
|
||||
changeling = M.mind.antag_holder.changeling //Check our mind's antag holder.
|
||||
return changeling
|
||||
|
||||
|
||||
///Handles the cooldown for the power. Returns TRUE if the cooldown has passed. FALSE if it's still on cooldown.
|
||||
///This is just a general anti-spam thing and not really a true cooldown
|
||||
/datum/component/antag/changeling/proc/handle_cooldown()
|
||||
if(world.time > last_used_sting_time+cooldown_time)
|
||||
last_used_sting_time = world.time
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/component/antag/changeling/proc/get_cooldown(id)
|
||||
return changeling_cooldowns[id]
|
||||
|
||||
/datum/component/antag/changeling/proc/set_cooldown(id, cooldown_time)
|
||||
changeling_cooldowns[id] = world.time + cooldown_time
|
||||
|
||||
/datum/component/antag/changeling/proc/is_on_cooldown(id)
|
||||
return (world.time < changeling_cooldowns[id])
|
||||
|
||||
/datum/component/antag/changeling/Initialize()
|
||||
..()
|
||||
if(owner)
|
||||
if(GLOB.possible_changeling_IDs.len)
|
||||
changelingID = pick(GLOB.possible_changeling_IDs)
|
||||
GLOB.possible_changeling_IDs -= changelingID
|
||||
changelingID = "[changelingID]"
|
||||
else
|
||||
changelingID = "[rand(1,999)]"
|
||||
|
||||
add_verb(owner,/mob/proc/EvolutionMenu)
|
||||
add_verb(owner,/mob/proc/changeling_respec)
|
||||
owner.add_language("Changeling")
|
||||
|
||||
///This is a component that is referenced to by the mind, so it should never be deleted
|
||||
/datum/component/antag/changeling/Destroy(force = FALSE)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
return ..()
|
||||
//Old code from when it did destroy itself.
|
||||
/*
|
||||
if(owner)
|
||||
remove_verb(owner,/mob/proc/EvolutionMenu)
|
||||
remove_verb(owner,/mob/proc/changeling_respec)
|
||||
qdel_null(power_panel)
|
||||
absorbed_dna.Cut()
|
||||
absorbed_languages.Cut()
|
||||
purchased_powers.Cut()
|
||||
purchased_powers_history.Cut()
|
||||
. = ..()
|
||||
*/
|
||||
|
||||
//Former /datum/changeling procs
|
||||
/datum/component/antag/changeling/proc/regenerate()
|
||||
chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage)
|
||||
geneticdamage = max(0, geneticdamage-1)
|
||||
|
||||
/datum/component/antag/changeling/proc/GetDNA(var/dna_owner)
|
||||
for(var/datum/absorbed_dna/DNA in absorbed_dna)
|
||||
if(dna_owner == DNA.name)
|
||||
return DNA
|
||||
|
||||
//Former /mob procs
|
||||
/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
return
|
||||
|
||||
|
||||
for(var/language in newDNA.languages)
|
||||
comp.absorbed_languages |= language
|
||||
|
||||
changeling_update_languages(comp.absorbed_languages)
|
||||
|
||||
if(!comp.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite
|
||||
comp.absorbed_dna += newDNA
|
||||
|
||||
//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human
|
||||
/mob/proc/make_changeling()
|
||||
|
||||
if(!mind)
|
||||
return
|
||||
//The current mob is made a changeling AND the mind is made a changeling.
|
||||
var/datum/component/antag/changeling/comp = LoadComponent(/datum/component/antag/changeling)
|
||||
mind.antag_holder.changeling = comp
|
||||
var/lesser_form = !ishuman(src)
|
||||
|
||||
if(!powerinstances.len)
|
||||
for(var/P in powers)
|
||||
powerinstances += new P()
|
||||
|
||||
// Code to auto-purchase free powers.
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
if(!P.genomecost) // Is it free?
|
||||
if(!(P in comp.purchased_powers)) // Do we not have it already?
|
||||
comp.purchasePower(comp.owner, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this.
|
||||
|
||||
for(var/datum/power/changeling/P in comp.purchased_powers)
|
||||
if(P.isVerb)
|
||||
if(lesser_form && !P.allowduringlesserform)
|
||||
continue
|
||||
if(!(P in src.verbs))
|
||||
add_verb(src, P.verbpath)
|
||||
if(P.make_hud_button)
|
||||
if(!src.ability_master)
|
||||
src.ability_master = new /obj/screen/movable/ability_master(src)
|
||||
src.ability_master.add_ling_ability(
|
||||
object_given = src,
|
||||
verb_given = P.verbpath,
|
||||
name_given = P.name,
|
||||
ability_icon_given = P.ability_icon_state,
|
||||
arguments = list()
|
||||
)
|
||||
|
||||
for(var/language in languages)
|
||||
comp.absorbed_languages |= language
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H))
|
||||
add_verb(H, /mob/living/carbon/human/proc/innate_shapeshifting)
|
||||
var/saved_dna = H.dna.Clone() /// Prevent transform from breaking.
|
||||
var/datum/absorbed_dna/newDNA = new(H.real_name, saved_dna, H.species.name, H.languages, H.identifying_gender, H.flavor_texts, H.modifiers)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
//Code to make it so our BR is marked as a changeling body, so it can't be stolen.
|
||||
for(var/key in SStranscore.databases)
|
||||
var/datum/transcore_db/db = SStranscore.databases[key]
|
||||
if(H.mind.name in db.body_scans)
|
||||
var/datum/transhuman/body_record/BR = db.body_scans[H.mind.name]
|
||||
BR.changeling_locked = TRUE
|
||||
|
||||
return TRUE
|
||||
|
||||
//removes our changeling verbs
|
||||
/mob/proc/remove_changeling_powers()
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
return
|
||||
for(var/datum/power/changeling/P in comp.purchased_powers)
|
||||
if(P.isVerb)
|
||||
remove_verb(src, P.verbpath)
|
||||
var/obj/screen/ability/verb_based/changeling/C = ability_master.get_ability_by_proc_ref(P.verbpath)
|
||||
if(C)
|
||||
ability_master.remove_ability(C)
|
||||
|
||||
|
||||
//Helper proc. Does all the checks and stuff for us to avoid copypasta
|
||||
/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0)
|
||||
|
||||
if(!src.mind) return
|
||||
if(!iscarbon(src)) return
|
||||
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
to_world_log("[src] used a changeling verb but is not a changeling.")
|
||||
return
|
||||
|
||||
if(src.stat > max_stat)
|
||||
to_chat(src, span_warning("We are incapacitated."))
|
||||
return
|
||||
|
||||
if(comp.absorbed_dna.len < required_dna)
|
||||
to_chat(src, span_warning("We require at least [required_dna] samples of compatible DNA."))
|
||||
return
|
||||
|
||||
if(comp.chem_charges < required_chems)
|
||||
to_chat(src, span_warning("We require at least [required_chems] units of chemicals to do that!"))
|
||||
return
|
||||
|
||||
if(comp.geneticdamage > max_genetic_damage)
|
||||
to_chat(src, span_warning("Our genomes are still reassembling. We need time to recover first."))
|
||||
return
|
||||
|
||||
return comp
|
||||
|
||||
//Used to dump the languages from the changeling datum into the actual mob.
|
||||
/mob/proc/changeling_update_languages(var/updated_languages)
|
||||
languages = list()
|
||||
for(var/language in updated_languages)
|
||||
languages += language
|
||||
|
||||
//This isn't strictly necessary but just to be safe...
|
||||
add_language("Changeling")
|
||||
|
||||
//////////
|
||||
//STINGS// //They get a pretty header because there's just so fucking many of them ;_;
|
||||
//////////
|
||||
|
||||
/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1)
|
||||
if(M.loc == src.loc)
|
||||
return 1 //target and source are in the same thing
|
||||
if(!isturf(src.loc) || !isturf(M.loc))
|
||||
to_chat(src, span_warning("We cannot reach \the [M] with a sting!"))
|
||||
return 0 //One is inside, the other is outside something.
|
||||
// Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising
|
||||
if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfsRangedSting, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail
|
||||
to_chat(src, span_warning("We cannot find a path to sting \the [M] by!"))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities)
|
||||
/mob/proc/changeling_sting(var/required_chems=0, var/verb_path)
|
||||
var/datum/component/antag/changeling/comp = changeling_power(required_chems)
|
||||
if(!comp)
|
||||
return
|
||||
if(!comp.handle_cooldown())
|
||||
to_chat(src, span_warning("We are still recovering from our last sting."))
|
||||
return
|
||||
|
||||
var/list/victims = list()
|
||||
for(var/mob/living/carbon/C in oview(comp.sting_range))
|
||||
victims += C
|
||||
var/mob/living/carbon/T = tgui_input_list(src, "Who will we sting?", "Sting!", victims)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
if(!comp.handle_cooldown())//Check again in case we have multiple windows open at once.
|
||||
to_chat(src, span_warning("We are still recovering from our last sting."))
|
||||
return
|
||||
if(T.isSynthetic())
|
||||
to_chat(src, span_notice("We are unable to pierce the outer shell of [T]."))
|
||||
return
|
||||
if(!(T in view(comp.sting_range))) return
|
||||
if(!sting_can_reach(T, comp.sting_range)) return
|
||||
if(!changeling_power(required_chems)) return
|
||||
|
||||
comp.chem_charges -= required_chems
|
||||
comp.sting_range = 1
|
||||
|
||||
to_chat(src, span_notice("We stealthily sting [T]."))
|
||||
var/datum/component/antag/changeling/target_comp = is_changeling(T)
|
||||
if(!T.mind || !target_comp)
|
||||
return T //T will be affected by the sting
|
||||
to_chat(T, span_warning("You feel a tiny prick.")) //Stings on other lings have no effect, but they know you're a ling, too.
|
||||
|
||||
return
|
||||
|
||||
//Former /turf procs
|
||||
/turf/proc/AdjacentTurfsRangedSting()
|
||||
//Yes this is snowflakey, but I couldn't get it to work any other way.. -Luke
|
||||
var/list/allowed = list(
|
||||
/obj/structure/table,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/frame,
|
||||
/obj/structure/target_stake,
|
||||
/obj/structure/cable,
|
||||
/obj/structure/disposalpipe,
|
||||
/obj/machinery,
|
||||
/mob
|
||||
)
|
||||
|
||||
var/L[] = new()
|
||||
for(var/turf/simulated/t in oview(src,1))
|
||||
var/add = 1
|
||||
if(t.density)
|
||||
add = 0
|
||||
if(add && LinkBlocked(src,t))
|
||||
add = 0
|
||||
if(add && TurfBlockedNonWindow(t))
|
||||
add = 0
|
||||
for(var/obj/O in t)
|
||||
if(O.density)
|
||||
add = 0
|
||||
break
|
||||
if(istype(O, /obj/machinery/door))
|
||||
//not sure why this doesn't fire on LinkBlocked()
|
||||
add = 0
|
||||
break
|
||||
for(var/type in allowed)
|
||||
if (istype(O, type))
|
||||
add = 1
|
||||
break
|
||||
if(!add)
|
||||
break
|
||||
if(add)
|
||||
L.Add(t)
|
||||
return L
|
||||
|
||||
/mob/proc/EvolutionMenu()
|
||||
set name = "-Evolution Menu-"
|
||||
set category = "Changeling"
|
||||
set desc = "Adapt yourself carefully."
|
||||
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
to_chat(src, "You are not a changeling!")
|
||||
return
|
||||
if(!powerinstances.len)
|
||||
for(var/changeling_power in powers)
|
||||
powerinstances += new changeling_power()
|
||||
if(!comp.power_panel)
|
||||
comp.power_panel = new()
|
||||
comp.power_panel.comp = comp
|
||||
|
||||
comp.power_panel.tgui_interact(src)
|
||||
|
||||
///Purchasing a power. Called by the Evolution Panel.
|
||||
/datum/component/antag/changeling/proc/purchasePower(var/mob/owner, var/Pname, var/remake_verbs = 1)
|
||||
|
||||
var/datum/power/changeling/Thepower = Pname
|
||||
|
||||
for (var/datum/power/changeling/P in powerinstances)
|
||||
//to_world("[P] - [Pname] = [P.name == Pname ? "True" : "False"]")
|
||||
if(P.name == Pname)
|
||||
Thepower = P
|
||||
break
|
||||
|
||||
|
||||
if(Thepower == null)
|
||||
to_chat(owner, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
|
||||
return
|
||||
|
||||
if(Thepower in purchased_powers)
|
||||
to_chat(owner, "We have already evolved this ability!")
|
||||
return
|
||||
|
||||
|
||||
if(geneticpoints < Thepower.genomecost)
|
||||
to_chat(owner, "We cannot evolve this... yet. We must acquire more DNA.")
|
||||
return
|
||||
|
||||
geneticpoints -= Thepower.genomecost
|
||||
|
||||
purchased_powers += Thepower
|
||||
|
||||
if(Thepower.genomecost > 0)
|
||||
purchased_powers_history.Add("[Pname] ([Thepower.genomecost] points)")
|
||||
|
||||
if(Thepower.make_hud_button && Thepower.isVerb)
|
||||
if(owner.ability_master)
|
||||
owner.ability_master = new /obj/screen/movable/ability_master(owner)
|
||||
owner.ability_master.add_ling_ability(
|
||||
object_given = owner,
|
||||
verb_given = Thepower.verbpath,
|
||||
name_given = Thepower.name,
|
||||
ability_icon_given = Thepower.ability_icon_state,
|
||||
arguments = list()
|
||||
)
|
||||
|
||||
if(!Thepower.isVerb && Thepower.verbpath)
|
||||
call(owner, Thepower.verbpath)()
|
||||
else if(remake_verbs)
|
||||
owner.make_changeling()
|
||||
|
||||
|
||||
//Debug item. Here because during debugging I DO NOT want to have to open the player panel 5000 times.
|
||||
/obj/item/toy/katana/changeling_debug
|
||||
name = "Katana of the Changeling"
|
||||
desc = "A katana imbued with special powers. It is said that those who wield it will become a changeling."
|
||||
/obj/item/toy/katana/changeling_debug/attack_self(mob/user)
|
||||
user.make_changeling()
|
||||
|
||||
///Changeling Panel
|
||||
/datum/changeling_panel
|
||||
var/datum/component/antag/changeling/comp
|
||||
|
||||
/datum/changeling_panel/Destroy(force)
|
||||
comp = null
|
||||
. = ..()
|
||||
|
||||
/datum/changeling_panel/tgui_state(mob/user)
|
||||
return GLOB.tgui_always_state
|
||||
|
||||
/datum/changeling_panel/tgui_status(mob/user)
|
||||
if(!isliving(user)) //We ghosted or something.
|
||||
return STATUS_CLOSE
|
||||
return ..()
|
||||
|
||||
/datum/changeling_panel/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src,"ChangelingPanel", "Changeling Evolution Panel", parent_ui)
|
||||
ui.open()
|
||||
|
||||
/datum/changeling_panel/tgui_data(mob/living/carbon/human/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = list()
|
||||
var/list/power_list = list()
|
||||
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
var/list/all_powers = list(
|
||||
"power_name" = P.name,
|
||||
"power_cost" = P.genomecost,
|
||||
"power_purchased" = (P in comp.purchased_powers),
|
||||
"power_desc" = P.desc,
|
||||
)
|
||||
UNTYPED_LIST_ADD(power_list, all_powers)
|
||||
|
||||
data["available_points"] = comp.geneticpoints
|
||||
data["power_list"] = power_list
|
||||
|
||||
return data
|
||||
|
||||
/datum/changeling_panel/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("evolve_power")
|
||||
comp.purchasePower(comp.owner, params["val"]) //The power must be the power's NAME.
|
||||
return TRUE
|
||||
return TRUE
|
||||
@@ -9,7 +9,7 @@
|
||||
if(istype(M.wear_suit, armor_type) || istype(M.head, helmet_type) || istype(M.shoes, boot_type))
|
||||
chem_cost = 0
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(chem_cost, 1, 100, CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(chem_cost, 1, 100, CONSCIOUS)
|
||||
|
||||
if(!changeling)
|
||||
return
|
||||
@@ -44,7 +44,7 @@
|
||||
var/obj/item/clothing/shoes/B = new boot_type(src)
|
||||
src.equip_to_slot_or_del(B, slot_shoes)
|
||||
|
||||
src.mind.changeling.chem_charges -= chem_cost
|
||||
changeling.chem_charges -= chem_cost
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
M.update_inv_wear_suit()
|
||||
M.update_inv_head()
|
||||
@@ -53,7 +53,7 @@
|
||||
return 1
|
||||
|
||||
/mob/proc/changeling_generic_equip_all_slots(var/list/stuff_to_equip, var/cost)
|
||||
var/datum/changeling/changeling = changeling_power(cost,1,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(cost,1,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
//First, check if we're already wearing the armor, and if so, take it off.
|
||||
|
||||
if(M.mind.changeling.armor_deployed)
|
||||
if(changeling.armor_deployed)
|
||||
if(M.head && stuff_to_equip["head"])
|
||||
if(istype(M.head, stuff_to_equip["head"]))
|
||||
qdel(M.head)
|
||||
@@ -122,7 +122,7 @@
|
||||
playsound(src, 'sound/effects/splat.ogg', 30, 1)
|
||||
visible_message(span_warning("[src] pulls on their clothes, peeling it off along with parts of their skin attached!"),
|
||||
span_notice("We remove and deform our equipment."))
|
||||
M.mind.changeling.armor_deployed = 0
|
||||
changeling.armor_deployed = 0
|
||||
return success
|
||||
|
||||
else
|
||||
@@ -226,13 +226,13 @@
|
||||
to_chat(M, span_notice("We have grown [feedback]."))
|
||||
|
||||
if(success)
|
||||
M.mind.changeling.armor_deployed = 1
|
||||
M.mind.changeling.chem_charges -= 10
|
||||
changeling.armor_deployed = 1
|
||||
changeling.chem_charges -= 10
|
||||
return success
|
||||
|
||||
//This is a generic proc that should be called by other ling weapon procs to equip them.
|
||||
/mob/proc/changeling_generic_weapon(var/weapon_type, var/make_sound = 1, var/cost = 20)
|
||||
var/datum/changeling/changeling = changeling_power(cost,1,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(cost,1,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
var/obj/item/W = new weapon_type(src)
|
||||
src.put_in_hands(W)
|
||||
|
||||
src.mind.changeling.chem_charges -= cost
|
||||
changeling.chem_charges -= cost
|
||||
if(make_sound)
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
return 1
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/absorb_dna
|
||||
name = "Absorb DNA"
|
||||
desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger if they were of our kind."
|
||||
@@ -11,7 +12,7 @@
|
||||
set category = "Changeling"
|
||||
set name = "Absorb DNA"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100) //Our changeling power
|
||||
if(!changeling) return
|
||||
|
||||
var/obj/item/grab/G = src.get_active_hand()
|
||||
@@ -28,8 +29,10 @@
|
||||
to_chat(src, span_warning("We do not know how to parse this creature's DNA!"))
|
||||
return
|
||||
|
||||
var/datum/component/antag/changeling/target_changeling = is_changeling(T) //If the target is a changeling
|
||||
|
||||
if(HUSK in T.mutations) //Lings can always absorb other lings, unless someone beat them to it first.
|
||||
if(!T.mind.changeling || T.mind.changeling && T.mind.changeling.geneticpoints < 0)
|
||||
if(!target_changeling || target_changeling && target_changeling.geneticpoints < 0)
|
||||
to_chat(src, span_warning("This creature's DNA is ruined beyond useability!"))
|
||||
return
|
||||
|
||||
@@ -41,7 +44,7 @@
|
||||
to_chat(src, span_warning("We are already absorbing!"))
|
||||
return
|
||||
|
||||
changeling.isabsorbing = 1
|
||||
changeling.isabsorbing = TRUE
|
||||
for(var/stage = 1, stage<=3, stage++)
|
||||
switch(stage)
|
||||
if(1)
|
||||
@@ -53,62 +56,87 @@
|
||||
to_chat(src, span_notice("We stab [T] with the proboscis."))
|
||||
src.visible_message(span_danger("[src] stabs [T] with the proboscis!"))
|
||||
to_chat(T, span_danger("You feel a sharp stabbing pain!"))
|
||||
add_attack_logs(src,T,"Absorbed (changeling)")
|
||||
var/obj/item/organ/external/affecting = T.get_organ(src.zone_sel.selecting)
|
||||
if(affecting.take_damage(39,0,1,0,"large organic needle"))
|
||||
T:UpdateDamageIcon()
|
||||
T.UpdateDamageIcon()
|
||||
|
||||
feedback_add_details("changeling_powers","A[stage]")
|
||||
if(!do_mob(src, T, 150) || G.state != GRAB_KILL)
|
||||
to_chat(src, span_warning("Our absorption of [T] has been interrupted!"))
|
||||
changeling.isabsorbing = 0
|
||||
changeling.isabsorbing = FALSE
|
||||
return
|
||||
|
||||
to_chat(src, span_notice("We have absorbed [T]!"))
|
||||
src.visible_message(span_danger("[src] sucks the fluids from [T]!"))
|
||||
add_attack_logs(src,T,"Absorbed (changeling)")
|
||||
visible_message(span_danger("[src] sucks the fluids from [T]!"))
|
||||
to_chat(T, span_danger("You have been absorbed by the changeling!"))
|
||||
adjust_nutrition(T.nutrition)
|
||||
changeling_obtain_dna(T, changeling, target_changeling)
|
||||
|
||||
changeling.isabsorbing = FALSE
|
||||
T.death(FALSE)
|
||||
T.Drain()
|
||||
return 1
|
||||
|
||||
///Proc that does the actual 'obtaining DNA' part for changelings. Has four arguments: Our victim, our changeling component, the target's changeling component, and if we drain the victim's nutrition or not.
|
||||
/mob/living/proc/changeling_obtain_dna(mob/living/carbon/human/victim, datum/component/antag/changeling/changeling, datum/component/antag/changeling/target_changeling, drain = TRUE)
|
||||
if(!victim || !ishuman(victim)) //There MUST be a victim and it MUST be a human and NOT a monkey!
|
||||
return
|
||||
if(!target_changeling)
|
||||
target_changeling = is_changeling(victim) //Let's see if the victim is a changeling or not.
|
||||
if(!target_changeling && isMonkey(victim)) //No absorbing non-changeling monkeys.
|
||||
return
|
||||
|
||||
//If we weren't fed a changeling component, we get it ourselves. If that fails, we see if the target is a changeling. If so, they get the DNA of the person predding them. Preyling!
|
||||
if(!changeling)
|
||||
changeling = is_changeling(src)
|
||||
if(!changeling && target_changeling) //Prey is a ling but owner is not.
|
||||
changeling_obtain_dna(src, target_changeling, drain = FALSE) //Flip the tables!~ Don't steal the pred's nutrition, though!
|
||||
return
|
||||
else if(!changeling) //Neither pred or prey are owner.
|
||||
return
|
||||
|
||||
var/saved_dna = victim.dna.Clone()
|
||||
var/datum/absorbed_dna/newDNA = new(victim.real_name, saved_dna, victim.species.name, victim.languages, victim.identifying_gender, victim.flavor_texts, victim.modifiers)
|
||||
if(changeling.GetDNA(newDNA.name))
|
||||
qdel(newDNA)
|
||||
return //No double dipping! You already ate or absorbed them once this shift, glutton!
|
||||
absorbDNA(newDNA)
|
||||
if(drain)
|
||||
adjust_nutrition(victim.nutrition)
|
||||
changeling.chem_charges += 10
|
||||
if(changeling.readapts <= 0)
|
||||
changeling.readapts = 0 //SANITYYYYYY
|
||||
changeling.readapts++
|
||||
//Let's give them a genetic point for absorbing someone...Because honestly if you absorb people you SHOULD get stronger.
|
||||
changeling.max_geneticpoints++
|
||||
changeling.geneticpoints++
|
||||
if(changeling.readapts > changeling.max_readapts)
|
||||
changeling.readapts = changeling.max_readapts
|
||||
|
||||
to_chat(src, span_notice("We can now re-adapt, reverting our evolution so that we may start anew, if needed."))
|
||||
|
||||
var/saved_dna = T.dna.Clone() /// Prevent transforming bugginess.
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, saved_dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts, T.modifiers)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
if(T.mind && T.mind.changeling)
|
||||
if(T.mind.changeling.absorbed_dna)
|
||||
for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
|
||||
if(victim.mind && target_changeling)
|
||||
if(target_changeling.absorbed_dna)
|
||||
for(var/datum/absorbed_dna/dna_data in target_changeling.absorbed_dna) //steal all their loot
|
||||
if(dna_data in changeling.absorbed_dna)
|
||||
continue
|
||||
absorbDNA(dna_data)
|
||||
changeling.absorbedcount++
|
||||
|
||||
T.mind.changeling.absorbed_dna.len = 1
|
||||
target_changeling.absorbed_dna.len = 1
|
||||
|
||||
// This is where lings get boosts from eating eachother
|
||||
if(T.mind.changeling.lingabsorbedcount)
|
||||
for(var/a = 1 to T.mind.changeling.lingabsorbedcount)
|
||||
if(target_changeling.lingabsorbedcount)
|
||||
for(var/a = 1 to target_changeling.lingabsorbedcount)
|
||||
changeling.lingabsorbedcount++
|
||||
changeling.geneticpoints += 4
|
||||
changeling.max_geneticpoints += 4
|
||||
|
||||
to_chat(src, span_notice("We absorbed another changeling, and we grow stronger. Our genomes increase."))
|
||||
|
||||
T.mind.changeling.chem_charges = 0
|
||||
T.mind.changeling.geneticpoints = -1
|
||||
T.mind.changeling.max_geneticpoints = -1 //To prevent revival.
|
||||
T.mind.changeling.absorbedcount = 0
|
||||
T.mind.changeling.lingabsorbedcount = 0
|
||||
|
||||
target_changeling.chem_charges = 0
|
||||
target_changeling.geneticpoints = -1
|
||||
target_changeling.max_geneticpoints = -1 //To prevent revival.
|
||||
target_changeling.absorbedcount = 0
|
||||
target_changeling.lingabsorbedcount = 0
|
||||
changeling.absorbedcount++
|
||||
changeling.isabsorbing = 0
|
||||
|
||||
T.death(0)
|
||||
T.Drain()
|
||||
return 1
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/arm_blade
|
||||
name = "Arm Blade"
|
||||
desc = "We reform one of our arms into a deadly blade."
|
||||
@@ -12,7 +13,10 @@
|
||||
set category = "Changeling"
|
||||
set name = "Arm Blade (20)"
|
||||
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
return
|
||||
if(comp.recursive_enhancement)
|
||||
if(changeling_generic_weapon(/obj/item/melee/changeling/arm_blade/greater))
|
||||
to_chat(src, span_notice("We prepare an extra sharp blade."))
|
||||
return 1
|
||||
@@ -36,8 +40,11 @@
|
||||
/mob/proc/changeling_claw()
|
||||
set category = "Changeling"
|
||||
set name = "Claw (15)"
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
return
|
||||
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
if(changeling_generic_weapon(/obj/item/melee/changeling/claw/greater, 1, 15))
|
||||
to_chat(src, span_notice("We prepare an extra sharp claw."))
|
||||
return 1
|
||||
@@ -58,6 +65,8 @@
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
embed_chance = 0 //No embedding.
|
||||
destroy_on_drop = TRUE
|
||||
var/mob/living/creator //This is just like ninja swords, needed to make sure dumb shit that removes the sword doesn't make it stay around.
|
||||
var/weapType = "weapon"
|
||||
var/weapLocation = "arm"
|
||||
@@ -67,7 +76,6 @@
|
||||
|
||||
/obj/item/melee/changeling/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(ismob(loc))
|
||||
visible_message(span_warning("A grotesque weapon forms around [loc.name]\'s arm!"),
|
||||
span_warning("Our arm twists and mutates, transforming it into a deadly weapon."),
|
||||
@@ -80,32 +88,11 @@
|
||||
span_notice("We assimilate the weapon back into our body."),
|
||||
span_warningplain("You hear organic matter ripping and tearing!"))
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
spawn(1)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/melee/changeling/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
creator = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/melee/changeling/process() //Stolen from ninja swords.
|
||||
if(!creator || loc != creator || !creator.item_is_in_hands(src))
|
||||
// Tidy up a bit.
|
||||
if(isliving(loc))
|
||||
var/mob/living/carbon/human/host = loc
|
||||
if(istype(host))
|
||||
for(var/obj/item/organ/external/organ in host.organs)
|
||||
for(var/obj/item/O in organ.implants)
|
||||
if(O == src)
|
||||
organ.implants -= src
|
||||
host.pinned -= src
|
||||
host.embedded -= src
|
||||
host.drop_from_inventory(src)
|
||||
spawn(1)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/melee/changeling/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
|
||||
if(default_parry_check(user, attacker, damage_source) && prob(defend_chance))
|
||||
user.visible_message(span_danger("\The [user] parries [attack_text] with \the [src]!"))
|
||||
@@ -1,9 +1,10 @@
|
||||
//Updated
|
||||
/datum/power/changeling/space_suit
|
||||
name = "Organic Space Suit"
|
||||
desc = "We grow an organic suit to protect ourselves from space exposure."
|
||||
helptext = "To remove the suit, use the ability again."
|
||||
ability_icon_state = "ling_space_suit"
|
||||
genomecost = 1
|
||||
genomecost = 0 //Have a free spacesuit. It's not worth buying. If you want a special version, get the armor.
|
||||
verbpath = /mob/proc/changeling_spacesuit
|
||||
|
||||
/mob/proc/changeling_spacesuit()
|
||||
@@ -37,6 +38,7 @@
|
||||
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
|
||||
flags = 0 //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it,
|
||||
//it still ends up in your blood. (also balance but muh fluff)
|
||||
destroy_on_drop = TRUE
|
||||
allowed = list(POCKET_GENERIC, POCKET_ALL_TANKS)
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) //No armor at all.
|
||||
canremove = FALSE
|
||||
@@ -48,10 +50,6 @@
|
||||
span_warning("We inflate our flesh, creating a spaceproof suit!"),
|
||||
span_warningplain("You hear organic matter ripping and tearing!"))
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/dropped(mob/user)
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/changeling
|
||||
name = "flesh mass"
|
||||
icon_state = "lingspacehelmet"
|
||||
@@ -60,10 +58,7 @@
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
body_parts_covered = HEAD|FACE|EYES
|
||||
canremove = FALSE
|
||||
|
||||
/obj/item/clothing/head/helmet/space/changeling/dropped(mob/user)
|
||||
..()
|
||||
qdel(src)
|
||||
destroy_on_drop = TRUE
|
||||
|
||||
/obj/item/clothing/shoes/magboots/changeling
|
||||
desc = "A suction cupped mass of flesh, shaped like a foot."
|
||||
@@ -71,6 +66,7 @@
|
||||
icon_state = "lingspacesuit"
|
||||
actions_types = list(/datum/action/item_action/toggle_grippers)
|
||||
canremove = FALSE
|
||||
destroy_on_drop = TRUE
|
||||
|
||||
/obj/item/clothing/shoes/magboots/changeling/set_slowdown()
|
||||
slowdown = shoes? max(SHOES_SLOWDOWN, shoes.slowdown): SHOES_SLOWDOWN //So you can't put on magboots to make you walk faster.
|
||||
@@ -91,10 +87,6 @@
|
||||
force = 5
|
||||
to_chat(user, "We cling to the terrain below us.")
|
||||
|
||||
/obj/item/clothing/shoes/magboots/changeling/dropped(mob/user)
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
//Armor
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/armored
|
||||
@@ -1,5 +1,5 @@
|
||||
//Updated
|
||||
//Augmented Eyesight: Gives you thermal vision. Also, higher DNA cost because of how powerful it is.
|
||||
|
||||
/datum/power/changeling/augmented_eyesight
|
||||
name = "Augmented Eyesight"
|
||||
desc = "Creates heat receptors in our eyes and dramatically increases light sensing ability."
|
||||
@@ -12,26 +12,21 @@
|
||||
set category = "Changeling"
|
||||
set name = "Augmented Eyesight (5)"
|
||||
set desc = "We evolve our eyes to sense the infrared."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(5,0,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
var/datum/component/antag/changeling/comp = changeling_power(5,0,100,CONSCIOUS)
|
||||
if(!comp)
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/C = src
|
||||
|
||||
changeling.thermal_sight = !changeling.thermal_sight
|
||||
comp.thermal_sight = !comp.thermal_sight
|
||||
|
||||
var/active = changeling.thermal_sight
|
||||
var/active = comp.thermal_sight
|
||||
|
||||
if(active)
|
||||
src.mind.changeling.chem_charges -= 5
|
||||
comp.chem_charges -= 5
|
||||
to_chat(C, span_notice("We feel a minute twitch in our eyes, and a hidden layer to the world is revealed."))
|
||||
C.add_modifier(/datum/modifier/changeling/thermal_sight, 0, src)
|
||||
// C.permanent_sight_flags |= SEE_MOBS
|
||||
// C.dna.species.invis_sight = SEE_INVISIBLE_MINIMUM
|
||||
else
|
||||
to_chat(C, span_notice("Our vision dulls."))
|
||||
C.remove_modifiers_of_type(/datum/modifier/changeling/thermal_sight)
|
||||
// C.permanent_sight_flags &= ~SEE_MOBS
|
||||
// C.dna.species.invis_sight = initial(user.dna.species.invis_sight)
|
||||
return 1
|
||||
@@ -15,29 +15,29 @@
|
||||
set name = "Bioelectrogenesis (20 + 10/shock)"
|
||||
set desc = "Recharges anything in your hand, or shocks people."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
|
||||
var/obj/held_item = get_active_hand()
|
||||
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(held_item == null)
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
if(changeling_generic_weapon(/obj/item/electric_hand/efficent,0))
|
||||
to_chat(src, span_notice("We will shock others more efficently."))
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
if(changeling_generic_weapon(/obj/item/electric_hand,0)) //Chemical cost is handled in the equip proc.
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
else
|
||||
// Handle glove conductivity.
|
||||
var/obj/item/clothing/gloves/gloves = src.gloves
|
||||
var/siemens = 1
|
||||
if(gloves)
|
||||
siemens = gloves.siemens_coefficient
|
||||
siemens = gloves.siemens_coefficient //Funnily enough, this means things like Knights Gloves will make you stun 2x harder and charge 2x more!
|
||||
|
||||
//If we're grabbing someone, electrocute them.
|
||||
if(istype(held_item,/obj/item/grab))
|
||||
@@ -55,13 +55,13 @@
|
||||
span_warningplain("You hear sparks!"))
|
||||
else
|
||||
to_chat(src, span_warning("Our gloves block us from shocking \the [G.affecting]."))
|
||||
src.mind.changeling.chem_charges -= 10
|
||||
return 1
|
||||
changeling.chem_charges -= 10
|
||||
return TRUE
|
||||
|
||||
//Otherwise, charge up whatever's in their hand.
|
||||
else
|
||||
//This checks both the active hand, and the contents of the active hand's held item.
|
||||
var/success = 0
|
||||
var/success = FALSE
|
||||
var/list/L = new() //We make a new list to avoid copypasta.
|
||||
|
||||
//Check our hand.
|
||||
@@ -75,26 +75,14 @@
|
||||
//Now for the actual recharging.
|
||||
for(var/obj/item/cell/cell in L)
|
||||
visible_message(span_warning("Some sparks fall out from \the [src.name]\'s [held_item]!"),
|
||||
span_warning("Our hand channels raw electricity into \the [held_item]."),
|
||||
span_warning("Our hand channels raw electricity into \the [held_item]. We must remain by the [held_item] to recharge it."),
|
||||
span_warningplain("You hear sparks!"))
|
||||
var/i = 10
|
||||
if(siemens)
|
||||
while(i)
|
||||
cell.charge += 100 * siemens //This should be a nice compromise between recharging guns and other batteries.
|
||||
if(cell.charge > cell.maxcharge)
|
||||
cell.charge = cell.maxcharge
|
||||
break
|
||||
if(siemens)
|
||||
var/T = get_turf(src)
|
||||
new /obj/effect/effect/sparks(T)
|
||||
held_item.update_icon()
|
||||
i--
|
||||
sleep(1 SECOND)
|
||||
success = 1
|
||||
if(success == 0) //If we couldn't do anything with the ability, don't deduct the chemicals.
|
||||
cell.gradual_charge(10, siemens, TRUE, src)
|
||||
success = TRUE
|
||||
if(success == FALSE) //If we couldn't do anything with the ability, don't deduct the chemicals.
|
||||
to_chat(src, span_warning("We are unable to affect \the [held_item]."))
|
||||
else
|
||||
src.mind.changeling.chem_charges -= 10
|
||||
changeling.chem_charges -= 10
|
||||
return success
|
||||
|
||||
/obj/item/electric_hand
|
||||
@@ -103,6 +91,7 @@
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "electric_hand"
|
||||
show_examine = FALSE
|
||||
destroy_on_drop = TRUE
|
||||
|
||||
var/shock_cost = 10
|
||||
var/agony_amount = 60
|
||||
@@ -122,12 +111,6 @@
|
||||
var/T = get_turf(src)
|
||||
new /obj/effect/effect/sparks(T)
|
||||
|
||||
/obj/item/electric_hand/dropped(mob/user)
|
||||
..()
|
||||
spawn(1)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/electric_hand/afterattack(var/atom/target, var/mob/living/carbon/human/user, proximity)
|
||||
if(!target)
|
||||
return
|
||||
@@ -141,12 +124,13 @@
|
||||
siemens = gloves.siemens_coefficient
|
||||
|
||||
//Excuse the copypasta.
|
||||
var/datum/component/antag/changeling/comp = is_changeling(user)
|
||||
if(istype(target,/mob/living/carbon))
|
||||
var/mob/living/carbon/C = target
|
||||
|
||||
if(user.mind.changeling.chem_charges < shock_cost)
|
||||
if(comp.chem_charges < shock_cost)
|
||||
to_chat(src, span_warning("We require more chemicals to electrocute [C]!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
C.electrocute_act(electrocute_amount * siemens,src,1.0,BP_TORSO)
|
||||
C.stun_effect_act(0, agony_amount * siemens, BP_TORSO, src)
|
||||
@@ -159,16 +143,15 @@
|
||||
span_warningplain("You hear sparks!"))
|
||||
else
|
||||
to_chat(src, span_warning("Our gloves block us from shocking \the [C]."))
|
||||
//qdel(src) //Since we're no longer a one hit stun, we need to stick around.
|
||||
user.mind.changeling.chem_charges -= shock_cost
|
||||
return 1
|
||||
comp.chem_charges -= shock_cost
|
||||
return TRUE
|
||||
|
||||
else if(istype(target,/mob/living/silicon))
|
||||
var/mob/living/silicon/S = target
|
||||
|
||||
if(user.mind.changeling.chem_charges < 10)
|
||||
if(comp.chem_charges < 10)
|
||||
to_chat(src, span_warning("We require more chemicals to electrocute [S]!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
S.electrocute_act(60,src,0.75) //If only they had surge protectors.
|
||||
if(siemens)
|
||||
@@ -176,38 +159,22 @@
|
||||
span_warning("Our hand channels raw electricity into [S]"),
|
||||
span_warningplain("You hear sparks!"))
|
||||
to_chat(S, span_danger("Warning: Electrical surge detected!"))
|
||||
//qdel(src)
|
||||
user.mind.changeling.chem_charges -= 10
|
||||
return 1
|
||||
comp.chem_charges -= 10
|
||||
return TRUE
|
||||
|
||||
else
|
||||
if(istype(target,/obj/))
|
||||
var/success = 0
|
||||
var/success = FALSE
|
||||
var/obj/T = target
|
||||
//We can also recharge things we touch, such as APCs or hardsuits.
|
||||
for(var/obj/item/cell/cell in T.contents)
|
||||
visible_message(span_warning("Some sparks fall out from \the [target]!"),
|
||||
span_warning("Our hand channels raw electricity into \the [target]."),
|
||||
span_warningplain("You hear sparks!"))
|
||||
var/i = 10
|
||||
if(siemens)
|
||||
while(i)
|
||||
cell.charge += 100 * siemens //This should be a nice compromise between recharging guns and other batteries.
|
||||
if(cell.charge > cell.maxcharge)
|
||||
cell.charge = cell.maxcharge
|
||||
break //No point making sparks if the cell's full.
|
||||
// if(!Adjacent(T))
|
||||
// break
|
||||
if(siemens)
|
||||
var/Turf = get_turf(src)
|
||||
new /obj/effect/effect/sparks(Turf)
|
||||
T.update_icon()
|
||||
i--
|
||||
sleep(1 SECOND)
|
||||
success = 1
|
||||
break
|
||||
if(success == 0)
|
||||
cell.gradual_charge(10, siemens, TRUE, src)
|
||||
success = TRUE
|
||||
if(success == FALSE)
|
||||
to_chat(src, span_warning("We are unable to affect \the [target]."))
|
||||
else
|
||||
qdel(src)
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -1,30 +1,35 @@
|
||||
//Updated
|
||||
/datum/power/changeling/blind_sting
|
||||
name = "Blind Sting"
|
||||
desc = "We silently sting a human, completely blinding them for a short time."
|
||||
enhancedtext = "Duration is extended."
|
||||
ability_icon_state = "ling_sting_blind"
|
||||
genomecost = 2
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_blind_sting
|
||||
|
||||
/mob/proc/changeling_blind_sting()
|
||||
set category = "Changeling"
|
||||
set name = "Blind sting (20)"
|
||||
set desc="Sting target"
|
||||
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting)
|
||||
if(!T)
|
||||
return 0
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Blind sting (changeling)")
|
||||
to_chat(T, span_danger("Your eyes burn horrificly!"))
|
||||
T.disabilities |= NEARSIGHTED
|
||||
var/duration = 300
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
duration = duration + 150
|
||||
var/duration = 30 SECONDS
|
||||
if(comp.recursive_enhancement)
|
||||
duration = duration + 15 SECONDS
|
||||
to_chat(src, span_notice("They will be deprived of sight for longer."))
|
||||
spawn(duration)
|
||||
T.disabilities &= ~NEARSIGHTED
|
||||
addtimer(CALLBACK(T, PROC_REF(nearsighted_sting_complete),T), duration, TIMER_DELETE_ME)
|
||||
T.Blind(10)
|
||||
T.eye_blurry = 20
|
||||
feedback_add_details("changeling_powers","BS")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/proc/nearsighted_sting_complete(mob/target, mode)
|
||||
if(!target)
|
||||
return
|
||||
target.disabilities &= ~NEARSIGHTED
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/boost_range
|
||||
name = "Boost Range"
|
||||
desc = "We evolve the ability to shoot our stingers at humans, with some preperation."
|
||||
@@ -5,7 +6,7 @@
|
||||
enhancedtext = "The range is extended to five tiles."
|
||||
ability_icon_state = "ling_sting_boost_range"
|
||||
genomecost = 1
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_boost_range
|
||||
|
||||
//Boosts the range of your next sting attack by 1
|
||||
@@ -14,18 +15,21 @@
|
||||
set name = "Ranged Sting (10)"
|
||||
set desc="Your next sting ability can be used against targets 2 squares away."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(10,0,100)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(10,0,100)
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
if(!changeling.recursive_enhancement && changeling.sting_range > 1)
|
||||
to_chat(src, span_notice("We have already empowered our sting!"))
|
||||
return
|
||||
else if(changeling.recursive_enhancement && changeling.sting_range > 2)
|
||||
to_chat(src, span_notice("We have already empowered our sting!"))
|
||||
return
|
||||
changeling.chem_charges -= 10
|
||||
to_chat(src, span_notice("Your throat adjusts to launch the sting."))
|
||||
var/range = 2
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
range = range + 3
|
||||
to_chat(src, span_notice("We can fire our next sting from five squares away."))
|
||||
changeling.sting_range = range
|
||||
remove_verb(src, /mob/proc/changeling_boost_range)
|
||||
spawn(5)
|
||||
add_verb(src, /mob/proc/changeling_boost_range)
|
||||
feedback_add_details("changeling_powers","RS")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -13,19 +13,25 @@
|
||||
set name = "Cryogenic Sting (20)"
|
||||
set desc = "Chills and freezes a biological creature."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_cryo_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_cryo_sting, CRYO_STING)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!T)
|
||||
return 0
|
||||
return FALSE
|
||||
if(comp.is_on_cooldown(CRYO_STING))
|
||||
to_chat(src, span_notice("We are still recovering. We will be able to sting again in [(comp.get_cooldown(CRYO_STING) - world.time)/10] seconds."))
|
||||
return
|
||||
|
||||
add_attack_logs(src,T,"Cryo sting (changeling)")
|
||||
var/inject_amount = 10
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
inject_amount = inject_amount * 1.5
|
||||
to_chat(src, span_notice("We inject extra chemicals."))
|
||||
if(T.reagents)
|
||||
T.reagents.add_reagent(REAGENT_ID_CRYOTOXIN, inject_amount)
|
||||
feedback_add_details("changeling_powers","CS")
|
||||
remove_verb(src, /mob/proc/changeling_cryo_sting)
|
||||
spawn(3 MINUTES)
|
||||
to_chat(src, span_notice("Our cryogenic string is ready to be used once more."))
|
||||
add_verb(src, /mob/proc/changeling_cryo_sting)
|
||||
return 1
|
||||
comp.set_cooldown(CRYO_STING, 3 MINUTES) //Set the cooldown to 3 minutes.
|
||||
addtimer(CALLBACK(src, PROC_REF(changeling_cryo_sting_ready)), 3 MINUTES, TIMER_DELETE_ME) //Calling a proc with arguments
|
||||
return TRUE
|
||||
|
||||
/mob/proc/changeling_cryo_sting_ready()
|
||||
to_chat(src, span_notice("Our cryogenic string is ready to be used once more."))
|
||||
@@ -11,7 +11,7 @@
|
||||
set name = "Toggle Darkvision"
|
||||
set desc = "We are able see in the dark."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
enhancedtext = "Deafness duration is extended."
|
||||
ability_icon_state = "ling_sting_deafen"
|
||||
genomecost = 1
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_deaf_sting
|
||||
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
set desc="Sting target:"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!T) return 0
|
||||
add_attack_logs(src,T,"Deaf sting (changeling)")
|
||||
var/duration = 300
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
duration = duration + 100
|
||||
to_chat(src, span_notice("They will be unable to hear for a little longer."))
|
||||
to_chat(T, span_danger("Your ears pop and begin ringing loudly!"))
|
||||
@@ -26,11 +26,12 @@
|
||||
set desc = "Injects the target with a toxin that will take effect after a few minutes."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_delayed_toxic_sting)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!T)
|
||||
return 0
|
||||
add_attack_logs(src,T,"Delayed toxic sting (chagneling)")
|
||||
var/type_to_give = /datum/modifier/delayed_toxin_sting
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
type_to_give = /datum/modifier/delayed_toxin_sting/strong
|
||||
to_chat(src, span_notice("Our toxin will be extra potent, when it strikes."))
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/datum/power/changeling/DigitalCamoflague
|
||||
/datum/power/changeling/digital_camoflague
|
||||
name = "Digital Camoflauge"
|
||||
desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras."
|
||||
helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this."
|
||||
ability_icon_state = "ling_digital_camo"
|
||||
genomecost = 1
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_digitalcamo
|
||||
|
||||
//Prevents AIs tracking you but makes you easily detectable to the human-eye.
|
||||
@@ -13,7 +13,7 @@
|
||||
set name = "Toggle Digital Camoflague"
|
||||
set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power()
|
||||
var/datum/component/antag/changeling/changeling = changeling_power()
|
||||
if(!changeling)
|
||||
return 0
|
||||
|
||||
@@ -25,12 +25,9 @@
|
||||
C.digitalcamo = !C.digitalcamo
|
||||
|
||||
spawn(0)
|
||||
while(C && C.digitalcamo && C.mind && C.mind.changeling)
|
||||
C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0)
|
||||
while(C && C.digitalcamo && C.mind && changeling)
|
||||
changeling.chem_charges = max(changeling.chem_charges - 1, 0)
|
||||
sleep(40)
|
||||
|
||||
remove_verb(src, /mob/proc/changeling_digitalcamo)
|
||||
spawn(5)
|
||||
add_verb(src, /mob/proc/changeling_digitalcamo)
|
||||
feedback_add_details("changeling_powers","CAM")
|
||||
return 1
|
||||
@@ -13,7 +13,7 @@
|
||||
set name = "Electric Lockpick (5 + 10/use)"
|
||||
set desc = "Bruteforces open most electrical locking systems, at 10 chemicals per use."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(5,0,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(5,0,100,CONSCIOUS)
|
||||
|
||||
var/obj/held_item = get_active_hand()
|
||||
|
||||
@@ -49,11 +49,10 @@
|
||||
return
|
||||
if(!proximity)
|
||||
return
|
||||
if(!user.mind.changeling)
|
||||
var/datum/component/antag/changeling/ling_datum = is_changeling(user)
|
||||
if(!ling_datum)
|
||||
return
|
||||
|
||||
var/datum/changeling/ling_datum = user.mind.changeling
|
||||
|
||||
if(ling_datum.chem_charges < 10)
|
||||
to_chat(user, span_warning("We require more chemicals to do that."))
|
||||
return
|
||||
@@ -1,9 +1,10 @@
|
||||
//Updated
|
||||
/datum/power/changeling/endoarmor
|
||||
name = "Endoarmor"
|
||||
desc = "We grow hard plating underneath our skin, making us more resilient to harm by increasing our maximum health potential by 50 points."
|
||||
helptext = "Our maximum health is increased by 50 points."
|
||||
genomecost = 1
|
||||
isVerb = 0
|
||||
isVerb = FALSE
|
||||
verbpath = /mob/proc/changeling_endoarmor
|
||||
|
||||
/datum/modifier/endoarmor
|
||||
@@ -18,5 +19,4 @@
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
H.add_modifier(/datum/modifier/endoarmor)
|
||||
// H.maxHealth += 50
|
||||
return 1
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/enfeebling_string
|
||||
name = "Enfeebling String"
|
||||
desc = "We sting a biological with a potent toxin that will greatly weaken them for a short period of time."
|
||||
@@ -30,6 +31,7 @@
|
||||
set desc = "Reduces the maximum health of a victim for a few minutes.."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_enfeebling_string)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!T)
|
||||
return 0
|
||||
if(ishuman(T))
|
||||
@@ -38,7 +40,7 @@
|
||||
add_attack_logs(src,T,"Enfeebling sting (changeling)")
|
||||
|
||||
var/type_to_give = /datum/modifier/enfeeble
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
type_to_give = /datum/modifier/enfeeble/strong
|
||||
to_chat(src, span_notice("We make them extremely weak."))
|
||||
H.add_modifier(type_to_give, 2 MINUTES)
|
||||
@@ -1,4 +1,5 @@
|
||||
/datum/power/changeling/EngorgedGlands
|
||||
//Updated
|
||||
/datum/power/changeling/engorged_glands
|
||||
name = "Engorged Chemical Glands"
|
||||
desc = "Our chemical glands swell, permitting us to store more chemicals inside of them."
|
||||
helptext = "Allows us to store an extra 30 units of chemicals, and doubles production rate."
|
||||
@@ -8,6 +9,7 @@
|
||||
|
||||
//Increases macimum chemical storage
|
||||
/mob/proc/changeling_engorgedglands()
|
||||
src.mind.changeling.chem_storage += 30
|
||||
src.mind.changeling.chem_recharge_rate *= 2
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
comp.chem_storage += 30
|
||||
comp.chem_recharge_rate *= 2
|
||||
return 1
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/enrage
|
||||
name = "Enrage"
|
||||
desc = "We evolve modifications to our mind and body, allowing us to call on intense periods of rage for our benefit."
|
||||
@@ -8,7 +9,7 @@
|
||||
enhancedtext = "The length of exhaustion after berserking is reduced to one minute, from two, and requires half as much nutrition."
|
||||
ability_icon_state = "ling_berserk"
|
||||
genomecost = 2
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/living/proc/changeling_berserk
|
||||
|
||||
// Makes the ling very upset.
|
||||
@@ -17,12 +18,12 @@
|
||||
set name = "Enrage (30)"
|
||||
set desc = "Causes you to go Berserk."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(30,0,100)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(30,0,100)
|
||||
if(!changeling)
|
||||
return 0
|
||||
|
||||
var/modifier_to_use = /datum/modifier/berserk/changeling
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
modifier_to_use = /datum/modifier/berserk/changeling/recursive
|
||||
to_chat(src, span_notice("We optimize our levels of anger, which will avoid excessive stress on ourselves."))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/epinephrine_overdose
|
||||
name = "Epinephrine Overdose"
|
||||
desc = "We evolve additional sacs of adrenaline throughout our body."
|
||||
@@ -22,7 +23,7 @@
|
||||
set name = "Epinephrine Overdose (30)"
|
||||
set desc = "Removes all stuns instantly, and reduces future stuns."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
changeling.chem_charges -= 30
|
||||
@@ -35,23 +36,21 @@
|
||||
C.SetWeakened(0)
|
||||
C.lying = 0
|
||||
C.update_canmove()
|
||||
// C.reagents.add_reagent(REAGENT_ID_TOXIN, 10)
|
||||
C.reagents.add_reagent("epinephrine", 20)
|
||||
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
C.add_modifier(/datum/modifier/unstoppable, 30 SECONDS)
|
||||
|
||||
feedback_add_details("changeling_powers","UNS")
|
||||
return 1
|
||||
|
||||
/datum/reagent/epinephrine
|
||||
name = "Epinephrine"
|
||||
id = "epinephrine"
|
||||
description = "Reduces stun times, but causing toxicity due to high concentration."
|
||||
name = REAGENT_EPINEPHRINE
|
||||
id = REAGENT_ID_EPINEPHRINE
|
||||
description = "A chemically naturally produced by the body while in fight-or-flight mode. Greatly increases one's strength."
|
||||
reagent_state = LIQUID
|
||||
color = "#C8A5DC"
|
||||
metabolism = REM * 2
|
||||
overdose = 5 //This is intentionally low, as we want the ling to take some tox damage, to discourage spamming the ability.
|
||||
wiki_flag = WIKI_SPOILER
|
||||
|
||||
/datum/reagent/epinephrine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
|
||||
@@ -63,5 +62,6 @@
|
||||
M.AdjustParalysis(-2)
|
||||
M.AdjustStunned(-2)
|
||||
M.AdjustWeakened(-2)
|
||||
M.adjustToxLoss(removed * 2.5) //It gives you 20units of epinephrine. 50 toxins damage. 1 Toxin per tick.
|
||||
..()
|
||||
return
|
||||
@@ -15,15 +15,15 @@
|
||||
|
||||
var/escape_cooldown = 5 MINUTES //This is used later to prevent spamming
|
||||
var/mob/living/carbon/human/C = src
|
||||
var/datum/changeling/changeling = changeling_power(40,0,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(40,0,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
if(world.time < changeling.next_escape)
|
||||
to_chat(src, span_warning("We are still recovering from our last escape..."))
|
||||
return 0
|
||||
return FALSE
|
||||
if(changeling.is_on_cooldown(ESCAPE_RESTRAINTS))
|
||||
to_chat(src, span_notice("We are still recovering from our last escape. We will be able to escape again in [(changeling.get_cooldown(ESCAPE_RESTRAINTS) - world.time)/10] seconds."))
|
||||
return FALSE
|
||||
if(!(C.handcuffed || C.legcuffed || istype(C.wear_suit,/obj/item/clothing/suit/straight_jacket))) // No need to waste chems if there's nothing to break out of
|
||||
to_chat(C, span_warning("We are are not restrained in a way we can escape..."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
changeling.chem_charges -= 40
|
||||
|
||||
@@ -58,10 +58,14 @@
|
||||
C.wear_suit = null
|
||||
escape_cooldown *= 1.5 // Straight jackets are tedious compared to cuffs.
|
||||
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
escape_cooldown *= 0.5
|
||||
|
||||
changeling.next_escape = world.time + escape_cooldown //And now we set the timer
|
||||
changeling.set_cooldown(ESCAPE_RESTRAINTS, escape_cooldown)
|
||||
addtimer(CALLBACK(src, PROC_REF(changeling_escape_restraints_ready)), escape_cooldown, TIMER_DELETE_ME)
|
||||
|
||||
feedback_add_details("changeling_powers","ESR")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/proc/changeling_escape_restraints_ready()
|
||||
to_chat(src, span_notice("We are able to escape our restraints once more."))
|
||||
@@ -1,10 +1,11 @@
|
||||
/datum/power/changeling/extractdna
|
||||
//Updated
|
||||
/datum/power/changeling/extract_dna
|
||||
name = "Extract DNA"
|
||||
desc = "We stealthily sting a target and extract the DNA from them."
|
||||
helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives."
|
||||
ability_icon_state = "ling_sting_extract"
|
||||
genomecost = 0
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_extract_dna_sting
|
||||
|
||||
/mob/proc/changeling_extract_dna_sting()
|
||||
@@ -12,11 +13,11 @@
|
||||
set name = "Extract DNA Sting (40)"
|
||||
set desc="Stealthily sting a target to extract their DNA."
|
||||
|
||||
var/datum/changeling/changeling = null
|
||||
if(src.mind && src.mind.changeling)
|
||||
changeling = src.mind.changeling
|
||||
var/datum/component/antag/changeling/changeling = null
|
||||
if(src.mind && changeling)
|
||||
changeling = changeling
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting)
|
||||
|
||||
@@ -25,15 +26,15 @@
|
||||
|
||||
if(!istype(T) || T.isSynthetic())
|
||||
to_chat(src, span_warning("\The [T] is not compatible with our biology."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(T.species.flags & (NO_DNA|NO_SLEEVE))
|
||||
to_chat(src, span_warning("We do not know how to parse this creature's DNA!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(HUSK in T.mutations)
|
||||
to_chat(src, span_warning("This creature's DNA is ruined beyond useability!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
add_attack_logs(src,T,"DNA extraction sting (changeling)")
|
||||
|
||||
@@ -42,4 +43,4 @@
|
||||
absorbDNA(newDNA)
|
||||
|
||||
feedback_add_details("changeling_powers","ED")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -1,3 +1,4 @@
|
||||
//Needs a BIG rework.
|
||||
var/global/list/changeling_fabricated_clothing = list(
|
||||
"w_uniform" = /obj/item/clothing/under/chameleon/changeling,
|
||||
"head" = /obj/item/clothing/head/chameleon/changeling,
|
||||
@@ -1,10 +1,10 @@
|
||||
/datum/power/changeling/fakedeath
|
||||
/datum/power/changeling/fake_death
|
||||
name = "Regenerative Stasis"
|
||||
desc = "We become weakened to a death-like state, where we will rise again from death."
|
||||
helptext = "Can be used before or after death. Duration varies greatly."
|
||||
ability_icon_state = "ling_regenerative_stasis"
|
||||
genomecost = 0
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_fakedeath
|
||||
|
||||
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
|
||||
@@ -12,7 +12,7 @@
|
||||
set category = "Changeling"
|
||||
set name = "Regenerative Stasis (20)"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(CHANGELING_STASIS_COST,1,100,DEAD)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(CHANGELING_STASIS_COST,1,100,DEAD)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
@@ -24,30 +24,29 @@
|
||||
|
||||
if(!C.stat && tgui_alert(src, "Are we sure we wish to regenerate? We will appear to be dead while doing so.","Revival",list("Yes","No")) != "Yes")
|
||||
return
|
||||
to_chat(C, span_notice("We will attempt to regenerate our form."))
|
||||
|
||||
C.update_canmove()
|
||||
C.remove_changeling_powers()
|
||||
changeling.chem_charges -= CHANGELING_STASIS_COST
|
||||
|
||||
if(C.suiciding)
|
||||
C.suiciding = 0
|
||||
C.suiciding = FALSE
|
||||
|
||||
if(C.does_not_breathe)
|
||||
C.does_not_breathe = 0 //This means they don't autoheal the oxy damage from the next step
|
||||
C.does_not_breathe = FALSE //This means they don't autoheal the oxy damage from the next step
|
||||
|
||||
if(C.stat != DEAD)
|
||||
C.adjustOxyLoss(C.getMaxHealth() * 2)
|
||||
|
||||
C.forbid_seeing_deadchat = TRUE
|
||||
|
||||
spawn(rand(2 MINUTES, 4 MINUTES))
|
||||
//The ling will now be able to choose when to revive
|
||||
add_verb(src, /mob/proc/changeling_revive)
|
||||
|
||||
new /obj/changeling_revive_holder(src)
|
||||
|
||||
to_chat(src, span_notice(span_giant("We are ready to rise. Use the <b>Revive</b> verb when you are ready.")))
|
||||
|
||||
var/resurrection_time = rand(2 MINUTES, 4 MINUTES)
|
||||
changeling.set_cooldown(FAKE_DEATH, resurrection_time)
|
||||
changeling.is_reviving = TRUE
|
||||
to_chat(C, span_notice("We will attempt to regenerate our form. This will take [(changeling.get_cooldown(FAKE_DEATH) - world.time)/600] minutes."))
|
||||
addtimer(CALLBACK(src, PROC_REF(finish_changeling_revive)), resurrection_time, TIMER_DELETE_ME)
|
||||
feedback_add_details("changeling_powers","FD")
|
||||
return 1
|
||||
|
||||
/mob/proc/finish_changeling_revive()
|
||||
//Lets the ling know it's revive time.
|
||||
to_chat(src, span_notice(span_giant("We are ready to rise. Use the <b>Revive</b> verb when you are ready.")))
|
||||
53
code/datums/components/antags/changeling/powers/fleshmend.dm
Normal file
53
code/datums/components/antags/changeling/powers/fleshmend.dm
Normal file
@@ -0,0 +1,53 @@
|
||||
/datum/power/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Begins a slow regeneration of our form. Does not effect stuns or chemicals."
|
||||
helptext = "Can be used while unconscious."
|
||||
enhancedtext = "Healing is twice as effective."
|
||||
ability_icon_state = "ling_fleshmend"
|
||||
genomecost = 1
|
||||
verbpath = /mob/proc/changeling_fleshmend
|
||||
|
||||
//Starts healing you every second for 50 seconds. Can be used whilst unconscious.
|
||||
/mob/proc/changeling_fleshmend()
|
||||
set category = "Changeling"
|
||||
set name = "Fleshmend (10)"
|
||||
set desc = "Begins a slow rengeration of our form. Does not effect stuns or chemicals."
|
||||
|
||||
var/mob/living/C = src
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(10,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
if(C.has_modifier_of_type(/datum/modifier/fleshmend))
|
||||
to_chat(src, span_notice("We are already under the effect of fleshmend."))
|
||||
return FALSE
|
||||
|
||||
changeling.chem_charges -= 10
|
||||
|
||||
if(changeling.recursive_enhancement)
|
||||
to_chat(src, span_notice("We will heal much faster."))
|
||||
C.add_modifier(/datum/modifier/fleshmend/recursive, 50 SECONDS)
|
||||
else
|
||||
C.add_modifier(/datum/modifier/fleshmend, 50 SECONDS)
|
||||
|
||||
feedback_add_details("changeling_powers","FM")
|
||||
return TRUE
|
||||
|
||||
/datum/modifier/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "We are regenerating"
|
||||
|
||||
// For changelings who bought the Recursive Enhancement evolution.
|
||||
/datum/modifier/fleshmend/recursive
|
||||
name = "Advanced Fleshmend"
|
||||
desc = "We are regenerating more rapidly."
|
||||
|
||||
//These were previously 2 or 4 per second, now it's 4 or 8 per 2 seconds
|
||||
/datum/modifier/fleshmend/tick()
|
||||
holder.adjustBruteLoss(-4)
|
||||
holder.adjustOxyLoss(-4)
|
||||
holder.adjustFireLoss(-4)
|
||||
|
||||
/datum/modifier/fleshmend/recursive/tick()
|
||||
holder.adjustBruteLoss(-8)
|
||||
holder.adjustOxyLoss(-8)
|
||||
holder.adjustFireLoss(-8)
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
// Hivemind
|
||||
|
||||
/datum/power/changeling/hive_upload
|
||||
@@ -5,7 +6,7 @@
|
||||
desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves."
|
||||
helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives."
|
||||
genomecost = 0
|
||||
make_hud_button = 0
|
||||
make_hud_button = FALSE
|
||||
verbpath = /mob/proc/changeling_hiveupload
|
||||
|
||||
/datum/power/changeling/hive_download
|
||||
@@ -13,7 +14,7 @@
|
||||
desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings."
|
||||
helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective."
|
||||
genomecost = 0
|
||||
make_hud_button = 0
|
||||
make_hud_button = FALSE
|
||||
verbpath = /mob/proc/changeling_hivedownload
|
||||
|
||||
// HIVE MIND UPLOAD/DOWNLOAD DNA
|
||||
@@ -25,8 +26,9 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Hive Channel (10)"
|
||||
set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(10,1)
|
||||
if(!changeling) return
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(10,1)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
|
||||
@@ -38,7 +40,8 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
return
|
||||
|
||||
var/S = tgui_input_list(src, "Select a DNA to channel:", "Channel DNA", names)
|
||||
if(!S) return
|
||||
if(!S)
|
||||
return
|
||||
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
@@ -48,15 +51,16 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
hivemind_bank += chosen_dna
|
||||
to_chat(src, span_notice("We channel the DNA of [S] to the air."))
|
||||
feedback_add_details("changeling_powers","HU")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/proc/changeling_hivedownload()
|
||||
set category = "Changeling"
|
||||
set name = "Hive Absorb (20)"
|
||||
set desc = "Allows you to absorb DNA that is being channeled in the airwaves."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(20,1)
|
||||
if(!changeling) return
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(20,1)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/absorbed_dna/DNA in hivemind_bank)
|
||||
@@ -68,7 +72,8 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
return
|
||||
|
||||
var/S = tgui_input_list(src, "Select a DNA to absorb:", "Absorb DNA", names)
|
||||
if(!S) return
|
||||
if(!S)
|
||||
return
|
||||
var/datum/absorbed_dna/chosen_dna = names[S]
|
||||
if(!chosen_dna)
|
||||
return
|
||||
@@ -77,4 +82,4 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
absorbDNA(chosen_dna)
|
||||
to_chat(src, span_notice("We absorb the DNA of [S] from the air."))
|
||||
feedback_add_details("changeling_powers","HD")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -9,10 +9,11 @@
|
||||
set category = "Changeling"
|
||||
set name = "Lesser Form (1)"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(1,0,0)
|
||||
if(!changeling) return
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(1,0,0)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
if(src.has_brain_worms())
|
||||
if(has_brain_worms())
|
||||
to_chat(src, span_warning("We cannot perform this ability at the present time!"))
|
||||
return
|
||||
|
||||
@@ -39,7 +40,7 @@
|
||||
set category = "Changeling"
|
||||
set name = "Transform (1)"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(1,1,0)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(1,1,0)
|
||||
if(!changeling) return
|
||||
|
||||
var/list/names = list()
|
||||
@@ -47,7 +48,8 @@
|
||||
names += "[DNA.real_name]"
|
||||
|
||||
var/S = tgui_input_list(src, "Select the target DNA:", "Target DNA", names)
|
||||
if(!S) return
|
||||
if(!S)
|
||||
return
|
||||
|
||||
var/datum/dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
@@ -1,5 +1,5 @@
|
||||
//This only exists to be abused, so it's highly recommended to ensure this file is unchecked.
|
||||
/datum/power/changeling/LSDSting
|
||||
/datum/power/changeling/lsd_sting
|
||||
name = "Hallucination Sting"
|
||||
desc = "We evolve the ability to sting a target with a powerful hallunicationary chemical."
|
||||
helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds."
|
||||
@@ -12,9 +12,9 @@
|
||||
set desc = "Causes terror in the target."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting)
|
||||
if(!T) return 0
|
||||
if(!T)
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Hallucination sting (changeling)")
|
||||
spawn(rand(300,600))
|
||||
if(T) T.hallucination += 400
|
||||
addtimer(VARSET_CALLBACK(T, hallucination, min(T.hallucination+400, 400)), rand(30 SECONDS, 60 SECONDS), TIMER_DELETE_ME) //No going ABOVE 400 hallucinations.
|
||||
feedback_add_details("changeling_powers","HS")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -14,7 +14,7 @@
|
||||
set desc = "Shape our vocal glands to form a voice of someone we choose. We cannot regenerate chemicals when mimicing."
|
||||
|
||||
|
||||
var/datum/changeling/changeling = changeling_power()
|
||||
var/datum/component/antag/changeling/changeling = changeling_power()
|
||||
if(!changeling) return
|
||||
|
||||
if(changeling.mimicing)
|
||||
@@ -34,8 +34,8 @@
|
||||
feedback_add_details("changeling_powers","MV")
|
||||
|
||||
spawn(0)
|
||||
while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing)
|
||||
src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0)
|
||||
while(src && src.mind && changeling && changeling.mimicing)
|
||||
changeling.chem_charges = max(changeling.chem_charges - 1, 0)
|
||||
sleep(40)
|
||||
if(src && src.mind && src.mind.changeling)
|
||||
src.mind.changeling.mimicing = ""
|
||||
if(src && src.mind && changeling)
|
||||
changeling.mimicing = ""
|
||||
@@ -13,10 +13,10 @@
|
||||
set name = "Anatomic Panacea (20)"
|
||||
set desc = "Clense ourselves of impurities."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(20,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(20,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
src.mind.changeling.chem_charges -= 20
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
to_chat(src, span_notice("We cleanse impurities from our form."))
|
||||
|
||||
@@ -30,10 +30,11 @@
|
||||
|
||||
|
||||
var/heal_amount = 5
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
heal_amount = heal_amount * 2
|
||||
to_chat(src, span_notice("We will heal much faster."))
|
||||
|
||||
//TODO: Replace with a modifier.
|
||||
for(var/i = 0, i<10,i++)
|
||||
if(C)
|
||||
C.adjustToxLoss(-heal_amount)
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/paralysis_sting
|
||||
name = "Paralysis Sting"
|
||||
desc = "We silently sting a human, paralyzing them for a short time."
|
||||
@@ -11,9 +12,9 @@
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting)
|
||||
if(!T)
|
||||
return 0
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Paralysis sting (changeling)")
|
||||
to_chat(T, span_danger("Your muscles begin to painfully tighten."))
|
||||
T.Weaken(20)
|
||||
feedback_add_details("changeling_powers","PS")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -14,15 +14,15 @@
|
||||
set name = "Rapid Regeneration (50)"
|
||||
set desc = "Heal ourselves of most injuries instantly."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(50,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(50,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
src.mind.changeling.chem_charges -= 50
|
||||
changeling.chem_charges -= 50
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/C = src
|
||||
var/healing_amount = 40
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
healing_amount = C.getMaxHealth()
|
||||
to_chat(src, span_notice("We completely heal ourselves."))
|
||||
spawn(0)
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
// make the icons look correct
|
||||
C.regenerate_icons()
|
||||
C.UpdateAppearance()
|
||||
|
||||
// now make it obvious that we're not human (or whatever xeno race they are impersonating)
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/recursive_enhancement
|
||||
name = "Recursive Enhancement"
|
||||
desc = "We cause our abilities to have increased or additional effects."
|
||||
@@ -11,14 +12,14 @@
|
||||
set category = "Changeling"
|
||||
set name = "Recursive Enhancement"
|
||||
set desc = "Empowers our abilities."
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
return FALSE
|
||||
if(changeling.recursive_enhancement)
|
||||
to_chat(src, span_warning("We will no longer empower our abilities."))
|
||||
src.mind.changeling.recursive_enhancement = 0
|
||||
return 0
|
||||
changeling.recursive_enhancement = FALSE
|
||||
return FALSE
|
||||
to_chat(src, span_notice("We empower ourselves. Our abilities will now be extra potent."))
|
||||
src.mind.changeling.recursive_enhancement = 1
|
||||
changeling.recursive_enhancement = TRUE
|
||||
feedback_add_details("changeling_powers","RE")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -3,22 +3,22 @@
|
||||
set name = "Re-adapt"
|
||||
set desc = "Allows us to refund our purchased abilities."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100)
|
||||
if(!changeling)
|
||||
return
|
||||
if(src.mind.changeling.readapts <= 0)
|
||||
if(changeling.readapts <= 0)
|
||||
to_chat(src, span_warning("We must first absorb another compatible creature!"))
|
||||
src.mind.changeling.readapts = 0
|
||||
changeling.readapts = 0
|
||||
return
|
||||
|
||||
src.remove_changeling_powers() //First, remove the verbs.
|
||||
var/datum/changeling/ling_datum = src.mind.changeling
|
||||
var/datum/component/antag/changeling/ling_datum = changeling
|
||||
ling_datum.readapts--
|
||||
ling_datum.purchased_powers = list() //Then wipe all the powers we bought.
|
||||
ling_datum.geneticpoints = ling_datum.max_geneticpoints //Now refund our points to the maximum.
|
||||
ling_datum.chem_recharge_rate = 0.5 //If glands were bought, revert that upgrade.
|
||||
ling_datum.thermal_sight = FALSE
|
||||
src.mind.changeling.recursive_enhancement = 0 //Ensures this is cleared
|
||||
changeling.recursive_enhancement = 0 //Ensures this is cleared
|
||||
|
||||
ling_datum.chem_storage = 50
|
||||
if(ishuman(src))
|
||||
@@ -1,16 +1,35 @@
|
||||
/datum/power/changeling/changeling_revive
|
||||
name = "Revive"
|
||||
desc = "We revive from our death-like state."
|
||||
helptext = "Regeneration must first be started via Regenerative Stasis."
|
||||
ability_icon_state = "ling_revive"
|
||||
genomecost = 0
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_revive
|
||||
|
||||
//Revive from revival stasis
|
||||
/mob/proc/changeling_revive()
|
||||
set category = "Changeling"
|
||||
set name = "Revive"
|
||||
set desc = "We are ready to revive ourselves on command."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100,DEAD)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100,DEAD)
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(stat != DEAD)
|
||||
to_chat(src, span_danger("We are not dead."))
|
||||
return FALSE
|
||||
if(!changeling.is_reviving)
|
||||
to_chat(src, span_danger("We have not begun the regeneration process yet.."))
|
||||
return FALSE
|
||||
if(changeling.is_on_cooldown(FAKE_DEATH))
|
||||
to_chat(src, span_danger("We are still recovering. We will be able to revive again in [(changeling.get_cooldown(FAKE_DEATH) - world.time)/10] seconds."))
|
||||
return FALSE
|
||||
|
||||
if(changeling.max_geneticpoints < 0) //Absorbed by another ling
|
||||
to_chat(src, span_danger("You have no genomes, not even your own, and cannot revive."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(src.stat == DEAD)
|
||||
dead_mob_list -= src
|
||||
@@ -72,38 +91,16 @@
|
||||
SJ.forceMove(H.loc)
|
||||
SJ.dropped(H)
|
||||
H.wear_suit = null
|
||||
H.UpdateAppearance()
|
||||
|
||||
C.halloss = 0
|
||||
C.shock_stage = 0 //Pain
|
||||
to_chat(C, span_notice("We have regenerated."))
|
||||
C.update_canmove()
|
||||
C.mind.changeling.purchased_powers -= C
|
||||
feedback_add_details("changeling_powers","CR")
|
||||
C.set_stat(CONSCIOUS)
|
||||
C.forbid_seeing_deadchat = FALSE
|
||||
C.timeofdeath = null
|
||||
remove_verb(src, /mob/proc/changeling_revive)
|
||||
// re-add our changeling powers
|
||||
C.make_changeling()
|
||||
changeling.is_reviving = FALSE
|
||||
|
||||
return 1
|
||||
|
||||
//Revive from revival stasis, but one level removed, as the tab refuses to update. Placed in its own tab to avoid hyper-exploding the original tab through the same name being used.
|
||||
|
||||
/obj/changeling_revive_holder
|
||||
name = "strange object"
|
||||
desc = "Please report this object's existence to the dev team! You shouldn't see it."
|
||||
mouse_opacity = FALSE
|
||||
alpha = 1
|
||||
|
||||
/obj/changeling_revive_holder/verb/ling_revive()
|
||||
set src = usr.contents
|
||||
set category = "Regenerate"
|
||||
set name = "Revive"
|
||||
set desc = "We are ready to revive ourselves on command."
|
||||
|
||||
if(iscarbon(usr))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.changeling_revive()
|
||||
|
||||
qdel(src)
|
||||
return TRUE
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/self_respiration
|
||||
name = "Self Respiration"
|
||||
desc = "We evolve our body to no longer require drawing oxygen from the atmosphere."
|
||||
@@ -12,20 +13,20 @@
|
||||
set name = "Toggle Breathing"
|
||||
set desc = "We choose whether or not to breathe."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(istype(src,/mob/living/carbon))
|
||||
var/mob/living/carbon/C = src
|
||||
if(C.suiciding)
|
||||
to_chat(src, "You're committing suicide, this isn't going to work.")
|
||||
return 0
|
||||
if(C.does_not_breathe == 0)
|
||||
C.does_not_breathe = 1
|
||||
return FALSE
|
||||
if(C.does_not_breathe == FALSE)
|
||||
C.does_not_breathe = TRUE
|
||||
to_chat(src, span_notice("We stop breathing, as we no longer need to."))
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
C.does_not_breathe = 0
|
||||
C.does_not_breathe = FALSE
|
||||
to_chat(src, span_notice("We resume breathing, as we now need to again."))
|
||||
return 0
|
||||
return FALSE
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/resonant_shriek
|
||||
name = "Resonant Shriek"
|
||||
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
|
||||
@@ -22,32 +23,33 @@
|
||||
set name = "Resonant Shriek (20)"
|
||||
set desc = "Emits a high-frequency sound that confuses and deafens organics, blows out nearby lights, and overloads synthetics' sensors."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
if(!changeling) return 0
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
if(changeling.is_on_cooldown(CHANGELING_SCREECH))
|
||||
to_chat(src, span_notice("We are still recovering. We will be able to screech again in [(changeling.get_cooldown(CHANGELING_SCREECH) - world.time)/10] seconds."))
|
||||
return
|
||||
|
||||
if(is_muzzled())
|
||||
to_chat(src, span_danger("Mmmf mrrfff!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(H.silent)
|
||||
to_chat(src, span_danger("You can't speak!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(world.time < (changeling.last_shriek + 10 SECONDS) )
|
||||
to_chat(src, span_warning("We are still recovering from our last shriek..."))
|
||||
return 0
|
||||
|
||||
if(!isturf(loc))
|
||||
to_chat(src, span_warning("Shrieking here would be a bad idea."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
src.break_cloak() //No more invisible shrieking
|
||||
|
||||
changeling.chem_charges -= 20
|
||||
var/range = 4
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
range = range * 2
|
||||
to_chat(src, span_notice("We are extra loud."))
|
||||
|
||||
@@ -55,7 +57,8 @@
|
||||
var/list/affected = list()
|
||||
for(var/mob/living/M in range(range, src))
|
||||
if(iscarbon(M))
|
||||
if(!M.mind || !M.mind.changeling)
|
||||
var/datum/component/antag/changeling/m_comp = M.GetComponent(/datum/component/antag/changeling)
|
||||
if(!M.mind || !m_comp)
|
||||
if(M.get_ear_protection() >= 2)
|
||||
continue
|
||||
to_chat(M, span_danger("You hear an extremely loud screeching sound! It \
|
||||
@@ -76,14 +79,15 @@
|
||||
affected += M
|
||||
|
||||
for(var/obj/machinery/light/L in range(range, src))
|
||||
L.on = 1
|
||||
L.on = TRUE
|
||||
L.broken()
|
||||
|
||||
changeling.last_shriek = world.time
|
||||
changeling.set_cooldown(CHANGELING_SCREECH, 10 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(changeling_screech_ready)), 10 SECONDS, TIMER_DELETE_ME)
|
||||
|
||||
add_attack_logs(src,affected,"Used resonant shriek")
|
||||
feedback_add_details("changeling_powers","RS")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//EMP version
|
||||
/mob/proc/changeling_dissonant_shriek()
|
||||
@@ -91,28 +95,29 @@
|
||||
set name = "Dissonant Shriek (20)"
|
||||
set desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
if(!changeling) return 0
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(20,0,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
|
||||
if(is_muzzled())
|
||||
to_chat(src, span_danger("Mmmf mrrfff!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(H.silent)
|
||||
to_chat(src, span_danger("You can't speak!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(world.time < (changeling.last_shriek + 10 SECONDS) )
|
||||
to_chat(src, span_warning("We are still recovering from our last shriek..."))
|
||||
return 0
|
||||
if(changeling.is_on_cooldown(CHANGELING_SCREECH))
|
||||
to_chat(src, span_notice("We are still recovering. We will be able to screech again in [(changeling.get_cooldown(CHANGELING_SCREECH) - world.time)/10] seconds."))
|
||||
return
|
||||
|
||||
if(!isturf(loc))
|
||||
to_chat(src, span_warning("Shrieking here would be a bad idea."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
src.break_cloak() //No more invisible shrieking
|
||||
break_cloak() //No more invisible shrieking
|
||||
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
@@ -120,23 +125,24 @@
|
||||
var/range_med = 2
|
||||
var/range_light = 4
|
||||
var/range_long = 6
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(changeling.recursive_enhancement)
|
||||
range_heavy = range_heavy * 2
|
||||
range_med = range_med * 2
|
||||
range_light = range_light * 2
|
||||
range_long = range_long * 2
|
||||
to_chat(src, span_notice("We are extra loud."))
|
||||
src.mind.changeling.recursive_enhancement = 0
|
||||
changeling.recursive_enhancement = FALSE
|
||||
|
||||
visible_message(span_notice("[src] appears to shout."))
|
||||
|
||||
add_attack_logs(src,null,"Use dissonant shriek")
|
||||
|
||||
for(var/obj/machinery/light/L in range(5, src))
|
||||
L.on = 1
|
||||
for(var/obj/machinery/light/L in range(range_light, src))
|
||||
L.on = TRUE
|
||||
L.broken()
|
||||
empulse(get_turf(src), range_heavy, range_light, 1)
|
||||
empulse(get_turf(src), range_heavy, range_med, range_light, range_long)
|
||||
|
||||
changeling.last_shriek = world.time
|
||||
changeling.set_cooldown(CHANGELING_SCREECH, 10 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(changeling_screech_ready)), 10 SECONDS, TIMER_DELETE_ME)
|
||||
visible_message(span_notice("[src] appears to shout."))
|
||||
add_attack_logs(src,null,"Use dissonant shriek")
|
||||
return TRUE
|
||||
|
||||
return 1
|
||||
/mob/proc/changeling_screech_ready()
|
||||
to_chat(src, span_notice("We are ready to release another screech."))
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/silence_sting
|
||||
name = "Silence Sting"
|
||||
desc = "We silently sting a human, completely silencing them for a short time."
|
||||
@@ -5,7 +6,7 @@
|
||||
enhancedtext = "Silence duration is extended."
|
||||
ability_icon_state = "ling_sting_mute"
|
||||
genomecost = 2
|
||||
allowduringlesserform = 1
|
||||
allowduringlesserform = TRUE
|
||||
verbpath = /mob/proc/changeling_silence_sting
|
||||
|
||||
/mob/proc/changeling_silence_sting()
|
||||
@@ -14,12 +15,14 @@
|
||||
set desc="Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting)
|
||||
if(!T) return 0
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Silence sting (changeling)")
|
||||
var/duration = 30
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
if(comp.recursive_enhancement)
|
||||
duration = duration + 10
|
||||
to_chat(src, span_notice("They will be unable to cry out in fear for a little longer."))
|
||||
T.silent += duration
|
||||
feedback_add_details("changeling_powers","SS")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -10,8 +10,9 @@
|
||||
set category = "Changeling"
|
||||
set name = "Transform (5)"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(5,1,0)
|
||||
if(!changeling) return
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(5,1,0)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
if(!isturf(loc))
|
||||
to_chat(src, span_warning("Transforming here would be a bad idea."))
|
||||
@@ -22,7 +23,8 @@
|
||||
names += "[DNA.name]"
|
||||
|
||||
var/S = tgui_input_list(src, "Select the target DNA:", "Target DNA", names)
|
||||
if(!S) return
|
||||
if(!S)
|
||||
return
|
||||
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
@@ -38,13 +40,12 @@
|
||||
H.set_species(newSpecies)
|
||||
|
||||
qdel_swap(src.dna, chosen_dna.dna.Clone())
|
||||
src.dna.b_type = "AB+" //This is needed to avoid blood rejection bugs. The fact that the blood type might not match up w/ records could be a *FEATURE* too.
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
H.identifying_gender = chosen_dna.identifying_gender
|
||||
H.flavor_texts = chosen_dna.flavour_texts ? chosen_dna.flavour_texts.Copy() : null
|
||||
src.real_name = chosen_dna.name
|
||||
src.UpdateAppearance()
|
||||
real_name = chosen_dna.name
|
||||
UpdateAppearance()
|
||||
domutcheck(src, null)
|
||||
UpdateAppearance()
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
@@ -55,11 +56,7 @@
|
||||
|
||||
for(var/datum/modifier/mod in chosen_dna.genMods)
|
||||
self.modifiers.Add(mod.type)
|
||||
|
||||
remove_verb(src, /mob/proc/changeling_transform)
|
||||
spawn(10)
|
||||
add_verb(src, /mob/proc/changeling_transform)
|
||||
src.regenerate_icons()
|
||||
regenerate_icons()
|
||||
|
||||
feedback_add_details("changeling_powers","TR")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -12,9 +12,9 @@
|
||||
set name = "Transformation sting (40)"
|
||||
set desc="Sting target"
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(40)
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(40)
|
||||
if(!changeling)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/dna/DNA in changeling.absorbed_dna)
|
||||
@@ -30,10 +30,10 @@
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting)
|
||||
if(!T)
|
||||
return 0
|
||||
return FALSE
|
||||
if((HUSK in T.mutations) || (!ishuman(T) && !issmall(T)))
|
||||
to_chat(src, span_warning("Our sting appears ineffective against its DNA."))
|
||||
return 0
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Transformation sting (changeling)")
|
||||
T.visible_message(span_warning("[T] transforms!"))
|
||||
qdel_swap(T.dna, chosen_dna.Clone())
|
||||
@@ -41,4 +41,4 @@
|
||||
T.UpdateAppearance()
|
||||
domutcheck(T, null)
|
||||
feedback_add_details("changeling_powers","TS")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -1,3 +1,4 @@
|
||||
//Updated
|
||||
/datum/power/changeling/unfat_sting
|
||||
name = "Unfat Sting"
|
||||
desc = "We silently sting a human, forcing them to rapidly metabolize their fat."
|
||||
@@ -10,9 +11,10 @@
|
||||
set desc = "Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting)
|
||||
if(!T) return 0
|
||||
if(!T)
|
||||
return FALSE
|
||||
add_attack_logs(src,T,"Unfat sting (changeling)")
|
||||
to_chat(T, span_danger("you feel a small prick as stomach churns violently and you become to feel skinnier."))
|
||||
T.adjust_nutrition(-100)
|
||||
T.adjust_nutrition(-max(100, T.nutrition/1.15)) //Decrease their nutrition by 100 or 85%, whatever is higher. Ex: 1000 nutrition becomes ~130. 6000 nutrition becomes 800.
|
||||
feedback_add_details("changeling_powers","US")
|
||||
return 1
|
||||
return TRUE
|
||||
@@ -0,0 +1,92 @@
|
||||
/datum/power/changeling/visible_camouflage
|
||||
name = "Camouflage"
|
||||
desc = "We rapidly shape the color of our skin and secrete easily reversible dye on our clothes, to blend in with our surroundings. \
|
||||
We are undetectable, so long as we move slowly.(Toggle)"
|
||||
helptext = "Running, and performing most acts will reveal us. Our chemical regeneration is halted while we are hidden."
|
||||
enhancedtext = "Can run while hidden."
|
||||
ability_icon_state = "ling_camoflage"
|
||||
genomecost = 3
|
||||
verbpath = /mob/proc/changeling_visible_camouflage
|
||||
|
||||
//Hide us from anyone who would do us harm.
|
||||
/mob/proc/changeling_visible_camouflage()
|
||||
set category = "Changeling"
|
||||
set name = "Visible Camouflage (10)"
|
||||
set desc = "Turns yourself almost invisible, as long as you move slowly."
|
||||
var/datum/component/antag/changeling/changeling = changeling_power(0,0,100,CONSCIOUS)
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
|
||||
if(changeling.cloaked)
|
||||
changeling.cloaked = FALSE
|
||||
return TRUE
|
||||
if(H.has_modifier_of_type(/datum/modifier/changeling_camouflage)) //If they double-clicked the button while invis.
|
||||
to_chat(H, span_warning("We are already camouflaged!"))
|
||||
return TRUE
|
||||
|
||||
//We delay the check, so that people can uncloak without needing 10 chemicals to do so.
|
||||
changeling = changeling_power(10,0,100,CONSCIOUS)
|
||||
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
changeling.chem_charges -= 10
|
||||
|
||||
to_chat(H, span_notice("We vanish from sight, and will remain hidden, so long as we move carefully."))
|
||||
changeling.cloaked = TRUE
|
||||
if(changeling.recursive_enhancement)
|
||||
to_chat(src, span_notice("We may move at our normal speed while hidden."))
|
||||
H.add_modifier(/datum/modifier/changeling_camouflage/recursive, 0)
|
||||
else
|
||||
H.add_modifier(/datum/modifier/changeling_camouflage, 0)
|
||||
|
||||
/datum/modifier/changeling_camouflage
|
||||
name = "Camoflauge"
|
||||
desc = "We are near-impossible to see."
|
||||
var/must_walk = TRUE
|
||||
var/datum/component/antag/changeling/comp
|
||||
var/old_regen_rate
|
||||
var/mob/living/carbon/human/owner
|
||||
|
||||
|
||||
/datum/modifier/changeling_camouflage/recursive
|
||||
must_walk = FALSE
|
||||
|
||||
/datum/modifier/changeling_camouflage/can_apply(var/mob/living/L, var/suppress_failure = FALSE)
|
||||
comp = L.GetComponent(/datum/component/antag/changeling)
|
||||
if(!comp)
|
||||
return FALSE
|
||||
|
||||
/datum/modifier/changeling_camouflage/on_applied()
|
||||
comp = holder.GetComponent(/datum/component/antag/changeling)
|
||||
if(must_walk)
|
||||
holder.set_m_intent(I_WALK)
|
||||
old_regen_rate = comp.chem_recharge_rate
|
||||
comp.chem_recharge_rate = 0
|
||||
animate(holder,alpha = 255, alpha = 10, time = 10)
|
||||
|
||||
/datum/modifier/changeling_camouflage/on_expire()
|
||||
animate(holder,alpha = 10, alpha = 255, time = 10)
|
||||
owner.invisibility = initial(owner.invisibility)
|
||||
holder.visible_message(span_warning("[holder] suddenly fades in, seemingly from nowhere!"),
|
||||
span_notice("We revert our camouflage, revealing ourselves."))
|
||||
holder.set_m_intent(I_RUN)
|
||||
comp.cloaked = FALSE
|
||||
comp.chem_recharge_rate = old_regen_rate
|
||||
comp = null
|
||||
owner = null
|
||||
|
||||
/datum/modifier/changeling_camouflage/tick()
|
||||
if(holder.m_intent != I_WALK && must_walk) // Moving too fast uncloaks you.
|
||||
expire(silent = TRUE)
|
||||
if(!comp.cloaked)
|
||||
expire(silent = TRUE)
|
||||
if(holder.stat) // Dead or unconscious lings can't stay cloaked.
|
||||
expire(silent = TRUE)
|
||||
if(holder.incapacitated(INCAPACITATION_DISABLED)) // Stunned lings also can't stay cloaked.
|
||||
expire(silent = TRUE)
|
||||
if(comp.chem_recharge_rate != 0) //Without this, there is an exploit that can be done, if one buys engorged chem sacks while cloaked.
|
||||
old_regen_rate += comp.chem_recharge_rate
|
||||
comp.chem_recharge_rate = 0
|
||||
@@ -1,167 +0,0 @@
|
||||
/client
|
||||
var/datum/managed_browser/changelingevolution/changelingevolution = null
|
||||
|
||||
/datum/managed_browser/changelingevolution
|
||||
base_browser_id = "evolution_tree"
|
||||
title = "Evolution Tree"
|
||||
size_x = 480
|
||||
size_y = 600
|
||||
var/textbody = null
|
||||
|
||||
/datum/managed_browser/changelingevolution/New(client/new_client)
|
||||
if(!new_client.mob || !new_client.mob.mind || !new_client.mob.mind.changeling)
|
||||
message_admins("[new_client] tried to access changeling evolutions while not changeling.")
|
||||
qdel(src)
|
||||
|
||||
..()
|
||||
|
||||
/datum/managed_browser/changelingevolution/Destroy()
|
||||
if(my_client)
|
||||
my_client.changelingevolution = null
|
||||
return ..()
|
||||
|
||||
/datum/managed_browser/changelingevolution/get_html()
|
||||
var/list/dat = list("<html><body>")
|
||||
var/geneticpoints_current = my_client.mob.mind.changeling.geneticpoints
|
||||
var/geneticpoints_max = my_client.mob.mind.changeling.max_geneticpoints
|
||||
|
||||
dat += "<center>Genetic Points Available: [geneticpoints_current] / [geneticpoints_max] <br>"
|
||||
dat += "Obtain more by feeding on your own kind. <br> <hr>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];tutorial=1'>What am I?</a><br><hr>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];inherent=1'>Inherent</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];armor=1'>Armor</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];weapons=1'>Weapons</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];stings=1'>Stings</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];shrieks=1'>Shrieks</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];health=1'>Health</a>"
|
||||
dat += "<a style='background-color:#c72121;' href='byond://?src=\ref[src];enhancements=1'>Enhancements</a></center>"
|
||||
if(textbody)
|
||||
dat += "<table border='1' style='width:100%; background-color:#000000;'>"
|
||||
dat += "[textbody]"
|
||||
dat += "</table>"
|
||||
dat += "</body></html>"
|
||||
|
||||
return dat.Join()
|
||||
|
||||
/datum/managed_browser/changelingevolution/Topic(href, href_list[])
|
||||
if(!my_client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["close"])
|
||||
return
|
||||
|
||||
if(href_list["inherent"])
|
||||
generate_abilitylist(CHANGELING_POWER_INHERENT)
|
||||
|
||||
if(href_list["armor"])
|
||||
generate_abilitylist(CHANGELING_POWER_ARMOR)
|
||||
|
||||
if(href_list["weapons"])
|
||||
generate_abilitylist(CHANGELING_POWER_WEAPONS)
|
||||
|
||||
if(href_list["stings"])
|
||||
generate_abilitylist(CHANGELING_POWER_STINGS)
|
||||
|
||||
if(href_list["shrieks"])
|
||||
generate_abilitylist(CHANGELING_POWER_SHRIEKS)
|
||||
|
||||
if(href_list["health"])
|
||||
generate_abilitylist(CHANGELING_POWER_HEALTH)
|
||||
|
||||
if(href_list["enhancements"])
|
||||
generate_abilitylist(CHANGELING_POWER_ENHANCEMENTS)
|
||||
|
||||
if(href_list["evolve"])
|
||||
var/datum/mind/M = my_client.mob.mind
|
||||
var/datum/changeling/C = my_client.mob.mind.changeling
|
||||
var/datum/power/changeling/Thepower = href_list["evolve"]
|
||||
|
||||
for (var/datum/power/changeling/P in powerinstances)
|
||||
if(P.name == Thepower)
|
||||
Thepower = P
|
||||
break
|
||||
|
||||
if(!istype(M))
|
||||
return
|
||||
|
||||
if(Thepower == null)
|
||||
to_chat(M.current, "Purchase failed. Inform a dev of this error.")
|
||||
return
|
||||
|
||||
if(Thepower in C.purchased_powers)
|
||||
to_chat(M.current, "You already have this ability! Inform a dev of this error.") /// Should not be possible
|
||||
return
|
||||
|
||||
if(C.geneticpoints < Thepower.genomecost)
|
||||
to_chat(M.current, "We cannot evolve this... yet. We must acquire more DNA.")
|
||||
return
|
||||
|
||||
C.purchased_powers += Thepower /// Set it to purchased
|
||||
C.geneticpoints -= Thepower.genomecost
|
||||
generate_abilitylist(Thepower.power_category) /// Refresh the UI
|
||||
|
||||
my_client.mob.mind.changeling.purchasePower(M, Thepower)
|
||||
|
||||
if(href_list["tutorial"])
|
||||
textbody = "<tr><th><center>" + span_red("What am I?") + "</center><br></th></tr>"
|
||||
textbody += "<tr><td>"
|
||||
textbody += span_white("You are a changeling, a creature empowered with genetic-based abilities that change your body in bizarre ways.")
|
||||
textbody += span_white(" It's probably best the crew doesn't know about your power -- at least not right away.") + "<br><br>"
|
||||
textbody += span_white("What a changeling " + span_italics("is"), + " however, is up to you. Are you a strange alien impersonating crew? Are you a")
|
||||
textbody += span_white(" normal crewmember infected with a parasite? An experiment gone wrong? It's up to you to make the story.") + "<br><br>"
|
||||
textbody += span_white("Of course, you need to know how it works to begin with.") + "<br><br>"
|
||||
textbody += span_white("Your abilities cost chemicals that your body will slowly regenerate with varying speeds based on enhancements obtained.")
|
||||
textbody += span_white(" There are a set of inherent abilities you will always have while the rest may be purchased through genomes.") + "<br><br>"
|
||||
textbody += span_white("You may obtain more genomes if you find another changeling and absorb them, but this is not required. If you've found ")
|
||||
textbody += span_white("your abilities aren't to your liking, you have up to two re-adapts available, and these may be refilled by absorbing anyone -- including monkeys.") + "<br><br>"
|
||||
textbody += span_white("Good luck and remember, killing isn't always the end goal.")
|
||||
display()
|
||||
|
||||
/datum/managed_browser/changelingevolution/proc/generate_abilitylist(cat)
|
||||
var/list/ability_list = list()
|
||||
var/info = ""
|
||||
var/catname = ""
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
if(P.power_category == cat)
|
||||
ability_list[++ability_list.len] = P
|
||||
switch(cat)
|
||||
if(CHANGELING_POWER_INHERENT)
|
||||
catname = "Inherent"
|
||||
info = "These powers are inherent to your kind and will always be accessible, provided you have the chemicals to use them."
|
||||
if(CHANGELING_POWER_ARMOR)
|
||||
catname = "Armor"
|
||||
info = "These abilities will provide you with space protection -- and potentially armor."
|
||||
if(CHANGELING_POWER_WEAPONS)
|
||||
catname = "Weapons"
|
||||
info = "These abilities will provide you the means to fight back."
|
||||
if(CHANGELING_POWER_STINGS)
|
||||
catname = "Stings"
|
||||
info = "These abilities provide the means to sting organic beings for various effects -- though you must be close enough, and they must have exposed flesh."
|
||||
if(CHANGELING_POWER_SHRIEKS)
|
||||
catname = "Shrieks"
|
||||
info = "These abilities enhance your vocal chords, empowering your screams."
|
||||
if(CHANGELING_POWER_HEALTH)
|
||||
catname = "Health"
|
||||
info = "These abilities will enhance your health or aid you in mending your wounds."
|
||||
if(CHANGELING_POWER_ENHANCEMENTS)
|
||||
catname = "Enhancements"
|
||||
info = "These abilities enhance you in various ways."
|
||||
create_textbody(ability_list, catname, info)
|
||||
|
||||
/datum/managed_browser/changelingevolution/proc/create_textbody(ability_list, cat, catinfo)
|
||||
textbody = "<tr><th><center>" + span_red("[cat] Skills") + "<br></th></tr>"
|
||||
textbody += "<tr><td>" + span_white("[catinfo]") + "</center><br><hr></td></tr>"
|
||||
for(var/A in ability_list)
|
||||
var/datum/power/changeling/powerdata = A
|
||||
textbody += "<tr><td><center>" + span_red(span_bold("[initial(powerdata.name)]")) + "<br></center>"
|
||||
textbody += span_white("[initial(powerdata.desc)]") + "<br><br>"
|
||||
textbody += span_white(span_italics("[powerdata.helptext]")) + "<br>"
|
||||
if(powerdata.enhancedtext != "")
|
||||
textbody += span_white(span_bold("WHEN ENHANCED: ") + span_italics("[powerdata.enhancedtext]")) + "<br>"
|
||||
if(powerdata in my_client.mob.mind.changeling.purchased_powers)
|
||||
textbody += "<center>" + span_white(span_italics(span_bold("This ability is already evolved!"))) + "</center>"
|
||||
else if(cat != "Inherent")
|
||||
textbody += "<center>Cost: [powerdata.genomecost]</center>"
|
||||
textbody += "<center><a style='background-color:#c72121;' href='byond://?src=\ref[src];evolve=[A]'>Evolve</a></center>"
|
||||
textbody += "</td></tr>"
|
||||
display()
|
||||
@@ -31,6 +31,8 @@
|
||||
var/assigned_role
|
||||
var/special_role
|
||||
|
||||
var/datum/antag_holder/antag_holder
|
||||
|
||||
var/role_alt_title
|
||||
|
||||
var/datum/job/assigned_job
|
||||
@@ -41,7 +43,6 @@
|
||||
var/has_been_rev = 0//Tracks if this mind has been a rev or not
|
||||
|
||||
var/datum/faction/faction //associated faction
|
||||
var/datum/changeling/changeling //changeling holder
|
||||
|
||||
var/rev_cooldown = 0
|
||||
var/tcrystals = 0
|
||||
@@ -70,15 +71,18 @@
|
||||
/datum/mind/New(var/key)
|
||||
src.key = key
|
||||
purchase_log = list()
|
||||
antag_holder = new
|
||||
..()
|
||||
|
||||
/datum/mind/proc/transfer_to(mob/living/new_character, force = FALSE)
|
||||
if(!istype(new_character))
|
||||
to_world_log("## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn")
|
||||
if(current) //remove ourself from our old body's mind variable
|
||||
if(changeling)
|
||||
var/datum/component/antag/changeling/comp
|
||||
if(current)
|
||||
comp = is_changeling(current) //remove ourself from our old body's mind variable
|
||||
if(comp)
|
||||
current.remove_changeling_powers()
|
||||
remove_verb(current, /datum/changeling/proc/EvolutionMenu)
|
||||
remove_verb(current, /mob/proc/EvolutionMenu)
|
||||
current.mind = null
|
||||
|
||||
if(new_character.mind) //remove any mind currently in our new body's mind variable
|
||||
@@ -87,7 +91,7 @@
|
||||
current = new_character //link ourself to our new body
|
||||
new_character.mind = src //and link our new body to ourself
|
||||
|
||||
if(changeling)
|
||||
if(comp)
|
||||
new_character.make_changeling()
|
||||
|
||||
if(active || force)
|
||||
@@ -471,7 +475,7 @@
|
||||
role_alt_title = null
|
||||
assigned_job = null
|
||||
//faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know.
|
||||
changeling = null
|
||||
//changeling = null //TODO: Figure out where this is all used and move it from mind to mob.
|
||||
initial_account = null
|
||||
objectives = list()
|
||||
special_verbs = list()
|
||||
|
||||
@@ -131,3 +131,7 @@ Made a proc so this is not repeated 14 (or more) times.*/
|
||||
to_chat(src, span_warning("I don't feel strong enough without my hat."))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/antagonist/wizard/remove_antagonist(datum/mind/player, show_message, implanted)
|
||||
. = ..()
|
||||
player.current.spellremove()
|
||||
|
||||
@@ -13,12 +13,25 @@
|
||||
antaghud_indicator = "hudchangeling"
|
||||
|
||||
/datum/antagonist/changeling/get_special_objective_text(var/datum/mind/player)
|
||||
return "<br><b>Changeling ID:</b> [player.changeling.changelingID].<br><b>Genomes Absorbed:</b> [player.changeling.absorbedcount]"
|
||||
if(player.current)
|
||||
var/datum/component/antag/changeling/comp = player.current.GetComponent(/datum/component/antag/changeling)
|
||||
if(comp)
|
||||
return "<br><b>Changeling ID:</b> [comp.changelingID].<br><b>Genomes Absorbed:</b> [comp.absorbedcount]"
|
||||
|
||||
/datum/antagonist/changeling/update_antag_mob(var/datum/mind/player)
|
||||
..()
|
||||
player.current.make_changeling()
|
||||
|
||||
/datum/antagonist/changeling/remove_antagonist(datum/mind/player, show_message, implanted)
|
||||
. = ..()
|
||||
var/datum/component/antag/changeling/comp = player.current.GetComponent(/datum/component/antag/changeling)
|
||||
if(comp)
|
||||
comp.owner.remove_changeling_powers()
|
||||
remove_verb(comp.owner, /mob/proc/EvolutionMenu)
|
||||
comp.RemoveComponent()
|
||||
if(comp.owner.mind)
|
||||
comp.owner.mind.antag_holder.changeling = null
|
||||
|
||||
/datum/antagonist/changeling/create_objectives(var/datum/mind/changeling)
|
||||
if(!..())
|
||||
return
|
||||
@@ -77,12 +90,12 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/antagonist/changeling/print_player_full(var/datum/mind/ply)
|
||||
var/text = print_player_lite(ply)
|
||||
/datum/antagonist/changeling/print_player_full(var/datum/mind/player)
|
||||
var/text = print_player_lite(player)
|
||||
|
||||
if(ply.changeling)
|
||||
var/datum/changeling/ling_datum = ply.changeling
|
||||
text += " (had [ling_datum.max_geneticpoints] genomes)"
|
||||
text += "<br>Bought [english_list(ling_datum.purchased_powers_history)]."
|
||||
var/datum/component/antag/changeling/comp = player.current.GetComponent(/datum/component/antag/changeling)
|
||||
if(comp)
|
||||
text += " (had [comp.max_geneticpoints] genomes)"
|
||||
text += "<br>Bought [english_list(comp.purchased_powers_history)]."
|
||||
|
||||
return text
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega")
|
||||
|
||||
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
|
||||
var/list/datum/absorbed_dna/absorbed_dna = list()
|
||||
var/list/absorbed_languages = list() // Necessary because of set_species stuff
|
||||
var/absorbedcount = 0
|
||||
var/lingabsorbedcount = 1 //Starts at one, because that's us
|
||||
var/chem_charges = 20
|
||||
var/chem_recharge_rate = 0.5
|
||||
var/chem_storage = 50
|
||||
var/sting_range = 1
|
||||
var/changelingID = "Changeling"
|
||||
var/geneticdamage = 0
|
||||
var/isabsorbing = 0
|
||||
var/geneticpoints = 7
|
||||
var/max_geneticpoints = 7
|
||||
var/readapts = 1
|
||||
var/max_readapts = 2
|
||||
var/list/purchased_powers = list()
|
||||
var/mimicing = ""
|
||||
var/cloaked = 0
|
||||
var/armor_deployed = 0 //This is only used for changeling_generic_equip_all_slots() at the moment.
|
||||
var/recursive_enhancement = 0 //Used to power up other abilities from the ling power with the same name.
|
||||
var/list/purchased_powers_history = list() //Used for round-end report, includes respec uses too.
|
||||
var/last_shriek = null // world.time when the ling last used a shriek.
|
||||
var/next_escape = 0 // world.time when the ling can next use Escape Restraints
|
||||
var/thermal_sight = FALSE // Is our Vision Augmented? With thermals?
|
||||
|
||||
/datum/changeling/New(var/gender=FEMALE)
|
||||
..()
|
||||
if(possible_changeling_IDs.len)
|
||||
changelingID = pick(possible_changeling_IDs)
|
||||
possible_changeling_IDs -= changelingID
|
||||
changelingID = "[changelingID]"
|
||||
else
|
||||
changelingID = "[rand(1,999)]"
|
||||
|
||||
/datum/changeling/proc/regenerate()
|
||||
chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage)
|
||||
geneticdamage = max(0, geneticdamage-1)
|
||||
|
||||
/datum/changeling/proc/GetDNA(var/dna_owner)
|
||||
for(var/datum/absorbed_dna/DNA in absorbed_dna)
|
||||
if(dna_owner == DNA.name)
|
||||
return DNA
|
||||
|
||||
/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA)
|
||||
var/datum/changeling/changeling = null
|
||||
if(src.mind && src.mind.changeling)
|
||||
changeling = src.mind.changeling
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
for(var/language in newDNA.languages)
|
||||
changeling.absorbed_languages |= language
|
||||
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
|
||||
if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite
|
||||
changeling.absorbed_dna += newDNA
|
||||
|
||||
//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human
|
||||
/mob/proc/make_changeling()
|
||||
|
||||
if(!mind) return
|
||||
if(!mind.changeling) mind.changeling = new /datum/changeling(gender)
|
||||
|
||||
add_verb(src, /datum/changeling/proc/EvolutionMenu)
|
||||
add_verb(src, /mob/proc/changeling_respec)
|
||||
add_language("Changeling")
|
||||
|
||||
var/lesser_form = !ishuman(src)
|
||||
|
||||
if(!powerinstances.len)
|
||||
for(var/P in powers)
|
||||
powerinstances += new P()
|
||||
|
||||
// Code to auto-purchase free powers.
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
if(!P.genomecost) // Is it free?
|
||||
if(!(P in mind.changeling.purchased_powers)) // Do we not have it already?
|
||||
mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this.
|
||||
|
||||
for(var/datum/power/changeling/P in mind.changeling.purchased_powers)
|
||||
if(P.isVerb)
|
||||
if(lesser_form && !P.allowduringlesserform) continue
|
||||
if(!(P in src.verbs))
|
||||
add_verb(src, P.verbpath)
|
||||
if(P.make_hud_button)
|
||||
if(!src.ability_master)
|
||||
src.ability_master = new /obj/screen/movable/ability_master(src)
|
||||
src.ability_master.add_ling_ability(
|
||||
object_given = src,
|
||||
verb_given = P.verbpath,
|
||||
name_given = P.name,
|
||||
ability_icon_given = P.ability_icon_state,
|
||||
arguments = list()
|
||||
)
|
||||
|
||||
for(var/language in languages)
|
||||
mind.changeling.absorbed_languages |= language
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H))
|
||||
var/saved_dna = H.dna.Clone() /// Prevent transform from breaking.
|
||||
var/datum/absorbed_dna/newDNA = new(H.real_name, saved_dna, H.species.name, H.languages, H.identifying_gender, H.flavor_texts, H.modifiers)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
return 1
|
||||
|
||||
//removes our changeling verbs
|
||||
/mob/proc/remove_changeling_powers()
|
||||
if(!mind || !mind.changeling) return
|
||||
for(var/datum/power/changeling/P in mind.changeling.purchased_powers)
|
||||
if(P.isVerb)
|
||||
remove_verb(src, P.verbpath)
|
||||
var/obj/screen/ability/verb_based/changeling/C = ability_master.get_ability_by_proc_ref(P.verbpath)
|
||||
if(C)
|
||||
ability_master.remove_ability(C)
|
||||
|
||||
|
||||
//Helper proc. Does all the checks and stuff for us to avoid copypasta
|
||||
/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0)
|
||||
|
||||
if(!src.mind) return
|
||||
if(!iscarbon(src)) return
|
||||
|
||||
var/datum/changeling/changeling = src.mind.changeling
|
||||
if(!changeling)
|
||||
to_world_log("[src] has the changeling_transform() verb but is not a changeling.")
|
||||
return
|
||||
|
||||
if(src.stat > max_stat)
|
||||
to_chat(src, span_warning("We are incapacitated."))
|
||||
return
|
||||
|
||||
if(changeling.absorbed_dna.len < required_dna)
|
||||
to_chat(src, span_warning("We require at least [required_dna] samples of compatible DNA."))
|
||||
return
|
||||
|
||||
if(changeling.chem_charges < required_chems)
|
||||
to_chat(src, span_warning("We require at least [required_chems] units of chemicals to do that!"))
|
||||
return
|
||||
|
||||
if(changeling.geneticdamage > max_genetic_damage)
|
||||
to_chat(src, span_warning("Our genomes are still reassembling. We need time to recover first."))
|
||||
return
|
||||
|
||||
return changeling
|
||||
|
||||
//Used to dump the languages from the changeling datum into the actual mob.
|
||||
/mob/proc/changeling_update_languages(var/updated_languages)
|
||||
languages = list()
|
||||
for(var/language in updated_languages)
|
||||
languages += language
|
||||
|
||||
//This isn't strictly necessary but just to be safe...
|
||||
add_language("Changeling")
|
||||
|
||||
//////////
|
||||
//STINGS// //They get a pretty header because there's just so fucking many of them ;_;
|
||||
//////////
|
||||
|
||||
/turf/proc/AdjacentTurfsRangedSting()
|
||||
//Yes this is snowflakey, but I couldn't get it to work any other way.. -Luke
|
||||
var/list/allowed = list(
|
||||
/obj/structure/table,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/frame,
|
||||
/obj/structure/target_stake,
|
||||
/obj/structure/cable,
|
||||
/obj/structure/disposalpipe,
|
||||
/obj/machinery,
|
||||
/mob
|
||||
)
|
||||
|
||||
var/L[] = new()
|
||||
for(var/turf/simulated/t in oview(src,1))
|
||||
var/add = 1
|
||||
if(t.density)
|
||||
add = 0
|
||||
if(add && LinkBlocked(src,t))
|
||||
add = 0
|
||||
if(add && TurfBlockedNonWindow(t))
|
||||
add = 0
|
||||
for(var/obj/O in t)
|
||||
if(O.density)
|
||||
add = 0
|
||||
break
|
||||
if(istype(O, /obj/machinery/door))
|
||||
//not sure why this doesn't fire on LinkBlocked()
|
||||
add = 0
|
||||
break
|
||||
for(var/type in allowed)
|
||||
if (istype(O, type))
|
||||
add = 1
|
||||
break
|
||||
if(!add)
|
||||
break
|
||||
if(add)
|
||||
L.Add(t)
|
||||
return L
|
||||
|
||||
|
||||
/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1)
|
||||
if(M.loc == src.loc)
|
||||
return 1 //target and source are in the same thing
|
||||
if(!isturf(src.loc) || !isturf(M.loc))
|
||||
to_chat(src, span_warning("We cannot reach \the [M] with a sting!"))
|
||||
return 0 //One is inside, the other is outside something.
|
||||
// Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising
|
||||
if(!SSpathfinder.get_path_jps(src, get_turf(src), get_turf(M), max_path_length = 25)) //CHOMPEdit
|
||||
to_chat(src, span_warning("We cannot find a path to sting \the [M] by!"))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities)
|
||||
/mob/proc/changeling_sting(var/required_chems=0, var/verb_path)
|
||||
var/datum/changeling/changeling = changeling_power(required_chems)
|
||||
if(!changeling) return
|
||||
|
||||
var/list/victims = list()
|
||||
for(var/mob/living/carbon/C in oview(changeling.sting_range))
|
||||
victims += C
|
||||
var/mob/living/carbon/T = tgui_input_list(src, "Who will we sting?", "Sting!", victims)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
if(T.isSynthetic())
|
||||
to_chat(src, span_notice("We are unable to pierce the outer shell of [T]."))
|
||||
return
|
||||
if(!(T in view(changeling.sting_range))) return
|
||||
if(!sting_can_reach(T, changeling.sting_range)) return
|
||||
if(!changeling_power(required_chems)) return
|
||||
|
||||
changeling.chem_charges -= required_chems
|
||||
changeling.sting_range = 1
|
||||
remove_verb(src, verb_path)
|
||||
spawn(10) add_verb(src, verb_path)
|
||||
|
||||
to_chat(src, span_notice("We stealthily sting [T]."))
|
||||
if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting
|
||||
to_chat(T, span_warning("You feel a tiny prick."))
|
||||
return
|
||||
@@ -1,359 +0,0 @@
|
||||
// READ: Don't use the apostrophe in name or desc. Causes script errors.
|
||||
|
||||
//Ling power's evolution menu entry datum should be contained alongside the mob proc for the actual power, in their own file.
|
||||
|
||||
var/list/powers = subtypesof(/datum/power/changeling) //needed for the badmin verb for now
|
||||
var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
/datum/power //Could be used by other antags too
|
||||
var/name = "Power"
|
||||
var/desc = "Placeholder"
|
||||
var/helptext = ""
|
||||
var/enhancedtext = ""
|
||||
var/isVerb = 1 // Is it an active power, or passive?
|
||||
var/verbpath // Path to a verb that contains the effects.
|
||||
var/make_hud_button = 1 // Is this ability significant enough to dedicate screen space for a HUD button?
|
||||
var/ability_icon_state = null // icon_state for icons for the ability HUD. Must be in screen_spells.dmi.
|
||||
|
||||
/datum/power/changeling
|
||||
var/allowduringlesserform = 0
|
||||
var/genomecost = 500000 // Cost for the changling to evolve this power.
|
||||
|
||||
|
||||
// Modularchangling, totally stolen from the new player panel. YAYY
|
||||
/datum/changeling/proc/EvolutionMenu()//The new one
|
||||
set name = "-Evolution Menu-"
|
||||
set category = "Changeling"
|
||||
set desc = "Adapt yourself carefully."
|
||||
|
||||
if(!usr || !usr.mind || !usr.mind.changeling) return
|
||||
src = usr.mind.changeling
|
||||
|
||||
if(!powerinstances.len)
|
||||
for(var/P in powers)
|
||||
powerinstances += new P()
|
||||
|
||||
var/dat = "<html><head><title>Changling Evolution Menu</title></head>"
|
||||
|
||||
//javascript, the part that does most of the work~
|
||||
dat += {"
|
||||
|
||||
<head>
|
||||
<script type='text/javascript'>
|
||||
|
||||
var locked_tabs = new Array();
|
||||
|
||||
function updateSearch(){
|
||||
|
||||
|
||||
var filter_text = document.getElementById('filter');
|
||||
var filter = filter_text.value.toLowerCase();
|
||||
|
||||
if(complete_list != null && complete_list != ""){
|
||||
var mtbl = document.getElementById("maintable_data_archive");
|
||||
mtbl.innerHTML = complete_list;
|
||||
}
|
||||
|
||||
if(filter.value == ""){
|
||||
return;
|
||||
}else{
|
||||
|
||||
var maintable_data = document.getElementById('maintable_data');
|
||||
var ltr = maintable_data.getElementsByTagName("tr");
|
||||
for ( var i = 0; i < ltr.length; ++i )
|
||||
{
|
||||
try{
|
||||
var tr = ltr\[i\];
|
||||
if(tr.getAttribute("id").indexOf("data") != 0){
|
||||
continue;
|
||||
}
|
||||
var ltd = tr.getElementsByTagName("td");
|
||||
var td = ltd\[0\];
|
||||
var lsearch = td.getElementsByTagName("b");
|
||||
var search = lsearch\[0\];
|
||||
//var inner_span = li.getElementsByTagName("span")\[1\] //Should only ever contain one element.
|
||||
//document.write("<p>"+search.innerText+"<br>"+filter+"<br>"+search.innerText.indexOf(filter))
|
||||
if ( search.innerText.toLowerCase().indexOf(filter) == -1 )
|
||||
{
|
||||
//document.write("a");
|
||||
//ltr.removeChild(tr);
|
||||
td.innerHTML = "";
|
||||
i--;
|
||||
}
|
||||
}catch(err) { }
|
||||
}
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
var index = -1;
|
||||
var debug = document.getElementById("debug");
|
||||
|
||||
locked_tabs = new Array();
|
||||
|
||||
}
|
||||
|
||||
function expand(id,name,desc,helptext,enhancedtext,power,ownsthis){
|
||||
|
||||
clearAll();
|
||||
|
||||
var span = document.getElementById(id);
|
||||
|
||||
body = "<table><tr><td>";
|
||||
|
||||
body += "</td><td align='center'>";
|
||||
|
||||
body += "<font size='2'><b>"+desc+"</b></font> <BR>"
|
||||
|
||||
body += "<font size='2'><font color = 'red'><b>"+helptext+"</b></font></font><BR>"
|
||||
|
||||
if(enhancedtext)
|
||||
{
|
||||
body += "<font size='2'><font color = 'blue'>Recursive Enhancement Effect: <b>"+enhancedtext+"</b></font></font><BR>"
|
||||
}
|
||||
|
||||
if(!ownsthis)
|
||||
{
|
||||
body += "<a href='byond://?src=\ref[src];P="+power+"'>Evolve</a>"
|
||||
}
|
||||
|
||||
body += "</td><td align='center'>";
|
||||
|
||||
body += "</td></tr></table>";
|
||||
|
||||
|
||||
span.innerHTML = body
|
||||
}
|
||||
|
||||
function clearAll(){
|
||||
var spans = document.getElementsByTagName('span');
|
||||
for(var i = 0; i < spans.length; i++){
|
||||
var span = spans\[i\];
|
||||
|
||||
var id = span.getAttribute("id");
|
||||
|
||||
if(!(id.indexOf("item")==0))
|
||||
continue;
|
||||
|
||||
var pass = 1;
|
||||
|
||||
for(var j = 0; j < locked_tabs.length; j++){
|
||||
if(locked_tabs\[j\]==id){
|
||||
pass = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pass != 1)
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
|
||||
span.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
function addToLocked(id,link_id,notice_span_id){
|
||||
var link = document.getElementById(link_id);
|
||||
var decision = link.getAttribute("name");
|
||||
if(decision == "1"){
|
||||
link.setAttribute("name","2");
|
||||
}else{
|
||||
link.setAttribute("name","1");
|
||||
removeFromLocked(id,link_id,notice_span_id);
|
||||
return;
|
||||
}
|
||||
|
||||
var pass = 1;
|
||||
for(var j = 0; j < locked_tabs.length; j++){
|
||||
if(locked_tabs\[j\]==id){
|
||||
pass = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!pass)
|
||||
return;
|
||||
locked_tabs.push(id);
|
||||
var notice_span = document.getElementById(notice_span_id);
|
||||
notice_span.innerHTML = "<font color='red'>Locked</font> ";
|
||||
//link.setAttribute("onClick","attempt('"+id+"','"+link_id+"','"+notice_span_id+"');");
|
||||
//document.write("removeFromLocked('"+id+"','"+link_id+"','"+notice_span_id+"')");
|
||||
//document.write("aa - "+link.getAttribute("onClick"));
|
||||
}
|
||||
|
||||
function attempt(ab){
|
||||
return ab;
|
||||
}
|
||||
|
||||
function removeFromLocked(id,link_id,notice_span_id){
|
||||
//document.write("a");
|
||||
var index = 0;
|
||||
var pass = 0;
|
||||
for(var j = 0; j < locked_tabs.length; j++){
|
||||
if(locked_tabs\[j\]==id){
|
||||
pass = 1;
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!pass)
|
||||
return;
|
||||
locked_tabs\[index\] = "";
|
||||
var notice_span = document.getElementById(notice_span_id);
|
||||
notice_span.innerHTML = "";
|
||||
//var link = document.getElementById(link_id);
|
||||
//link.setAttribute("onClick","addToLocked('"+id+"','"+link_id+"','"+notice_span_id+"')");
|
||||
}
|
||||
|
||||
function selectTextField(){
|
||||
var filter_text = document.getElementById('filter');
|
||||
filter_text.focus();
|
||||
filter_text.select();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
"}
|
||||
|
||||
//body tag start + onload and onkeypress (onkeyup) javascript event calls
|
||||
dat += "<body onload='selectTextField(); updateSearch();' onkeyup='updateSearch();'>"
|
||||
|
||||
//title + search bar
|
||||
dat += {"
|
||||
|
||||
<table width='560' align='center' cellspacing='0' cellpadding='5' id='maintable'>
|
||||
<tr id='title_tr'>
|
||||
<td align='center'>
|
||||
<font size='5'><b>Changling Evolution Menu</b></font><br>
|
||||
Hover over a power to see more information<br>
|
||||
Current evolution points left to evolve with: [geneticpoints]<br>
|
||||
Absorb other changelings to acquire more evolution points
|
||||
<p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='search_tr'>
|
||||
<td align='center'>
|
||||
<b>Search:</b> <input type='text' id='filter' value='' style='width:300px;'>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
"}
|
||||
|
||||
//player table header
|
||||
dat += {"
|
||||
<span id='maintable_data_archive'>
|
||||
<table width='560' align='center' cellspacing='0' cellpadding='5' id='maintable_data'>"}
|
||||
|
||||
var/i = 1
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
var/ownsthis = 0
|
||||
|
||||
if(P in purchased_powers)
|
||||
ownsthis = 1
|
||||
|
||||
|
||||
var/color = "#e6e6e6"
|
||||
if(i%2 == 0)
|
||||
color = "#f2f2f2"
|
||||
|
||||
|
||||
dat += {"
|
||||
|
||||
<tr id='data[i]' name='[i]' onClick="addToLocked('item[i]','data[i]','notice_span[i]')">
|
||||
<td align='center' bgcolor='[color]'>
|
||||
<span id='notice_span[i]'></span>
|
||||
<a id='link[i]'
|
||||
onmouseover='expand("item[i]","[P.name]","[P.desc]","[P.helptext]","[P.enhancedtext]","[P]",[ownsthis])'
|
||||
>
|
||||
<span id='search[i]'><b>Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost]</b></span>
|
||||
</a>
|
||||
<br><span id='item[i]'></span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
"}
|
||||
|
||||
i++
|
||||
|
||||
|
||||
//player table ending
|
||||
dat += {"
|
||||
</table>
|
||||
</span>
|
||||
|
||||
<script type='text/javascript'>
|
||||
var maintable = document.getElementById("maintable_data_archive");
|
||||
var complete_list = maintable.innerHTML;
|
||||
</script>
|
||||
</body></html>
|
||||
"}
|
||||
|
||||
usr << browse(dat, "window=powers;size=900x480")
|
||||
|
||||
|
||||
/datum/changeling/Topic(href, href_list)
|
||||
..()
|
||||
if(!ismob(usr))
|
||||
return
|
||||
|
||||
if(href_list["P"])
|
||||
var/datum/mind/M = usr.mind
|
||||
if(!istype(M))
|
||||
return
|
||||
purchasePower(M, href_list["P"])
|
||||
call(/datum/changeling/proc/EvolutionMenu)()
|
||||
|
||||
|
||||
|
||||
/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1)
|
||||
if(!M || !M.changeling)
|
||||
return
|
||||
|
||||
var/datum/power/changeling/Thepower = Pname
|
||||
|
||||
|
||||
for (var/datum/power/changeling/P in powerinstances)
|
||||
//to_world("[P] - [Pname] = [P.name == Pname ? "True" : "False"]")
|
||||
if(P.name == Pname)
|
||||
Thepower = P
|
||||
break
|
||||
|
||||
|
||||
if(Thepower == null)
|
||||
to_chat(M.current, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
|
||||
return
|
||||
|
||||
if(Thepower in purchased_powers)
|
||||
to_chat(M.current, "We have already evolved this ability!")
|
||||
return
|
||||
|
||||
|
||||
if(geneticpoints < Thepower.genomecost)
|
||||
to_chat(M.current, "We cannot evolve this... yet. We must acquire more DNA.")
|
||||
return
|
||||
|
||||
geneticpoints -= Thepower.genomecost
|
||||
|
||||
purchased_powers += Thepower
|
||||
|
||||
if(Thepower.genomecost > 0)
|
||||
purchased_powers_history.Add("[Pname] ([Thepower.genomecost] points)")
|
||||
|
||||
if(Thepower.make_hud_button && Thepower.isVerb)
|
||||
if(!M.current.ability_master)
|
||||
M.current.ability_master = new /obj/screen/movable/ability_master(M.current)
|
||||
M.current.ability_master.add_ling_ability(
|
||||
object_given = M.current,
|
||||
verb_given = Thepower.verbpath,
|
||||
name_given = Thepower.name,
|
||||
ability_icon_given = Thepower.ability_icon_state,
|
||||
arguments = list()
|
||||
)
|
||||
|
||||
if(!Thepower.isVerb && Thepower.verbpath)
|
||||
call(M.current, Thepower.verbpath)()
|
||||
else if(remake_verbs)
|
||||
M.current.make_changeling()
|
||||
@@ -1,23 +0,0 @@
|
||||
/datum/power/changeling/DeathSting
|
||||
name = "Death Sting"
|
||||
desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured."
|
||||
ability_icon_state = "ling_sting_death"
|
||||
genomecost = 10
|
||||
verbpath = /mob/proc/changeling_DEATHsting
|
||||
|
||||
/mob/proc/changeling_DEATHsting()
|
||||
set category = "Changeling"
|
||||
set name = "Death Sting (40)"
|
||||
set desc = "Causes spasms onto death."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting)
|
||||
if(!T)
|
||||
return 0
|
||||
add_attack_logs(src,T,"Death sting (changeling)")
|
||||
to_chat(T, span_danger("You feel a small prick and your chest becomes tight."))
|
||||
T.silent = 10
|
||||
T.Paralyse(10)
|
||||
T.make_jittery(100)
|
||||
if(T.reagents) T.reagents.add_reagent(REAGENT_ID_LEXORIN, 40)
|
||||
feedback_add_details("changeling_powers","DTHS")
|
||||
return 1
|
||||
@@ -1,41 +0,0 @@
|
||||
/datum/power/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Begins a slow regeneration of our form. Does not effect stuns or chemicals."
|
||||
helptext = "Can be used while unconscious."
|
||||
enhancedtext = "Healing is twice as effective."
|
||||
ability_icon_state = "ling_fleshmend"
|
||||
genomecost = 1
|
||||
verbpath = /mob/proc/changeling_fleshmend
|
||||
|
||||
//Starts healing you every second for 50 seconds. Can be used whilst unconscious.
|
||||
/mob/proc/changeling_fleshmend()
|
||||
set category = "Changeling"
|
||||
set name = "Fleshmend (10)"
|
||||
set desc = "Begins a slow rengeration of our form. Does not effect stuns or chemicals."
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(10,0,100,UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return 0
|
||||
src.mind.changeling.chem_charges -= 10
|
||||
|
||||
var/mob/living/carbon/human/C = src
|
||||
var/heal_amount = 2
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
heal_amount = heal_amount * 2
|
||||
to_chat(src, span_notice("We will heal much faster."))
|
||||
|
||||
spawn(0)
|
||||
to_chat(src, span_notice("We begin to heal ourselves."))
|
||||
for(var/i = 0, i<50,i++)
|
||||
if(C)
|
||||
C.adjustBruteLoss(-heal_amount)
|
||||
C.adjustOxyLoss(-heal_amount)
|
||||
C.adjustFireLoss(-heal_amount)
|
||||
sleep(1 SECOND)
|
||||
|
||||
remove_verb(src, /mob/proc/changeling_fleshmend)
|
||||
spawn(50 SECONDS)
|
||||
to_chat(src, span_notice("Our regeneration has slowed to normal levels."))
|
||||
add_verb(src, /mob/proc/changeling_fleshmend)
|
||||
feedback_add_details("changeling_powers","FM")
|
||||
return 1
|
||||
@@ -1,72 +0,0 @@
|
||||
/datum/power/changeling/visible_camouflage
|
||||
name = "Camouflage"
|
||||
desc = "We rapidly shape the color of our skin and secrete easily reversible dye on our clothes, to blend in with our surroundings. \
|
||||
We are undetectable, so long as we move slowly.(Toggle)"
|
||||
helptext = "Running, and performing most acts will reveal us. Our chemical regeneration is halted while we are hidden."
|
||||
enhancedtext = "Can run while hidden."
|
||||
ability_icon_state = "ling_camoflage"
|
||||
genomecost = 3
|
||||
verbpath = /mob/proc/changeling_visible_camouflage
|
||||
|
||||
//Hide us from anyone who would do us harm.
|
||||
/mob/proc/changeling_visible_camouflage()
|
||||
set category = "Changeling"
|
||||
set name = "Visible Camouflage (10)"
|
||||
set desc = "Turns yourself almost invisible, as long as you move slowly."
|
||||
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
|
||||
if(H.mind.changeling.cloaked)
|
||||
H.mind.changeling.cloaked = 0
|
||||
return 1
|
||||
|
||||
//We delay the check, so that people can uncloak without needing 10 chemicals to do so.
|
||||
var/datum/changeling/changeling = changeling_power(10,0,100,CONSCIOUS)
|
||||
|
||||
if(!changeling)
|
||||
return 0
|
||||
changeling.chem_charges -= 10
|
||||
var/old_regen_rate = H.mind.changeling.chem_recharge_rate
|
||||
|
||||
to_chat(H, span_notice("We vanish from sight, and will remain hidden, so long as we move carefully."))
|
||||
H.mind.changeling.cloaked = 1
|
||||
H.mind.changeling.chem_recharge_rate = 0
|
||||
animate(src,alpha = 255, alpha = 10, time = 10)
|
||||
|
||||
var/must_walk = TRUE
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
must_walk = FALSE
|
||||
to_chat(src, span_notice("We may move at our normal speed while hidden."))
|
||||
|
||||
if(must_walk)
|
||||
H.set_m_intent(I_WALK)
|
||||
|
||||
var/remain_cloaked = TRUE
|
||||
while(remain_cloaked) //This loop will keep going until the player uncloaks.
|
||||
sleep(1 SECOND) // Sleep at the start so that if something invalidates a cloak, it will drop immediately after the check and not in one second.
|
||||
|
||||
if(H.m_intent != I_WALK && must_walk) // Moving too fast uncloaks you.
|
||||
remain_cloaked = 0
|
||||
if(!H.mind.changeling.cloaked)
|
||||
remain_cloaked = 0
|
||||
if(H.stat) // Dead or unconscious lings can't stay cloaked.
|
||||
remain_cloaked = 0
|
||||
if(H.incapacitated(INCAPACITATION_DISABLED)) // Stunned lings also can't stay cloaked.
|
||||
remain_cloaked = 0
|
||||
|
||||
if(mind.changeling.chem_recharge_rate != 0) //Without this, there is an exploit that can be done, if one buys engorged chem sacks while cloaked.
|
||||
old_regen_rate += mind.changeling.chem_recharge_rate //Unfortunately, it has to occupy this part of the proc. This fixes it while at the same time
|
||||
mind.changeling.chem_recharge_rate = 0 //making sure nobody loses out on their bonus regeneration after they're done hiding.
|
||||
|
||||
|
||||
|
||||
H.invisibility = initial(invisibility)
|
||||
visible_message(span_warning("[src] suddenly fades in, seemingly from nowhere!"),
|
||||
span_notice("We revert our camouflage, revealing ourselves."))
|
||||
H.set_m_intent(I_RUN)
|
||||
H.mind.changeling.cloaked = 0
|
||||
H.mind.changeling.chem_recharge_rate = old_regen_rate
|
||||
|
||||
animate(src,alpha = 10, alpha = 255, time = 10)
|
||||
@@ -614,7 +614,8 @@ GLOBAL_LIST_EMPTY(all_objectives)
|
||||
n_p ++
|
||||
else if (ticker.current_state == GAME_STATE_PLAYING)
|
||||
for(var/mob/living/carbon/human/P in player_list)
|
||||
if(P.client && !(P.mind.changeling) && P.mind!=owner)
|
||||
var/datum/component/antag/changeling/comp = P.GetComponent(/datum/component/antag/changeling)
|
||||
if(P.client && !(comp) && P.mind!=owner)
|
||||
n_p ++
|
||||
target_amount = min(target_amount, n_p)
|
||||
|
||||
@@ -622,8 +623,10 @@ GLOBAL_LIST_EMPTY(all_objectives)
|
||||
return target_amount
|
||||
|
||||
/datum/objective/absorb/check_completion()
|
||||
if(owner && owner.changeling && owner.changeling.absorbed_dna && (owner.changeling.absorbedcount >= target_amount))
|
||||
return 1
|
||||
if(owner)
|
||||
var/datum/component/antag/changeling/comp = owner.GetComponent(/datum/component/antag/changeling)
|
||||
if(comp && comp.absorbed_dna && (comp.absorbedcount >= target_amount))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
@@ -302,6 +302,10 @@ var/global/mob/living/carbon/human/dummy/mannequin/sleevemate_mob
|
||||
if(H.resleeve_lock && stored_mind.loaded_from_ckey != H.resleeve_lock)
|
||||
to_chat(usr,span_warning("\The [H] is protected from impersonation!"))
|
||||
return
|
||||
//Changeling bodies. Only changelings can be put in them.
|
||||
if(H.changeling_locked && !is_changeling(stored_mind))
|
||||
to_chat(usr,span_warning("\The [H] is too complex to put this mind into!"))
|
||||
return
|
||||
|
||||
usr.visible_message(span_warning("[usr] begins uploading someone's mind into [target]!"),span_notice("You begin uploading a mind into [target]!"))
|
||||
if(do_after(usr,35 SECONDS,target))
|
||||
|
||||
@@ -543,6 +543,8 @@ ADMIN_VERB(respawn_character, (R_ADMIN|R_REJUVINATE), "Spawn Character", "(Re)Sp
|
||||
if(antag_data)
|
||||
antag_data.add_antagonist(new_character.mind)
|
||||
antag_data.place_mob(new_character)
|
||||
if(new_character.mind.antag_holder)
|
||||
new_character.mind.antag_holder.apply_antags(new_character)
|
||||
|
||||
if(new_character.mind)
|
||||
new_character.mind.loaded_from_ckey = picked_ckey
|
||||
|
||||
@@ -119,7 +119,15 @@
|
||||
|
||||
/mob/proc/update_examine_panel(var/atom/A)
|
||||
if(client)
|
||||
var/is_antag = ((mind && mind.special_role) || isobserver(src)) //ghosts don't have minds
|
||||
var/is_antag
|
||||
if((mind && mind.special_role) || isobserver(src)) //todo: Phase out special_role entirely and make it check for component/antag entirely.
|
||||
is_antag = TRUE
|
||||
else if(isliving(src))
|
||||
var/datum/component/antag/comp = GetComponent(/datum/component/antag)
|
||||
if(comp)
|
||||
is_antag = TRUE
|
||||
else if(mind && mind.antag_holder.is_antag())
|
||||
is_antag = TRUE
|
||||
client.update_description_holders(A, is_antag)
|
||||
SSstatpanels.set_examine_tab(client)
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
|
||||
else
|
||||
L = holder
|
||||
|
||||
L.mind.changeling.chem_charges = between(0, L.mind.changeling.chem_charges - chem_maintenance, L.mind.changeling.chem_storage)
|
||||
if(L)
|
||||
var/datum/component/antag/changeling/comp = L.GetComponent(/datum/component/antag/changeling)
|
||||
comp.chem_charges = between(0, comp.chem_charges - chem_maintenance, comp.chem_storage)
|
||||
|
||||
/datum/modifier/changeling/thermal_sight
|
||||
name = "Thermal Adaptation"
|
||||
@@ -63,7 +64,7 @@
|
||||
expire()
|
||||
return
|
||||
|
||||
var/datum/changeling/changeling = L.changeling_power(0,0,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = L.changeling_power(0,0,100,CONSCIOUS)
|
||||
|
||||
if(!changeling)
|
||||
expire()
|
||||
@@ -85,7 +86,7 @@
|
||||
L = holder
|
||||
|
||||
if(L)
|
||||
var/datum/changeling/changeling = L.changeling_power(0,0,100,CONSCIOUS)
|
||||
var/datum/component/antag/changeling/changeling = L.changeling_power(0,0,100,CONSCIOUS)
|
||||
|
||||
if(changeling)
|
||||
changeling.thermal_sight = FALSE
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
|
||||
/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask)
|
||||
|
||||
if(speaker.mind && speaker.mind.changeling)
|
||||
..(speaker,message,speaker.mind.changeling.changelingID)
|
||||
var/datum/component/antag/changeling/comp = speaker.GetComponent(/datum/component/antag/changeling)
|
||||
if(speaker.mind && comp)
|
||||
..(speaker,message,comp.changelingID)
|
||||
else
|
||||
..(speaker,message)
|
||||
|
||||
|
||||
@@ -54,10 +54,11 @@
|
||||
stop_flying()
|
||||
|
||||
//Handle snowflake ling stuff.
|
||||
if(mind && mind.changeling)
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(comp)
|
||||
// If the ling is capable of revival, don't allow them to see deadchat.
|
||||
if(mind.changeling.chem_charges >= CHANGELING_STASIS_COST)
|
||||
if(mind.changeling.max_geneticpoints >= 0) // Absorbed lings don't count, as they can't revive.
|
||||
if(comp.chem_charges >= CHANGELING_STASIS_COST)
|
||||
if(comp.max_geneticpoints >= 0) // Absorbed lings don't count, as they can't revive.
|
||||
forbid_seeing_deadchat = TRUE
|
||||
|
||||
//Handle brain slugs.
|
||||
|
||||
@@ -123,11 +123,11 @@
|
||||
if(suit.cell) cell_status = "[suit.cell.charge]/[suit.cell.maxcharge]"
|
||||
. += "Suit charge: [cell_status]"
|
||||
|
||||
if(mind)
|
||||
if(mind.changeling)
|
||||
. += "Chemical Storage: [mind.changeling.chem_charges]"
|
||||
. += "Genetic Damage Time: [mind.changeling.geneticdamage]"
|
||||
. += "Re-Adaptations: [mind.changeling.readapts]/[mind.changeling.max_readapts]"
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(comp)
|
||||
. += "Chemical Storage: [comp.chem_charges]"
|
||||
. += "Genetic Damage Time: [comp.geneticdamage]"
|
||||
. += "Re-Adaptations: [comp.readapts]/[comp.max_readapts]"
|
||||
if(species)
|
||||
species.get_status_tab_items(src)
|
||||
|
||||
|
||||
@@ -56,8 +56,9 @@
|
||||
|
||||
//This is called when we want different types of 'cloaks' to stop working, e.g. when attacking.
|
||||
/mob/living/carbon/human/break_cloak()
|
||||
if(mind && mind.changeling) //Changeling visible camo
|
||||
mind.changeling.cloaked = 0
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(comp) //Changeling visible camo
|
||||
comp.cloaked = 0
|
||||
if(istype(back, /obj/item/rig)) //Ninja cloak
|
||||
var/obj/item/rig/suit = back
|
||||
for(var/obj/item/rig_module/stealth_field/cloaker in suit.installed_modules)
|
||||
@@ -67,7 +68,8 @@
|
||||
dr.uncloak()
|
||||
|
||||
/mob/living/carbon/human/is_cloaked()
|
||||
if(mind && mind.changeling && mind.changeling.cloaked) // Ling camo.
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(comp && comp.cloaked) // Ling camo.
|
||||
return TRUE
|
||||
else if(istype(back, /obj/item/rig)) //Ninja cloak
|
||||
var/obj/item/rig/suit = back
|
||||
|
||||
@@ -1807,14 +1807,19 @@
|
||||
playsound_local(src,pick(GLOB.scarySounds),50, 1, -1)
|
||||
|
||||
/mob/living/carbon/human/proc/handle_changeling()
|
||||
if(mind && mind.changeling)
|
||||
mind.changeling.regenerate()
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(!comp)
|
||||
if(mind && hud_used)
|
||||
ling_chem_display.invisibility = INVISIBILITY_ABSTRACT
|
||||
return
|
||||
else
|
||||
comp.regenerate()
|
||||
if(hud_used)
|
||||
ling_chem_display.invisibility = INVISIBILITY_NONE
|
||||
// ling_chem_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[round(mind.changeling.chem_charges)]</font></div>"
|
||||
switch(mind.changeling.chem_storage)
|
||||
switch(comp.chem_storage)
|
||||
if(1 to 50)
|
||||
switch(mind.changeling.chem_charges)
|
||||
switch(comp.chem_charges)
|
||||
if(0 to 9)
|
||||
ling_chem_display.icon_state = "ling_chems0"
|
||||
if(10 to 19)
|
||||
@@ -1828,7 +1833,7 @@
|
||||
if(50)
|
||||
ling_chem_display.icon_state = "ling_chems50"
|
||||
if(51 to 80) //This is a crappy way of checking for engorged sacs...
|
||||
switch(mind.changeling.chem_charges)
|
||||
switch(comp.chem_charges)
|
||||
if(0 to 9)
|
||||
ling_chem_display.icon_state = "ling_chems0e"
|
||||
if(10 to 19)
|
||||
@@ -1847,9 +1852,6 @@
|
||||
ling_chem_display.icon_state = "ling_chems70e"
|
||||
if(80)
|
||||
ling_chem_display.icon_state = "ling_chems80e"
|
||||
else
|
||||
if(mind && hud_used)
|
||||
ling_chem_display.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/mob/living/carbon/human/handle_shock()
|
||||
..()
|
||||
|
||||
@@ -101,8 +101,9 @@
|
||||
voice_sub = get_id_name()
|
||||
if(voice_sub)
|
||||
return voice_sub
|
||||
if(mind && mind.changeling && mind.changeling.mimicing)
|
||||
return mind.changeling.mimicing
|
||||
var/datum/component/antag/changeling/comp = is_changeling(src)
|
||||
if(comp && comp.mimicing)
|
||||
return comp.mimicing
|
||||
if(GetSpecialVoice())
|
||||
return GetSpecialVoice()
|
||||
return real_name
|
||||
|
||||
@@ -519,14 +519,13 @@
|
||||
if(H.hallucination >= hallucination_cap && H.loneliness_stage >= warning_cap)
|
||||
return
|
||||
|
||||
// Outpost 21 addition begin - extended loneliness mechanics
|
||||
if(H.mind && H.mind.changeling) // We are never alone~
|
||||
var/datum/component/antag/changeling/comp = H.GetComponent(/datum/component/antag/changeling)
|
||||
if(comp) // We are never alone~
|
||||
H.loneliness_stage = 0
|
||||
return
|
||||
if(H.has_brain_worms()) // Brain friends!
|
||||
sub_loneliness(H)
|
||||
return
|
||||
// Outpost 21 addition end
|
||||
|
||||
// Vored? Not gonna get frightened.
|
||||
if(isbelly(H.loc))
|
||||
|
||||
@@ -371,9 +371,10 @@ var/const/CE_STABLE_THRESHOLD = 0.5
|
||||
if(!our)
|
||||
log_debug("Failed to re-initialize blood datums on [src]!")
|
||||
return
|
||||
|
||||
|
||||
if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"],injected.data["species"],our.data["species"]) )
|
||||
if(is_changeling(src)) //Changelings don't reject blood!
|
||||
vessel.add_reagent(REAGENT_ID_BLOOD, amount, injected.data)
|
||||
vessel.update_total()
|
||||
else if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"],injected.data["species"],our.data["species"]) )
|
||||
reagents.add_reagent(REAGENT_ID_TOXIN,amount * 0.5)
|
||||
reagents.update_total()
|
||||
else
|
||||
|
||||
@@ -146,6 +146,27 @@
|
||||
loc.update_icon()
|
||||
return amount_used
|
||||
|
||||
/// Recharges the cell over time. 100 per second multiplied by the multiplier.
|
||||
/obj/item/cell/proc/gradual_charge(iterations, multiplier, sparks, mob/living/user)
|
||||
var/charged_object = src
|
||||
if(!multiplier || iterations <= 0)
|
||||
return
|
||||
if(user) //If we have a user, time to check to make sure they're adjacent/holding us!
|
||||
if(istype(loc, /obj/machinery/power/apc)) //We're in an APC!
|
||||
charged_object = loc
|
||||
if(loc != user && !(user in orange(1,charged_object))) //If we have a user fed to us, they need to hold us or be in range of us.
|
||||
if(loc.loc && !istype(loc.loc, user)) //Are we inside of something the user is holding?
|
||||
return
|
||||
charge += 100 * multiplier
|
||||
if(charge > maxcharge)
|
||||
charge = maxcharge
|
||||
if(sparks)
|
||||
var/T = get_turf(src)
|
||||
new /obj/effect/effect/sparks(T)
|
||||
update_icon()
|
||||
iterations--
|
||||
addtimer(CALLBACK(src, PROC_REF(gradual_charge), iterations, multiplier, sparks, user), 1 SECOND, TIMER_DELETE_ME)
|
||||
|
||||
|
||||
/obj/item/cell/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
new_character.key = player_key
|
||||
|
||||
//Were they any particular special role? If so, copy.
|
||||
|
||||
if(new_character.mind)
|
||||
new_character.mind.loaded_from_ckey = picked_ckey
|
||||
new_character.mind.loaded_from_slot = picked_slot
|
||||
@@ -172,6 +173,8 @@
|
||||
if(antag_data)
|
||||
antag_data.add_antagonist(new_character.mind)
|
||||
antag_data.place_mob(new_character)
|
||||
if(new_character.mind.antag_holder)
|
||||
new_character.mind.antag_holder.apply_antags(new_character)
|
||||
|
||||
for(var/lang in ghost_client.prefs.alternate_languages)
|
||||
var/datum/language/chosen_language = GLOB.all_languages[lang]
|
||||
|
||||
@@ -387,6 +387,12 @@
|
||||
active_mr = null
|
||||
return
|
||||
|
||||
//Changeling lock.
|
||||
if(sleever.get_occupant().changeling_locked && !is_changeling(active_mr.mind_ref))
|
||||
set_temp("Error: Mind incompatible with body", "danger")
|
||||
active_mr = null
|
||||
return TRUE
|
||||
|
||||
var/list/subtargets = list()
|
||||
for(var/mob/living/carbon/human/H in sleever.get_occupant())
|
||||
if(H.resleeve_lock && active_mr.ckey != H.resleeve_lock)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
////////////////////////////////
|
||||
|
||||
/mob/living/carbon/human/var/resleeve_lock
|
||||
/mob/living/carbon/human/var/changeling_locked
|
||||
/mob/living/carbon/human/var/original_player
|
||||
|
||||
/////// Mind-backup record ///////
|
||||
@@ -79,6 +80,7 @@
|
||||
//These may or may not be set, mostly irrelevant since it's just a body record.
|
||||
var/ckey
|
||||
var/locked
|
||||
var/changeling_locked
|
||||
var/client/client_ref
|
||||
var/datum/mind/mind_ref
|
||||
var/synthetic
|
||||
@@ -123,6 +125,11 @@
|
||||
//Person OOCly doesn't want people impersonating them
|
||||
locked = ckeylock
|
||||
|
||||
//The mob is a changeling, don't allow anyone to possess them. Not using locked as locked gives OOC notices.
|
||||
if(is_changeling(M))
|
||||
changeling_locked = TRUE
|
||||
|
||||
|
||||
var/datum/species/S = GLOB.all_species["[M.dna.species]"]
|
||||
if(S)
|
||||
// Force ckey locking if species is whitelisted
|
||||
|
||||
@@ -493,8 +493,15 @@
|
||||
if(!occupant.mind)
|
||||
log_debug("[occupant] didn't have a mind to check for vore_death, which may be problematic.")
|
||||
|
||||
if(occupant.mind && occupant.original_player && ckey(occupant.mind.key) != occupant.original_player)
|
||||
log_and_message_admins("is now a cross-sleeved character. Body originally belonged to [occupant.real_name]. Mind is now [occupant.mind.name].",occupant)
|
||||
if(occupant.mind)
|
||||
if(occupant.original_player && ckey(occupant.mind.key) != occupant.original_player)
|
||||
log_and_message_admins("is now a cross-sleeved character. Body originally belonged to [occupant.real_name]. Mind is now [occupant.mind.name].",occupant)
|
||||
var/datum/antagonist/antag_data = get_antag_data(occupant.mind.special_role)
|
||||
if(antag_data)
|
||||
antag_data.add_antagonist(occupant.mind)
|
||||
antag_data.place_mob(occupant)
|
||||
if(occupant.mind.antag_holder)
|
||||
occupant.mind.antag_holder.apply_antags(occupant)
|
||||
|
||||
if(original_occupant)
|
||||
occupant = original_occupant
|
||||
|
||||
@@ -593,6 +593,7 @@
|
||||
if(DC.allowed(ui.user) || BR.ckey == ui.user.ckey)
|
||||
BD.load_record_to_body(BR)
|
||||
owner.resleeve_lock = BR.locked
|
||||
owner.changeling_locked = BR.changeling_locked
|
||||
DC.selected_record = TRUE
|
||||
return TRUE
|
||||
if("view_stock_brec")
|
||||
@@ -621,7 +622,9 @@
|
||||
return FALSE
|
||||
if(!DC.disk)
|
||||
return FALSE
|
||||
if(owner.resleeve_lock)
|
||||
if(owner.changeling_locked)
|
||||
to_chat(ui.user, span_warning("ERROR: Record too complex. Disk does not have enough space to store this record."))
|
||||
else if(owner.resleeve_lock)
|
||||
var/answer = tgui_alert(ui.user,"This body record will be written to a disk and allow any mind to inhabit it. This is against the current body owner's configured OOC preferences for body impersonation. Please confirm that you have permission to do this, and are sure! Admins will be notified.","Mind Compatability",list("No","Yes"))
|
||||
if(!answer)
|
||||
return
|
||||
@@ -630,7 +633,7 @@
|
||||
else
|
||||
message_admins("[ui.user] wrote an unlocked version of [owner.real_name]'s bodyrecord to a disk. Their preferences do not allow body impersonation, but may be allowed with OOC consent.")
|
||||
owner.resleeve_lock = FALSE // unlock it, even though it's only temp, so you don't get the warning every time
|
||||
if(!owner.resleeve_lock && can_change(owner, APPEARANCE_RACE))
|
||||
if(!owner.changeling_locked && (!owner.resleeve_lock && can_change(owner, APPEARANCE_RACE)))
|
||||
// Create it from the mob
|
||||
if(DC.disk.stored)
|
||||
qdel_null(DC.disk.stored)
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
/obj/belly/proc/digestion_death(mob/living/M)
|
||||
digested_prey_count++
|
||||
add_attack_logs(owner, M, "Digested in [lowertext(name)]")
|
||||
owner.changeling_obtain_dna(M)
|
||||
|
||||
// Reverts TF on death. This fixes a bug with posibrains or similar, and also makes reforming easier.
|
||||
if(M.tf_mob_holder && M.tf_mob_holder.loc == M)
|
||||
@@ -1149,6 +1150,7 @@
|
||||
// TODO - Find a way to make the absorbed prey share the effects with the pred.
|
||||
// Currently this is infeasible because reagent containers are designed to have a single my_atom, and we get
|
||||
// problems when A absorbs B, and then C absorbs A, resulting in B holding onto an invalid reagent container.
|
||||
Pred.changeling_obtain_dna(Prey)
|
||||
|
||||
//This is probably already the case, but for sub-prey, it won't be.
|
||||
if(M.loc != src)
|
||||
|
||||
@@ -154,10 +154,10 @@ Please do not abuse this ability.
|
||||
if(antag_data)
|
||||
antag_data.add_antagonist(new_character.mind)
|
||||
antag_data.place_mob(new_character)
|
||||
|
||||
if(new_character.mind)
|
||||
new_character.mind.loaded_from_ckey = picked_ckey
|
||||
new_character.mind.loaded_from_slot = picked_slot
|
||||
if(new_character.mind.antag_holder)
|
||||
new_character.mind.antag_holder.apply_antags(new_character)
|
||||
|
||||
for(var/lang in prey.prefs.alternate_languages)
|
||||
var/datum/language/chosen_language = GLOB.all_languages[lang]
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
|| species.name == SPECIES_PROTEAN \
|
||||
|| species.name == SPECIES_REPLICANT)
|
||||
return FALSE
|
||||
if(mind && mind.changeling)
|
||||
if(is_changeling(src))
|
||||
return FALSE
|
||||
|
||||
var/obj/item/organ/internal/malignant/neworgan = new type_path( src, TRUE)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useState } from 'react';
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Button, Divider, Input, Section, Stack } from 'tgui-core/components';
|
||||
import { createSearch } from 'tgui-core/string';
|
||||
|
||||
import { getButtonColor } from './functions';
|
||||
import type { powerData } from './types';
|
||||
|
||||
export const ChangeLingSearchableList = (props: {
|
||||
title: string;
|
||||
powerData: powerData[];
|
||||
points: number;
|
||||
}) => {
|
||||
const { act } = useBackend();
|
||||
|
||||
const { title, powerData, points } = props;
|
||||
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const searcher = createSearch(searchText, (power: powerData) => {
|
||||
return power.power_name;
|
||||
});
|
||||
|
||||
const shownPowers = powerData.filter(searcher);
|
||||
|
||||
return (
|
||||
<Stack.Item basis="49%" grow>
|
||||
<Section fill title={title}>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
<Input
|
||||
mr="10px"
|
||||
fluid
|
||||
value={searchText}
|
||||
placeholder={'Search for ' + title + '...'}
|
||||
onChange={(value: string) => setSearchText(value)}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Divider />
|
||||
<Stack.Item grow>
|
||||
<Section fill scrollable>
|
||||
<Stack vertical fill>
|
||||
{shownPowers
|
||||
.sort((a, b) => a.power_name.localeCompare(b.power_name))
|
||||
.map((entry) => (
|
||||
<Stack.Item key={entry.power_name}>
|
||||
<Button
|
||||
fluid
|
||||
tooltipPosition={
|
||||
entry.power_purchased ? 'left' : 'right'
|
||||
}
|
||||
disabled={
|
||||
points < entry.power_cost || entry.power_purchased
|
||||
}
|
||||
color={getButtonColor(entry, points)}
|
||||
tooltip={entry.power_desc}
|
||||
onClick={() =>
|
||||
act('evolve_power', { val: entry.power_name })
|
||||
}
|
||||
>
|
||||
<Stack>
|
||||
<Stack.Item grow>{entry.power_name}</Stack.Item>
|
||||
<Stack.Item>({entry.power_cost})</Stack.Item>
|
||||
</Stack>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
))}
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
);
|
||||
};
|
||||
12
tgui/packages/tgui/interfaces/ChangelingPanel/functions.ts
Normal file
12
tgui/packages/tgui/interfaces/ChangelingPanel/functions.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { powerData } from './types';
|
||||
|
||||
export function getButtonColor(entry: powerData, availablePoints: number) {
|
||||
if (entry.power_purchased) {
|
||||
return undefined;
|
||||
}
|
||||
if (availablePoints < entry.power_cost) {
|
||||
return 'red';
|
||||
} else {
|
||||
return 'green';
|
||||
}
|
||||
}
|
||||
43
tgui/packages/tgui/interfaces/ChangelingPanel/index.tsx
Normal file
43
tgui/packages/tgui/interfaces/ChangelingPanel/index.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useBackend } from 'tgui/backend';
|
||||
import { Window } from 'tgui/layouts';
|
||||
import { Stack } from 'tgui-core/components';
|
||||
|
||||
import { ChangeLingSearchableList } from './ChangelingPowerList';
|
||||
import type { Data } from './types';
|
||||
|
||||
export const ChangelingPanel = (props) => {
|
||||
const { data } = useBackend<Data>();
|
||||
|
||||
const { available_points, power_list } = data;
|
||||
|
||||
const purchasedPowers = power_list.filter((entry) => entry.power_purchased);
|
||||
const unpurchasedPowers = power_list.filter(
|
||||
(entry) => !entry.power_purchased,
|
||||
);
|
||||
|
||||
return (
|
||||
<Window width={600} height={700}>
|
||||
<Window.Content>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
Current evolution points left to evolve with: {available_points}
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack fill>
|
||||
<ChangeLingSearchableList
|
||||
title="Purchasable Powers"
|
||||
powerData={unpurchasedPowers}
|
||||
points={available_points}
|
||||
/>
|
||||
<ChangeLingSearchableList
|
||||
title="Purchased Powers"
|
||||
powerData={purchasedPowers}
|
||||
points={available_points}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
13
tgui/packages/tgui/interfaces/ChangelingPanel/types.ts
Normal file
13
tgui/packages/tgui/interfaces/ChangelingPanel/types.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
export type Data = {
|
||||
available_points: number;
|
||||
power_list: powerData[];
|
||||
};
|
||||
|
||||
export type powerData = {
|
||||
power_name: string;
|
||||
power_cost: number;
|
||||
power_purchased: BooleanLike;
|
||||
power_desc: string;
|
||||
};
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "code\__defines\blueprints.dm"
|
||||
#include "code\__defines\borg_overlays.dm"
|
||||
#include "code\__defines\callbacks.dm"
|
||||
#include "code\__defines\changeling.dm"
|
||||
#include "code\__defines\chat.dm"
|
||||
#include "code\__defines\chemistry.dm"
|
||||
#include "code\__defines\chemistry_vr.dm"
|
||||
@@ -544,7 +545,50 @@
|
||||
#include "code\datums\components\recursive_move.dm"
|
||||
#include "code\datums\components\resize_guard.dm"
|
||||
#include "code\datums\components\swarm.dm"
|
||||
#include "code\datums\components\waddle.dm"
|
||||
#include "code\datums\components\antags\antag.dm"
|
||||
#include "code\datums\components\antags\changeling\changeling.dm"
|
||||
#include "code\datums\components\antags\changeling\helpers\absorbed_dna.dm"
|
||||
#include "code\datums\components\antags\changeling\helpers\generic_equip_procs.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\absorb.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\armblade.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\armor.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\augmented_eyesight.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\bioelectrogenesis.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\blind_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\boost_range.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\cryo_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\darkvision.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\deaf_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\delayed_toxin_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\digital_camo.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\electric_lockpick.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\endoarmor.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\enfeebling_string.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\engorged_glands.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\enrage.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\epinephrine_overdose.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\escape_restraints.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\extract_dna_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\fabricate_clothing.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\fake_death.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\fleshmend.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\hivemind.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\lesser_form.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\lsd_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\mimic_voice.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\panacea.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\para_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\rapid_regen.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\recursive_enhancement.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\respec.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\revive.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\self_respiration.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\shriek.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\silence_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\transform.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\transform_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\unfat_sting.dm"
|
||||
#include "code\datums\components\antags\changeling\powers\visible_camouflage.dm"
|
||||
#include "code\datums\components\crafting\crafting.dm"
|
||||
#include "code\datums\components\crafting\crafting_external.dm"
|
||||
#include "code\datums\components\crafting\recipes.dm"
|
||||
@@ -567,6 +611,7 @@
|
||||
#include "code\datums\components\traits\burninlight.dm"
|
||||
#include "code\datums\components\traits\drippy.dm"
|
||||
#include "code\datums\components\traits\gargoyle.dm"
|
||||
#include "code\datums\components\traits\waddle.dm"
|
||||
#include "code\datums\components\traits\nutrition_size_change.dm"
|
||||
#include "code\datums\components\traits\photosynth.dm"
|
||||
#include "code\datums\components\traits\weaver.dm"
|
||||
@@ -858,46 +903,7 @@
|
||||
#include "code\game\gamemodes\objective.dm"
|
||||
#include "code\game\gamemodes\setupgame.dm"
|
||||
#include "code\game\gamemodes\calamity\calamity.dm"
|
||||
#include "code\game\gamemodes\changeling\absorbed_dna.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling_powers.dm"
|
||||
#include "code\game\gamemodes\changeling\generic_equip_procs.dm"
|
||||
#include "code\game\gamemodes\changeling\modularchangling.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\absorb.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\armblade.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\armor.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\augmented_eyesight.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\bioelectrogenesis.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\blind_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\boost_range.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\cryo_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\darkvision.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\deaf_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\delayed_toxin_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\digital_camo.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\electric_lockpick.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\endoarmor.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\enfeebling_string.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\engorged_glands.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\enrage.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\epinephrine_overdose.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\escape_restraints.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\extract_dna_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\fabricate_clothing.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\fake_death.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\fleshmend.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\hivemind.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\mimic_voice.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\panacea.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\rapid_regen.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\recursive_enhancement.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\respec.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\revive.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\self_respiration.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\shriek.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\silence_sting.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\transform.dm"
|
||||
#include "code\game\gamemodes\changeling\powers\visible_camouflage.dm"
|
||||
#include "code\game\gamemodes\cult\construct_spells.dm"
|
||||
#include "code\game\gamemodes\cult\construct_spells_ch.dm"
|
||||
#include "code\game\gamemodes\cult\cult.dm"
|
||||
|
||||
Reference in New Issue
Block a user