diff --git a/code/__defines/_reagents.dm b/code/__defines/_reagents.dm index fb2a736b2b..d2257c0706 100644 --- a/code/__defines/_reagents.dm +++ b/code/__defines/_reagents.dm @@ -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" diff --git a/code/__defines/changeling.dm b/code/__defines/changeling.dm new file mode 100644 index 0000000000..463589656b --- /dev/null +++ b/code/__defines/changeling.dm @@ -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" diff --git a/code/datums/components/antags/antag.dm b/code/datums/components/antags/antag.dm new file mode 100644 index 0000000000..4f4335efb1 --- /dev/null +++ b/code/datums/components/antags/antag.dm @@ -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 diff --git a/code/datums/components/antags/changeling/changeling.dm b/code/datums/components/antags/changeling/changeling.dm new file mode 100644 index 0000000000..65aa680e1e --- /dev/null +++ b/code/datums/components/antags/changeling/changeling.dm @@ -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 diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/datums/components/antags/changeling/helpers/absorbed_dna.dm similarity index 100% rename from code/game/gamemodes/changeling/absorbed_dna.dm rename to code/datums/components/antags/changeling/helpers/absorbed_dna.dm diff --git a/code/game/gamemodes/changeling/generic_equip_procs.dm b/code/datums/components/antags/changeling/helpers/generic_equip_procs.dm similarity index 93% rename from code/game/gamemodes/changeling/generic_equip_procs.dm rename to code/datums/components/antags/changeling/helpers/generic_equip_procs.dm index 21d0b5b73b..cc8ad5a68c 100644 --- a/code/game/gamemodes/changeling/generic_equip_procs.dm +++ b/code/datums/components/antags/changeling/helpers/generic_equip_procs.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/datums/components/antags/changeling/powers/absorb.dm similarity index 52% rename from code/game/gamemodes/changeling/powers/absorb.dm rename to code/datums/components/antags/changeling/powers/absorb.dm index f5ca7e53fb..451c5a889b 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/datums/components/antags/changeling/powers/absorb.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/armblade.dm b/code/datums/components/antags/changeling/powers/armblade.dm similarity index 88% rename from code/game/gamemodes/changeling/powers/armblade.dm rename to code/datums/components/antags/changeling/powers/armblade.dm index fba95bbcac..6f1c1f3fc3 100644 --- a/code/game/gamemodes/changeling/powers/armblade.dm +++ b/code/datums/components/antags/changeling/powers/armblade.dm @@ -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]!")) diff --git a/code/game/gamemodes/changeling/powers/armor.dm b/code/datums/components/antags/changeling/powers/armor.dm similarity index 95% rename from code/game/gamemodes/changeling/powers/armor.dm rename to code/datums/components/antags/changeling/powers/armor.dm index e1e0fb032a..47cc27972e 100644 --- a/code/game/gamemodes/changeling/powers/armor.dm +++ b/code/datums/components/antags/changeling/powers/armor.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/datums/components/antags/changeling/powers/augmented_eyesight.dm similarity index 71% rename from code/game/gamemodes/changeling/powers/augmented_eyesight.dm rename to code/datums/components/antags/changeling/powers/augmented_eyesight.dm index 3498e5df4d..a09870b6a1 100644 --- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm +++ b/code/datums/components/antags/changeling/powers/augmented_eyesight.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm b/code/datums/components/antags/changeling/powers/bioelectrogenesis.dm similarity index 75% rename from code/game/gamemodes/changeling/powers/bioelectrogenesis.dm rename to code/datums/components/antags/changeling/powers/bioelectrogenesis.dm index bdbebb740d..1da904f78c 100644 --- a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm +++ b/code/datums/components/antags/changeling/powers/bioelectrogenesis.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/blind_sting.dm b/code/datums/components/antags/changeling/powers/blind_sting.dm similarity index 64% rename from code/game/gamemodes/changeling/powers/blind_sting.dm rename to code/datums/components/antags/changeling/powers/blind_sting.dm index 40d5f96824..9553fe3eff 100644 --- a/code/game/gamemodes/changeling/powers/blind_sting.dm +++ b/code/datums/components/antags/changeling/powers/blind_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/boost_range.dm b/code/datums/components/antags/changeling/powers/boost_range.dm similarity index 66% rename from code/game/gamemodes/changeling/powers/boost_range.dm rename to code/datums/components/antags/changeling/powers/boost_range.dm index 1b818a1f03..d710109abc 100644 --- a/code/game/gamemodes/changeling/powers/boost_range.dm +++ b/code/datums/components/antags/changeling/powers/boost_range.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/cryo_sting.dm b/code/datums/components/antags/changeling/powers/cryo_sting.dm similarity index 59% rename from code/game/gamemodes/changeling/powers/cryo_sting.dm rename to code/datums/components/antags/changeling/powers/cryo_sting.dm index b61b5b00ed..2cc45b6a3b 100644 --- a/code/game/gamemodes/changeling/powers/cryo_sting.dm +++ b/code/datums/components/antags/changeling/powers/cryo_sting.dm @@ -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.")) diff --git a/code/game/gamemodes/changeling/powers/darkvision.dm b/code/datums/components/antags/changeling/powers/darkvision.dm similarity index 89% rename from code/game/gamemodes/changeling/powers/darkvision.dm rename to code/datums/components/antags/changeling/powers/darkvision.dm index 3139a85e39..2489c551c9 100644 --- a/code/game/gamemodes/changeling/powers/darkvision.dm +++ b/code/datums/components/antags/changeling/powers/darkvision.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/deaf_sting.dm b/code/datums/components/antags/changeling/powers/deaf_sting.dm similarity index 87% rename from code/game/gamemodes/changeling/powers/deaf_sting.dm rename to code/datums/components/antags/changeling/powers/deaf_sting.dm index e03205665c..9b6689eb15 100644 --- a/code/game/gamemodes/changeling/powers/deaf_sting.dm +++ b/code/datums/components/antags/changeling/powers/deaf_sting.dm @@ -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!")) diff --git a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm b/code/datums/components/antags/changeling/powers/delayed_toxin_sting.dm similarity index 94% rename from code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm rename to code/datums/components/antags/changeling/powers/delayed_toxin_sting.dm index bbd63db65f..d2e5384617 100644 --- a/code/game/gamemodes/changeling/powers/delayed_toxin_sting.dm +++ b/code/datums/components/antags/changeling/powers/delayed_toxin_sting.dm @@ -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.")) diff --git a/code/game/gamemodes/changeling/powers/digital_camo.dm b/code/datums/components/antags/changeling/powers/digital_camo.dm similarity index 74% rename from code/game/gamemodes/changeling/powers/digital_camo.dm rename to code/datums/components/antags/changeling/powers/digital_camo.dm index cca4f054ae..be0e7e3766 100644 --- a/code/game/gamemodes/changeling/powers/digital_camo.dm +++ b/code/datums/components/antags/changeling/powers/digital_camo.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/electric_lockpick.dm b/code/datums/components/antags/changeling/powers/electric_lockpick.dm similarity index 95% rename from code/game/gamemodes/changeling/powers/electric_lockpick.dm rename to code/datums/components/antags/changeling/powers/electric_lockpick.dm index 62ab50231b..cde4fcbb97 100644 --- a/code/game/gamemodes/changeling/powers/electric_lockpick.dm +++ b/code/datums/components/antags/changeling/powers/electric_lockpick.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/endoarmor.dm b/code/datums/components/antags/changeling/powers/endoarmor.dm similarity index 95% rename from code/game/gamemodes/changeling/powers/endoarmor.dm rename to code/datums/components/antags/changeling/powers/endoarmor.dm index 6ada286574..c2ca894f06 100644 --- a/code/game/gamemodes/changeling/powers/endoarmor.dm +++ b/code/datums/components/antags/changeling/powers/endoarmor.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/enfeebling_string.dm b/code/datums/components/antags/changeling/powers/enfeebling_string.dm similarity index 94% rename from code/game/gamemodes/changeling/powers/enfeebling_string.dm rename to code/datums/components/antags/changeling/powers/enfeebling_string.dm index 49829aecce..05dc875fd0 100644 --- a/code/game/gamemodes/changeling/powers/enfeebling_string.dm +++ b/code/datums/components/antags/changeling/powers/enfeebling_string.dm @@ -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) diff --git a/code/game/gamemodes/changeling/powers/engorged_glands.dm b/code/datums/components/antags/changeling/powers/engorged_glands.dm similarity index 69% rename from code/game/gamemodes/changeling/powers/engorged_glands.dm rename to code/datums/components/antags/changeling/powers/engorged_glands.dm index 8efb2cf46d..f0513f86be 100644 --- a/code/game/gamemodes/changeling/powers/engorged_glands.dm +++ b/code/datums/components/antags/changeling/powers/engorged_glands.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/enrage.dm b/code/datums/components/antags/changeling/powers/enrage.dm similarity index 90% rename from code/game/gamemodes/changeling/powers/enrage.dm rename to code/datums/components/antags/changeling/powers/enrage.dm index 2336b3042a..79c024eb99 100644 --- a/code/game/gamemodes/changeling/powers/enrage.dm +++ b/code/datums/components/antags/changeling/powers/enrage.dm @@ -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.")) diff --git a/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm b/code/datums/components/antags/changeling/powers/epinephrine_overdose.dm similarity index 81% rename from code/game/gamemodes/changeling/powers/epinephrine_overdose.dm rename to code/datums/components/antags/changeling/powers/epinephrine_overdose.dm index 5ef4de1558..38177dc956 100644 --- a/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm +++ b/code/datums/components/antags/changeling/powers/epinephrine_overdose.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/escape_restraints.dm b/code/datums/components/antags/changeling/powers/escape_restraints.dm similarity index 73% rename from code/game/gamemodes/changeling/powers/escape_restraints.dm rename to code/datums/components/antags/changeling/powers/escape_restraints.dm index 504cb884c9..09d5a0b41b 100644 --- a/code/game/gamemodes/changeling/powers/escape_restraints.dm +++ b/code/datums/components/antags/changeling/powers/escape_restraints.dm @@ -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.")) diff --git a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm b/code/datums/components/antags/changeling/powers/extract_dna_sting.dm similarity index 83% rename from code/game/gamemodes/changeling/powers/extract_dna_sting.dm rename to code/datums/components/antags/changeling/powers/extract_dna_sting.dm index 3584f58f05..bbf8d8b11f 100644 --- a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm +++ b/code/datums/components/antags/changeling/powers/extract_dna_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm b/code/datums/components/antags/changeling/powers/fabricate_clothing.dm similarity index 99% rename from code/game/gamemodes/changeling/powers/fabricate_clothing.dm rename to code/datums/components/antags/changeling/powers/fabricate_clothing.dm index 5e4979cb2d..bf52f673e2 100644 --- a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm +++ b/code/datums/components/antags/changeling/powers/fabricate_clothing.dm @@ -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, diff --git a/code/game/gamemodes/changeling/powers/fake_death.dm b/code/datums/components/antags/changeling/powers/fake_death.dm similarity index 60% rename from code/game/gamemodes/changeling/powers/fake_death.dm rename to code/datums/components/antags/changeling/powers/fake_death.dm index e8a3121eee..18a25d5ef6 100644 --- a/code/game/gamemodes/changeling/powers/fake_death.dm +++ b/code/datums/components/antags/changeling/powers/fake_death.dm @@ -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 Revive 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 Revive verb when you are ready."))) diff --git a/code/datums/components/antags/changeling/powers/fleshmend.dm b/code/datums/components/antags/changeling/powers/fleshmend.dm new file mode 100644 index 0000000000..8aa80e17a8 --- /dev/null +++ b/code/datums/components/antags/changeling/powers/fleshmend.dm @@ -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) diff --git a/code/game/gamemodes/changeling/powers/hivemind.dm b/code/datums/components/antags/changeling/powers/hivemind.dm similarity index 88% rename from code/game/gamemodes/changeling/powers/hivemind.dm rename to code/datums/components/antags/changeling/powers/hivemind.dm index 44f66c8791..84e86afa9c 100644 --- a/code/game/gamemodes/changeling/powers/hivemind.dm +++ b/code/datums/components/antags/changeling/powers/hivemind.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/lesser_form.dm b/code/datums/components/antags/changeling/powers/lesser_form.dm similarity index 92% rename from code/game/gamemodes/changeling/powers/lesser_form.dm rename to code/datums/components/antags/changeling/powers/lesser_form.dm index be438634aa..9a6c18a695 100644 --- a/code/game/gamemodes/changeling/powers/lesser_form.dm +++ b/code/datums/components/antags/changeling/powers/lesser_form.dm @@ -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) diff --git a/code/game/gamemodes/changeling/powers/lsd_sting.dm b/code/datums/components/antags/changeling/powers/lsd_sting.dm similarity index 75% rename from code/game/gamemodes/changeling/powers/lsd_sting.dm rename to code/datums/components/antags/changeling/powers/lsd_sting.dm index 9529b13280..35e59ce04a 100644 --- a/code/game/gamemodes/changeling/powers/lsd_sting.dm +++ b/code/datums/components/antags/changeling/powers/lsd_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/mimic_voice.dm b/code/datums/components/antags/changeling/powers/mimic_voice.dm similarity index 81% rename from code/game/gamemodes/changeling/powers/mimic_voice.dm rename to code/datums/components/antags/changeling/powers/mimic_voice.dm index f5d65b8ec2..4464f30618 100644 --- a/code/game/gamemodes/changeling/powers/mimic_voice.dm +++ b/code/datums/components/antags/changeling/powers/mimic_voice.dm @@ -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 = "" diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/datums/components/antags/changeling/powers/panacea.dm similarity index 89% rename from code/game/gamemodes/changeling/powers/panacea.dm rename to code/datums/components/antags/changeling/powers/panacea.dm index 19a043669a..c7660af55f 100644 --- a/code/game/gamemodes/changeling/powers/panacea.dm +++ b/code/datums/components/antags/changeling/powers/panacea.dm @@ -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) diff --git a/code/game/gamemodes/changeling/powers/para_sting.dm b/code/datums/components/antags/changeling/powers/para_sting.dm similarity index 94% rename from code/game/gamemodes/changeling/powers/para_sting.dm rename to code/datums/components/antags/changeling/powers/para_sting.dm index 2b2cf636ed..6ab8c96203 100644 --- a/code/game/gamemodes/changeling/powers/para_sting.dm +++ b/code/datums/components/antags/changeling/powers/para_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/rapid_regen.dm b/code/datums/components/antags/changeling/powers/rapid_regen.dm similarity index 91% rename from code/game/gamemodes/changeling/powers/rapid_regen.dm rename to code/datums/components/antags/changeling/powers/rapid_regen.dm index b33e250312..3d371e3997 100644 --- a/code/game/gamemodes/changeling/powers/rapid_regen.dm +++ b/code/datums/components/antags/changeling/powers/rapid_regen.dm @@ -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) diff --git a/code/game/gamemodes/changeling/powers/recursive_enhancement.dm b/code/datums/components/antags/changeling/powers/recursive_enhancement.dm similarity index 75% rename from code/game/gamemodes/changeling/powers/recursive_enhancement.dm rename to code/datums/components/antags/changeling/powers/recursive_enhancement.dm index 21ce98bf1c..e70596d6e7 100644 --- a/code/game/gamemodes/changeling/powers/recursive_enhancement.dm +++ b/code/datums/components/antags/changeling/powers/recursive_enhancement.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/respec.dm b/code/datums/components/antags/changeling/powers/respec.dm similarity index 81% rename from code/game/gamemodes/changeling/powers/respec.dm rename to code/datums/components/antags/changeling/powers/respec.dm index 371307700e..bf98cf2937 100644 --- a/code/game/gamemodes/changeling/powers/respec.dm +++ b/code/datums/components/antags/changeling/powers/respec.dm @@ -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)) diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/datums/components/antags/changeling/powers/revive.dm similarity index 71% rename from code/game/gamemodes/changeling/powers/revive.dm rename to code/datums/components/antags/changeling/powers/revive.dm index d3ebd820c3..2effde42d8 100644 --- a/code/game/gamemodes/changeling/powers/revive.dm +++ b/code/datums/components/antags/changeling/powers/revive.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/self_respiration.dm b/code/datums/components/antags/changeling/powers/self_respiration.dm similarity index 77% rename from code/game/gamemodes/changeling/powers/self_respiration.dm rename to code/datums/components/antags/changeling/powers/self_respiration.dm index 4b939c8b89..ed6e9ffd90 100644 --- a/code/game/gamemodes/changeling/powers/self_respiration.dm +++ b/code/datums/components/antags/changeling/powers/self_respiration.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/datums/components/antags/changeling/powers/shriek.dm similarity index 67% rename from code/game/gamemodes/changeling/powers/shriek.dm rename to code/datums/components/antags/changeling/powers/shriek.dm index e5112133e1..ed2e25ae5e 100644 --- a/code/game/gamemodes/changeling/powers/shriek.dm +++ b/code/datums/components/antags/changeling/powers/shriek.dm @@ -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.")) diff --git a/code/game/gamemodes/changeling/powers/silence_sting.dm b/code/datums/components/antags/changeling/powers/silence_sting.dm similarity index 83% rename from code/game/gamemodes/changeling/powers/silence_sting.dm rename to code/datums/components/antags/changeling/powers/silence_sting.dm index c94713b9b1..2ae21a6b27 100644 --- a/code/game/gamemodes/changeling/powers/silence_sting.dm +++ b/code/datums/components/antags/changeling/powers/silence_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/datums/components/antags/changeling/powers/transform.dm similarity index 77% rename from code/game/gamemodes/changeling/powers/transform.dm rename to code/datums/components/antags/changeling/powers/transform.dm index 606beda59e..2925e1fb3b 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/datums/components/antags/changeling/powers/transform.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/transform_sting.dm b/code/datums/components/antags/changeling/powers/transform_sting.dm similarity index 91% rename from code/game/gamemodes/changeling/powers/transform_sting.dm rename to code/datums/components/antags/changeling/powers/transform_sting.dm index 5b4e99f5b2..158f617383 100644 --- a/code/game/gamemodes/changeling/powers/transform_sting.dm +++ b/code/datums/components/antags/changeling/powers/transform_sting.dm @@ -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 diff --git a/code/game/gamemodes/changeling/powers/unfat_sting.dm b/code/datums/components/antags/changeling/powers/unfat_sting.dm similarity index 73% rename from code/game/gamemodes/changeling/powers/unfat_sting.dm rename to code/datums/components/antags/changeling/powers/unfat_sting.dm index 57321859f2..c5d2c05e07 100644 --- a/code/game/gamemodes/changeling/powers/unfat_sting.dm +++ b/code/datums/components/antags/changeling/powers/unfat_sting.dm @@ -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 diff --git a/code/datums/components/antags/changeling/powers/visible_camouflage.dm b/code/datums/components/antags/changeling/powers/visible_camouflage.dm new file mode 100644 index 0000000000..922981b282 --- /dev/null +++ b/code/datums/components/antags/changeling/powers/visible_camouflage.dm @@ -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 diff --git a/code/datums/components/waddle.dm b/code/datums/components/traits/waddle.dm similarity index 100% rename from code/datums/components/waddle.dm rename to code/datums/components/traits/waddle.dm diff --git a/code/datums/managed_browsers/changelingevolution.dm b/code/datums/managed_browsers/changelingevolution.dm deleted file mode 100644 index e09511fef5..0000000000 --- a/code/datums/managed_browsers/changelingevolution.dm +++ /dev/null @@ -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("
") - var/geneticpoints_current = my_client.mob.mind.changeling.geneticpoints - var/geneticpoints_max = my_client.mob.mind.changeling.max_geneticpoints - - dat += "|
- Changling Evolution Menu - Hover over a power to see more information - Current evolution points left to evolve with: [geneticpoints] - Absorb other changelings to acquire more evolution points - - |
-
| - Search: - | -
|
-
-
- Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost]
-
- - |
-