From 43bdced1e8ed4ab97cb7897c10a520aff2355927 Mon Sep 17 00:00:00 2001 From: Git-Nivrak <59925169+Git-Nivrak@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:26:24 +0200 Subject: [PATCH] Xeno strain resetting (#7841) # About the pull request Allows xenos to reset their strain, first use is free after that it can be used every 40 minutes # Explain why it's good for the game Allows players to change their strain if they do not enjoy playing it anymore or the round has went on for long enough it became basically useless - happier players >> profit. (You could also make a point for new players that accidently clicked a strain out of curiosity and now want to reset it) # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: add: Xenomorphs can now reset their strain, first use is free then it can be done once every 40 minutes. /:cl: --------- Co-authored-by: Zenith <109559450+Zenith00000@users.noreply.github.com> Co-authored-by: Blundir <100090741+Blundir@users.noreply.github.com> Co-authored-by: cmss13-ci[bot] <180991813+cmss13-ci[bot]@users.noreply.github.com> --- code/__DEFINES/keybinding.dm | 1 + code/datums/keybinding/xenomorph.dm | 15 +++++ .../mob/living/carbon/xenomorph/Evolution.dm | 27 ++++++--- .../mob/living/carbon/xenomorph/Xenomorph.dm | 1 + .../xenomorph/abilities/queen/queen_powers.dm | 58 ++----------------- .../carbon/xenomorph/strains/xeno_strain.dm | 39 ++++++++++++- 6 files changed, 79 insertions(+), 62 deletions(-) diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 9345599dab2d..2c656212ae23 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -167,6 +167,7 @@ #define COMSIG_KB_XENO_HIDE "keybinding_hide" #define COMSIG_KB_XENO_EVOLVE "keybinding_evolve" #define COMSIG_KB_XENO_PURCHASE_STRAIN "keybinding_purchase_strain" +#define COMSIG_KB_XENO_RESET_STRAIN "keybinding_reset_strain" // Yautja diff --git a/code/datums/keybinding/xenomorph.dm b/code/datums/keybinding/xenomorph.dm index 64acd876b49f..92c11a0d19ad 100644 --- a/code/datums/keybinding/xenomorph.dm +++ b/code/datums/keybinding/xenomorph.dm @@ -221,3 +221,18 @@ var/mob/living/carbon/xenomorph/current_xeno = user?.mob current_xeno.purchase_strain() + +/datum/keybinding/xenomorph/reset_strain + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "reset_strain" + full_name = "Reset Strain" + keybind_signal = COMSIG_KB_XENO_RESET_STRAIN + +/datum/keybinding/xenomorph/reset_strain/down(client/user) + . = ..() + if(.) + return + + var/mob/living/carbon/xenomorph/current_xeno = user?.mob + current_xeno.reset_strain() diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 33924c8a1963..bcb61ecc1703 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -309,27 +309,39 @@ SEND_SIGNAL(src, COMSIG_XENO_DEEVOLVE) + var/mob/living/carbon/xenomorph/new_xeno = transmute(newcaste) + if(new_xeno) + log_game("EVOLVE: [key_name(src)] de-evolved into [new_xeno].") + + return + +/mob/living/carbon/xenomorph/proc/transmute(newcaste) + // We have to delete the organ before creating the new xeno because all old_xeno contents are dropped to the ground on Initalize() var/obj/item/organ/xeno/organ = locate() in src if(!isnull(organ)) qdel(organ) var/level_to_switch_to = get_vision_level() var/xeno_type = GLOB.RoleAuthority.get_caste_by_text(newcaste) - var/mob/living/carbon/xenomorph/new_xeno = new xeno_type(get_turf(src), src) - + if(!istype(new_xeno)) - //Something went horribly wrong! + //Something went horribly wrong to_chat(src, SPAN_WARNING("Something went terribly wrong here. Your new xeno is null! Tell a coder immediately!")) if(new_xeno) qdel(new_xeno) - return + + if(organ_value != 0) + organ = new() + organ.forceMove(src) + organ.research_value = organ_value + organ.caste_origin = caste_type + organ.icon_state = get_organ_icon() + return FALSE new_xeno.built_structures = built_structures.Copy() built_structures = null - log_game("EVOLVE: [key_name(src)] de-evolved into [new_xeno].") - if(mind) mind.transfer_to(new_xeno) else @@ -363,7 +375,8 @@ SSround_recording.recorder.track_player(new_xeno) qdel(src) - return + + return new_xeno /mob/living/carbon/xenomorph/proc/can_evolve(castepick, potential_queens) var/selected_caste = GLOB.xeno_datum_list[castepick]?.type diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 236ca482a1d2..3c68b3c986ab 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -208,6 +208,7 @@ var/armor_integrity_modifier = 0 var/list/modifier_sources + COOLDOWN_DECLARE(next_strain_reset) ////////////////////////////////////////////////////////////////// // diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm index c73a1d7e66cb..431893bb014c 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm @@ -63,61 +63,15 @@ SEND_SIGNAL(target_xeno, COMSIG_XENO_DEEVOLVE) - var/obj/item/organ/xeno/organ = locate() in target_xeno - if(!isnull(organ)) - qdel(organ) + var/mob/living/carbon/xenomorph/new_xeno = target_xeno.transmute(newcaste) - var/level_to_switch_to = target_xeno.get_vision_level() - var/xeno_type = GLOB.RoleAuthority.get_caste_by_text(newcaste) + if(new_xeno) + message_admins("[key_name_admin(user_xeno)] has deevolved [key_name_admin(target_xeno)]. Reason: [reason]") + log_admin("[key_name_admin(user_xeno)] has deevolved [key_name_admin(target_xeno)]. Reason: [reason]") - //From there, the new xeno exists, hopefully - var/mob/living/carbon/xenomorph/new_xeno = new xeno_type(get_turf(target_xeno), target_xeno) + if(user_xeno.hive.living_xeno_queen && user_xeno.hive.living_xeno_queen.observed_xeno == target_xeno) + user_xeno.hive.living_xeno_queen.overwatch(new_xeno) - if(!istype(new_xeno)) - //Something went horribly wrong! - to_chat(user_xeno, SPAN_WARNING("Something went terribly wrong here. Your new xeno is null! Tell a coder immediately!")) - if(new_xeno) - qdel(new_xeno) - return - - new_xeno.built_structures = target_xeno.built_structures.Copy() - target_xeno.built_structures = null - - if(target_xeno.mind) - target_xeno.mind.transfer_to(new_xeno) - else - new_xeno.key = target_xeno.key - if(new_xeno.client) - new_xeno.client.change_view(GLOB.world_view_size) - new_xeno.client.pixel_x = 0 - new_xeno.client.pixel_y = 0 - - //Regenerate the new mob's name now that our player is inside - new_xeno.generate_name() - if(new_xeno.client) - new_xeno.set_lighting_alpha(level_to_switch_to) - - // If the player has lost the Deevolve verb before, don't allow them to do it again - if(!(/mob/living/carbon/xenomorph/verb/Deevolve in target_xeno.verbs)) - remove_verb(new_xeno, /mob/living/carbon/xenomorph/verb/Deevolve) - - new_xeno.visible_message(SPAN_XENODANGER("A [new_xeno.caste.caste_type] emerges from the husk of \the [target_xeno]."), \ - SPAN_XENODANGER("[user_xeno] makes us regress into your previous form.")) - - if(user_xeno.hive.living_xeno_queen && user_xeno.hive.living_xeno_queen.observed_xeno == target_xeno) - user_xeno.hive.living_xeno_queen.overwatch(new_xeno) - - message_admins("[key_name_admin(user_xeno)] has deevolved [key_name_admin(target_xeno)]. Reason: [reason]") - log_admin("[key_name_admin(user_xeno)] has deevolved [key_name_admin(target_xeno)]. Reason: [reason]") - - target_xeno.transfer_observers_to(new_xeno) - - if(GLOB.round_statistics && !new_xeno.statistic_exempt) - GLOB.round_statistics.track_new_participant(target_xeno.faction, -1) //so an evolved xeno doesn't count as two. - SSround_recording.recorder.stop_tracking(target_xeno) - SSround_recording.recorder.track_player(new_xeno) - - qdel(target_xeno) return /datum/action/xeno_action/onclick/remove_eggsac/use_ability(atom/A) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 18f1f892ddfa..99f9e2db30cf 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -61,7 +61,6 @@ // Override with custom behaviour. return - /mob/living/carbon/xenomorph/verb/purchase_strain() set name = "Purchase Strain" set desc = "Purchase a strain for yourself" @@ -99,15 +98,49 @@ // If it applied successfully, add it to the logs. log_strain("[name] purchased strain '[strain_instance.type]'") +/mob/living/carbon/xenomorph/verb/reset_strain() + set name = "Reset Strain" + set desc = "Reset your strain" + set category = "Alien" + + // Firstly, make sure the xeno is actually able to take a strain. + if(!can_take_strain(reset = TRUE)) + return + + if(!COOLDOWN_FINISHED(src, next_strain_reset)) + to_chat(src, SPAN_WARNING("We lack the strength to reset our strain. We will be able to reset it in [round((next_strain_reset - world.time) / 600, 1)] minutes")) + return + + // Show the user the strain's description, and double check that they want it. + if(tgui_alert(src, "Are you sure?", "Reset Strain", list("Yes", "No")) != "Yes") + return + + // One more time after they confirm. + if(!can_take_strain(reset = TRUE)) + return + + var/mob/living/carbon/xenomorph/new_xeno = transmute(caste_type) + if(!new_xeno) + return + + new_xeno.xeno_jitter(1.5 SECONDS) + // If it applied successfully, add it to the logs. + log_strain("[new_xeno.name] reset their strain.") + COOLDOWN_START(new_xeno, next_strain_reset, 40 MINUTES) + /// Is this xeno currently able to take a strain? -/mob/living/carbon/xenomorph/proc/can_take_strain() +/mob/living/carbon/xenomorph/proc/can_take_strain(reset=FALSE) if(!length(caste.available_strains) || !check_state(TRUE)) return FALSE - if(strain) + if(strain && !reset) to_chat(src, SPAN_WARNING("We have already chosen a strain.")) return FALSE + if(!strain && reset) + to_chat(src, SPAN_WARNING("You must first pick a strain before resetting it.")) + return FALSE + if(is_ventcrawling) to_chat(src, SPAN_WARNING("This place is too constraining to take a strain.")) return FALSE