From 37953d4bcfbc7d04295d6bdf7683da4f1cbd98f2 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 10 Mar 2023 07:08:19 +0100 Subject: [PATCH] [MIRROR] Makes Lesser Form into one ability & unit tests it [MDB IGNORE] (#19521) * Makes Lesser Form into one ability & unit tests it * Update headcrab.dm --------- Co-authored-by: Jacquerel Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> --- code/datums/dna.dm | 7 +- .../antagonists/changeling/changeling.dm | 2 +- .../changeling/changeling_power.dm | 20 ++--- .../antagonists/changeling/powers/absorb.dm | 8 +- .../changeling/powers/augmented_eyesight.dm | 4 +- .../changeling/powers/biodegrade.dm | 2 +- .../changeling/powers/fakedeath.dm | 2 +- .../changeling/powers/fleshmend.dm | 2 +- .../changeling/powers/lesserform.dm | 81 +++++++++++------ .../changeling/powers/mutations.dm | 88 ++++++++++++------- .../changeling/powers/regenerate.dm | 2 +- .../changeling/powers/tiny_prick.dm | 8 +- code/modules/mob/living/carbon/human/dummy.dm | 3 + .../mob/living/carbon/human/species.dm | 2 +- .../living/simple_animal/hostile/headcrab.dm | 7 +- code/modules/mob/transform_procs.dm | 13 ++- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/lesserform.dm | 23 +++++ tgstation.dme | 1 - 19 files changed, 178 insertions(+), 98 deletions(-) create mode 100644 code/modules/unit_tests/lesserform.dm diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 098eb083abf..5680227a9ee 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -531,11 +531,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) return death_sound = new_race.death_sound - if (dna.species.properly_gained) - dna.species.on_species_loss(src, new_race, pref_load) - var/datum/species/old_species = dna.species dna.species = new_race + + if (old_species.properly_gained) + old_species.on_species_loss(src, new_race, pref_load) + dna.species.on_species_gain(src, old_species, pref_load) if(ishuman(src)) qdel(language_holder) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 43b0a90e271..eab04891e7f 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -343,7 +343,7 @@ var/cap_to = isnum(override_cap) ? override_cap : total_chem_storage chem_charges = clamp(chem_charges + amount, 0, cap_to) - lingchemdisplay.maptext = FORMAT_CHEM_CHARGES_TEXT(chem_charges) + lingchemdisplay?.maptext = FORMAT_CHEM_CHARGES_TEXT(chem_charges) /* * Remove changeling powers from the current Changeling's purchased_powers list. diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index 3c16ae3ebe2..9ae7ac977be 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -69,21 +69,21 @@ the same goes for Remove(). if you override Remove(), call parent or else your p /datum/action/changeling/proc/can_sting(mob/living/user, mob/living/target) if(!can_be_used_by(user)) return FALSE - var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling) - if(c.chem_charges < chemical_cost) - to_chat(user, span_warning("We require at least [chemical_cost] unit\s of chemicals to do that!")) + var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) + if(changeling.chem_charges < chemical_cost) + user.balloon_alert(user, "needs [chemical_cost] chemicals!") return FALSE - if(c.absorbed_count < req_dna) - to_chat(user, span_warning("We require at least [req_dna] sample\s of compatible DNA.")) + if(changeling.absorbed_count < req_dna) + user.balloon_alert(user, "needs [req_dna] dna sample\s!") return FALSE - if(c.true_absorbs < req_absorbs) - to_chat(user, span_warning("We require at least [req_absorbs] sample\s of DNA gained through our Absorb ability.")) + if(changeling.true_absorbs < req_absorbs) + user.balloon_alert(user, "needs [req_absorbs] absorption\s!") return FALSE if(req_stat < user.stat) - to_chat(user, span_warning("We are incapacitated.")) + user.balloon_alert(user, "incapacitated!") return FALSE if((HAS_TRAIT(user, TRAIT_DEATHCOMA)) && (!ignores_fakedeath)) - to_chat(user, span_warning("We are incapacitated.")) + user.balloon_alert(user, "playing dead!") return FALSE return TRUE @@ -93,6 +93,6 @@ the same goes for Remove(). if you override Remove(), call parent or else your p if(!ishuman(user)) return FALSE if(req_human && ismonkey(user)) - to_chat(user, span_warning("This ability requires you be in human form!")) + user.balloon_alert(user, "become human!") return FALSE return TRUE diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 3e6e952ce7f..9a295fc8ac2 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -13,14 +13,14 @@ return if(is_absorbing) - to_chat(owner, span_warning("We are already absorbing!")) + owner.balloon_alert(owner, "already absorbing!") return if(!owner.pulling || !iscarbon(owner.pulling)) - to_chat(owner, span_warning("We must be grabbing a creature to absorb them!")) + owner.balloon_alert(owner, "needs grab!") return if(owner.grab_state <= GRAB_NECK) - to_chat(owner, span_warning("We must have a tighter grip to absorb this creature!")) + owner.balloon_alert(owner, "needs tighter grip!") return var/mob/living/carbon/target = owner.pulling @@ -161,7 +161,7 @@ SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[absorbing_iteration]")) if(!do_after(owner, 15 SECONDS, target)) - to_chat(owner, span_warning("Our absorption of [target] has been interrupted!")) + owner.balloon_alert(owner, "interrupted!") is_absorbing = FALSE return FALSE return TRUE diff --git a/code/modules/antagonists/changeling/powers/augmented_eyesight.dm b/code/modules/antagonists/changeling/powers/augmented_eyesight.dm index 29ce2f94113..afc4f441c63 100644 --- a/code/modules/antagonists/changeling/powers/augmented_eyesight.dm +++ b/code/modules/antagonists/changeling/powers/augmented_eyesight.dm @@ -37,8 +37,8 @@ active = FALSE user.update_sight() else - to_chat(user, "We can't adjust our eyes if we don't have any!") - return 1 + user.balloon_alert(user, "no eyes!") + return TRUE /datum/action/changeling/augmented_eyesight/Remove(mob/user) //Get rid of x-ray vision and flash protection when the user refunds this ability diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index da8cce9607b..16bd707831b 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -10,7 +10,7 @@ /datum/action/changeling/biodegrade/sting_action(mob/living/carbon/human/user) var/used = FALSE // only one form of shackles removed per use if(!HAS_TRAIT(user, TRAIT_RESTRAINED) && !user.legcuffed && isopenturf(user.loc)) - to_chat(user, span_warning("We are already free!")) + user.balloon_alert(user, "already free!") return FALSE if(user.handcuffed) diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm index c83345ffdd9..8166e23f310 100644 --- a/code/modules/antagonists/changeling/powers/fakedeath.dm +++ b/code/modules/antagonists/changeling/powers/fakedeath.dm @@ -63,7 +63,7 @@ /datum/action/changeling/fakedeath/can_sting(mob/living/user) if(HAS_TRAIT_FROM(user, TRAIT_DEATHCOMA, "changeling") && !revive_ready) - to_chat(user, span_warning("We are already reviving.")) + user.balloon_alert(user, "already reviving!") return if(!user.stat && !revive_ready) //Confirmation for living changelings if they want to fake their death switch(tgui_alert(usr,"Are we sure we wish to fake our own death?", "Feign Death", list("Yes", "No"))) diff --git a/code/modules/antagonists/changeling/powers/fleshmend.dm b/code/modules/antagonists/changeling/powers/fleshmend.dm index 2a9c89f1235..0f1b5d8f2f1 100644 --- a/code/modules/antagonists/changeling/powers/fleshmend.dm +++ b/code/modules/antagonists/changeling/powers/fleshmend.dm @@ -11,7 +11,7 @@ //Can be used whilst unconscious. /datum/action/changeling/fleshmend/sting_action(mob/living/user) if(user.has_status_effect(/datum/status_effect/fleshmend)) - to_chat(user, span_warning("We are already fleshmending!")) + user.balloon_alert(user, "already fleshmending!") return ..() to_chat(user, span_notice("We begin to heal rapidly.")) diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm index acac97322ea..f4aab1c8968 100644 --- a/code/modules/antagonists/changeling/powers/lesserform.dm +++ b/code/modules/antagonists/changeling/powers/lesserform.dm @@ -5,14 +5,17 @@ button_icon_state = "lesser_form" chemical_cost = 5 dna_cost = 1 - req_human = TRUE + /// Whether to allow the transformation animation to play + var/transform_instantly = FALSE /datum/action/changeling/lesserform/Grant(mob/granted_to) . = ..() - RegisterSignal(granted_to, COMSIG_HUMAN_MONKEYIZE, PROC_REF(swap_powers)) + if (!owner) + return + RegisterSignals(granted_to, list(COMSIG_HUMAN_MONKEYIZE, COMSIG_MONKEY_HUMANIZE), PROC_REF(changed_form)) /datum/action/changeling/lesserform/Remove(mob/remove_from) - UnregisterSignal(remove_from, COMSIG_HUMAN_MONKEYIZE) + UnregisterSignal(remove_from, list(COMSIG_HUMAN_MONKEYIZE, COMSIG_MONKEY_HUMANIZE)) return ..() //Transform into a monkey. @@ -20,34 +23,54 @@ if(!user || user.notransform) return FALSE ..() - to_chat(user, span_warning("Our genes cry out!")) - user.monkeyize() + return ismonkey(user) ? unmonkey(user) : become_monkey(user) + +/// Stop being a monkey +/datum/action/changeling/lesserform/proc/unmonkey(mob/living/carbon/human/user) + if(user.movement_type & VENTCRAWLING) + user.balloon_alert(user, "can't transform in pipes!") + return FALSE + var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) + var/datum/changeling_profile/chosen_form = select_form(changeling, user) + if(!chosen_form) + return FALSE + to_chat(user, span_notice("We transform our appearance.")) + var/datum/dna/chosen_dna = chosen_form.dna + var/datum/species/chosen_species = chosen_dna.species + user.humanize(species = chosen_species, instant = transform_instantly) + + changeling.transform(user, chosen_form) + user.regenerate_icons() return TRUE -/** - * Called on COMSIG_HUMAN_MONKEYIZE - * Handles giving the new human force ability and removing ourselves - * - * Args: - * source - Human user who is now turning into a monkey - */ -/datum/action/changeling/lesserform/proc/swap_powers(mob/living/carbon/source) +/// Returns the form to transform back into, automatically selects your only profile if you only have one +/datum/action/changeling/lesserform/proc/select_form(datum/antagonist/changeling/changeling, mob/living/carbon/human/user) + if (!changeling) + return + if (length(changeling.stored_profiles) == 1) + return changeling.first_profile + return changeling?.select_dna() + +/// Become a monkey +/datum/action/changeling/lesserform/proc/become_monkey(mob/living/carbon/human/user) + to_chat(user, span_warning("Our genes cry out!")) + user.monkeyize(instant = transform_instantly) + return TRUE + +/// Called when you become a human or monkey, whether or not it was voluntary +/datum/action/changeling/lesserform/proc/changed_form() SIGNAL_HANDLER + build_all_button_icons(update_flags = UPDATE_BUTTON_NAME | UPDATE_BUTTON_ICON) - var/datum/antagonist/changeling/changeling = source.mind.has_antag_datum(/datum/antagonist/changeling) - // Drops all flesh disguise items after monkeyizing, because they don't drop automatically like real clothing. - for(var/slot in changeling.slot2type) - if(istype(source.vars[slot], changeling.slot2type[slot])) - qdel(source.vars[slot]) - for(var/datum/scar/iter_scar as anything in source.all_scars) - if(iter_scar.fake) - qdel(iter_scar) - source.regenerate_icons() +/datum/action/changeling/lesserform/update_button_name(atom/movable/screen/movable/action_button/button, force) + if (ismonkey(owner)) + name = "Human Form" + desc = "We change back into a human. Costs 5 chemicals." + else + name = initial(name) + desc = initial(desc) + return ..() - var/datum/action/changeling/humanform/from_monkey/human_form_ability = new() - changeling.purchased_powers += human_form_ability - changeling.purchased_powers -= src - - human_form_ability.Grant(source) - Remove(source) - qdel(src) +/datum/action/changeling/lesserform/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force) + button_icon_state = ismonkey(owner) ? "human_form" : initial(button_icon_state) + return ..() diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 04c9ebceb1f..c34aa018b78 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -21,10 +21,32 @@ var/weapon_type var/weapon_name_simple +/datum/action/changeling/weapon/Grant(mob/granted_to) + . = ..() + if (!owner || !req_human) + return + RegisterSignal(granted_to, COMSIG_HUMAN_MONKEYIZE, PROC_REF(became_monkey)) + +/datum/action/changeling/weapon/Remove(mob/remove_from) + UnregisterSignal(remove_from, COMSIG_HUMAN_MONKEYIZE) + unequip_held(remove_from) + return ..() + +/// Remove weapons if we become a monkey +/datum/action/changeling/weapon/proc/became_monkey(mob/source) + SIGNAL_HANDLER + unequip_held(source) + +/// Removes weapon if it exists, returns true if we removed something +/datum/action/changeling/weapon/proc/unequip_held(mob/user) + var/found_weapon = FALSE + for(var/obj/item/held in user.held_items) + found_weapon = check_weapon(user, held) || found_weapon + return found_weapon + /datum/action/changeling/weapon/try_to_sting(mob/user, mob/target) - for(var/obj/item/I in user.held_items) - if(check_weapon(user, I)) - return + if (unequip_held(user)) + return ..(user, target) /datum/action/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item) @@ -34,15 +56,15 @@ playsound(user, 'sound/effects/blobattack.ogg', 30, TRUE) user.visible_message(span_warning("With a sickening crunch, [user] reforms [user.p_their()] [weapon_name_simple] into an arm!"), span_notice("We assimilate the [weapon_name_simple] back into our body."), "