diff --git a/code/__DEFINES/client_prefs.dm b/code/__DEFINES/client_prefs.dm index 440044424a53..b46140c68395 100644 --- a/code/__DEFINES/client_prefs.dm +++ b/code/__DEFINES/client_prefs.dm @@ -1,5 +1,6 @@ #define BE_ALIEN_AFTER_DEATH (1<<0) #define BE_AGENT (1<<1) +#define BE_KING (1<<2) /// Determines how abilities are activated, whether they're activated via middle click, shift click or right click. #define XENO_ABILITY_CLICK_MIDDLE 1 diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index cb13e55b264e..ad19b560babb 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -1,5 +1,5 @@ #define SAVEFILE_VERSION_MIN 8 -#define SAVEFILE_VERSION_MAX 29 +#define SAVEFILE_VERSION_MAX 30 //handles converting savefiles to new formats //MAKE SURE YOU KEEP THIS UP TO DATE! @@ -192,6 +192,12 @@ S["hair_style_name"] << hair_style + if(savefile_version < 30) + var/be_special = 0 + S["be_special"] >> be_special + be_special &= ~BE_KING + S["be_special"] << be_special + savefile_version = SAVEFILE_VERSION_MAX return 1 diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index b0df321ade11..99816cb6b524 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -210,6 +210,7 @@ var/list/be_special_flags = list( "Xenomorph after unrevivable death" = BE_ALIEN_AFTER_DEATH, "Agent" = BE_AGENT, + "Be King" = BE_KING, ) var/role = tgui_input_list(usr, "Toggle which candidacy?", "Select role", be_special_flags) if(!role) diff --git a/code/modules/cm_aliens/XenoStructures.dm b/code/modules/cm_aliens/XenoStructures.dm index c9a4a34499b9..130e5b155d26 100644 --- a/code/modules/cm_aliens/XenoStructures.dm +++ b/code/modules/cm_aliens/XenoStructures.dm @@ -884,12 +884,18 @@ var/hive_number = XENO_HIVE_NORMAL /// Whether the cocoon has hatched var/hatched = FALSE - /// Current running timer - var/timer /// Is currently rolling candidates var/rolling_candidates = FALSE /// Voting for King var/list/mob/living/carbon/xenomorph/votes = list() + /// Candidates + var/list/mob/living/carbon/xenomorph/candidates = list() + /// Time to hatch + var/time_to_hatch = 10 MINUTES + /// Announced that the hatchery was paused + var/announced_paused = FALSE + /// Stage of hatching + var/stage = 0 /obj/effect/alien/resin/king_cocoon/Destroy() if(!hatched) @@ -912,6 +918,7 @@ votes = null chosen_candidate = null + candidates = null . = ..() @@ -930,8 +937,7 @@ var/obj/effect/build_blocker/blocker = new(turf_to_block, src) blockers += blocker - timer = addtimer(CALLBACK(src, PROC_REF(start_growing)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) - addtimer(CALLBACK(src, PROC_REF(check_pylons)), 10 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME|TIMER_LOOP) + START_PROCESSING(SSobj, src) marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP DETECTED IN [uppertext(get_area_name(loc))].\n\nESTIMATED TIME UNTIL COMPLETION - 10 MINUTES.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') var/datum/hive_status/hive @@ -944,18 +950,51 @@ else xeno_announcement(SPAN_XENOANNOUNCE("Another hive's King is growing at [get_area_name(loc)]."), cur_hive_num, XENO_GENERAL_ANNOUNCE) -/// Callback for a repeating 10s timer to ensure both pylons are active (otherwise delete) and counts the number of marines groundside (would cause hatching to expedite). -/obj/effect/alien/resin/king_cocoon/proc/check_pylons() + +#define STAGE_GROWING 1 +#define STAGE_HALFWAY 2 +#define STAGE_VOTE 3 +#define STAGE_PICK 4 +#define STAGE_BEFORE_HATCH 5 +#define STAGE_HATCH 6 + +/obj/effect/alien/resin/king_cocoon/process(delta_time) var/datum/hive_status/hive = GLOB.hive_datum[hive_number] if(length(hive.active_endgame_pylons) < 2) - qdel(src) + if(!announced_paused) + marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP IN [uppertext(get_area_name(loc))] HAS BEEN PAUSED.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') + for(var/cur_hive_num in GLOB.hive_datum) + hive = GLOB.hive_datum[cur_hive_num] + if(!length(hive.totalXenos)) + continue + if(cur_hive_num == hive_number) + xeno_announcement(SPAN_XENOANNOUNCE("One of our pylons was destroyed, the hatchery has paused its progress!"), cur_hive_num, XENO_GENERAL_ANNOUNCE) + else + xeno_announcement(SPAN_XENOANNOUNCE("One of another hive's pylons was destroyed, the hatchery has paused its progress!"), cur_hive_num, XENO_GENERAL_ANNOUNCE) + + announced_paused = TRUE + icon_state = "static" return - - if(chosen_candidate || rolling_candidates) - return - + else if (length(hive.active_endgame_pylons) >= 2 && announced_paused) + for(var/cur_hive_num in GLOB.hive_datum) + hive = GLOB.hive_datum[cur_hive_num] + if(!length(hive.totalXenos)) + continue + if(cur_hive_num == hive_number) + xeno_announcement(SPAN_XENOANNOUNCE("The hatchery's progress has resumed!"), cur_hive_num, XENO_GENERAL_ANNOUNCE) + else + xeno_announcement(SPAN_XENOANNOUNCE("Another hive's hatchery progress has resumed!"), cur_hive_num, XENO_GENERAL_ANNOUNCE) + marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP IN [uppertext(get_area_name(loc))] HAS BEEN RESUMED.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') + announced_paused = FALSE + icon_state = "growing" + + for(var/obj/effect/alien/resin/special/pylon/pylon as anything in hive.active_endgame_pylons) + pylon.protection_level = TURF_PROTECTION_OB + pylon.update_icon() + if(hatched) + STOP_PROCESSING(SSobj, src) return var/groundside_humans = 0 @@ -968,21 +1007,46 @@ groundside_humans += 1 if(groundside_humans > 12) - return + break + + if(groundside_humans < 12) + // Too few marines are now groundside, hatch immediately + start_vote() + addtimer(CALLBACK(src, PROC_REF(roll_candidates)), 20 SECONDS) + addtimer(CALLBACK(src, PROC_REF(start_hatching), TRUE), 25 SECONDS) + STOP_PROCESSING(SSobj, src) + return - // Too few marines are now groundside, hatch immediately - deltimer(timer) - start_vote(expedite = TRUE) + time_to_hatch -= delta_time SECONDS + + if(!stage && time_to_hatch < 10 MINUTES) + icon_state = "growing" + stage = STAGE_GROWING + else if (stage == STAGE_GROWING && time_to_hatch <= 5 MINUTES) + announce_halfway() + stage = STAGE_HALFWAY + else if (stage == STAGE_HALFWAY && time_to_hatch <= 1 MINUTES) + start_vote() + stage = STAGE_VOTE + else if (stage == STAGE_VOTE && time_to_hatch <= 40 SECONDS) + roll_candidates() + stage = STAGE_PICK + else if (stage == STAGE_PICK && time_to_hatch <= 20 SECONDS) + start_hatching() + stage = STAGE_BEFORE_HATCH + else if (stage == STAGE_BEFORE_HATCH && time_to_hatch <= 0) + animate_hatch_king() + STOP_PROCESSING(SSobj, src) -/// Causes the cocoon to change visually for growing and initiates the next timer. -/obj/effect/alien/resin/king_cocoon/proc/start_growing() - icon_state = "growing" - timer = addtimer(CALLBACK(src, PROC_REF(announce_halfway)), 5 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) +#undef STAGE_GROWING +#undef STAGE_HALFWAY +#undef STAGE_VOTE +#undef STAGE_PICK +#undef STAGE_BEFORE_HATCH +#undef STAGE_HATCH /// Causes the halfway announcements and initiates the next timer. /obj/effect/alien/resin/king_cocoon/proc/announce_halfway() - timer = addtimer(CALLBACK(src, PROC_REF(start_vote)), 4 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) - marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP DETECTED IN [uppertext(get_area_name(loc))].\n\nESTIMATED TIME UNTIL COMPLETION - 5 MINUTES.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') var/datum/hive_status/hive for(var/cur_hive_num in GLOB.hive_datum) @@ -1032,7 +1096,10 @@ if(!is_candidate_valid(hive, candidate, playtime_restricted)) return FALSE - return tgui_alert(candidate, "Would you like to become the King?", "Choice", list("Yes", "No"), 10 SECONDS) == "Yes" + if(!candidate.client) + return FALSE + + return candidate.client.prefs.be_special & BE_KING #undef KING_PLAYTIME_HOURS @@ -1052,7 +1119,7 @@ votes[choice] = 1 /// Initiates a vote that will end in 20 seconds to vote for the King. Hatching will then begin in 1 minute unless expedited. -/obj/effect/alien/resin/king_cocoon/proc/start_vote(expedite = FALSE) +/obj/effect/alien/resin/king_cocoon/proc/start_vote() rolling_candidates = TRUE var/datum/hive_status/hive = GLOB.hive_datum[hive_number] @@ -1066,7 +1133,8 @@ if(is_candidate_valid(hive, candidate, playtime_restricted = FALSE, skip_playtime = FALSE)) INVOKE_ASYNC(src, PROC_REF(cast_vote), candidate, voting_candidates) - addtimer(CALLBACK(src, PROC_REF(roll_candidates), voting_candidates, expedite), 20 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) + candidates = voting_candidates + /** * Finalizes the vote for King opting to use a series of fallbacks in case a candidate declines. @@ -1077,12 +1145,8 @@ * Then all other living xenos not meeting the playtime requirement are asked. * Then all other xeno observer candidates not meeting the playtime requirement are asked. * Then finally if after all that, the search is given up and will ultimately result in a freed King mob. - * - * Arguments: - * * voting_candidates: A list of xenomorphs that are valid candidates to vote on. - * * expedite: Whether hatching should begin in a minute or immediately after a candidate is found. */ -/obj/effect/alien/resin/king_cocoon/proc/roll_candidates(list/mob/living/carbon/xenomorph/voting_candidates, expedite = FALSE) +/obj/effect/alien/resin/king_cocoon/proc/roll_candidates() var/datum/hive_status/hive = GLOB.hive_datum[hive_number] var/primary_votes = 0 @@ -1103,27 +1167,25 @@ if(prob(50) && try_roll_candidate(hive, primary_candidate, playtime_restricted = TRUE)) chosen_candidate = primary_candidate.client rolling_candidates = FALSE - start_hatching(expedite) return - voting_candidates -= primary_candidate + candidates -= primary_candidate if(try_roll_candidate(hive, secondary_candidate, playtime_restricted = TRUE)) chosen_candidate = secondary_candidate.client rolling_candidates = FALSE - start_hatching(expedite) return - voting_candidates -= secondary_candidate + candidates -= secondary_candidate // Otherwise ask all the living xenos (minus the player(s) who got voted on earlier) - for(var/mob/living/carbon/xenomorph/candidate in shuffle(voting_candidates)) + for(var/mob/living/carbon/xenomorph/candidate in shuffle(candidates)) if(try_roll_candidate(hive, candidate, playtime_restricted = TRUE)) chosen_candidate = candidate.client rolling_candidates = FALSE - start_hatching(expedite) return + // Then observers var/list/observer_list_copy = shuffle(get_alien_candidates(hive)) @@ -1131,42 +1193,41 @@ if(try_roll_candidate(hive, candidate, playtime_restricted = TRUE)) chosen_candidate = candidate.client rolling_candidates = FALSE - start_hatching(expedite) return + // Lastly all of the above again, without playtime requirements for(var/mob/living/carbon/xenomorph/candidate in shuffle(hive.totalXenos.Copy() - hive.living_xeno_queen)) if(try_roll_candidate(hive, candidate, playtime_restricted = FALSE)) chosen_candidate = candidate.client rolling_candidates = FALSE - start_hatching(expedite) return + for(var/mob/candidate in observer_list_copy) if(try_roll_candidate(hive, candidate, playtime_restricted = FALSE)) chosen_candidate = candidate.client rolling_candidates = FALSE - start_hatching(expedite) return message_admins("Failed to find a client for the King, releasing as freed mob.") - start_hatching(expedite) + -/// Starts the hatching in one minute, otherwise immediately if expedited +/// Starts the hatching in twenty seconds, otherwise immediately if expedited /obj/effect/alien/resin/king_cocoon/proc/start_hatching(expedite = FALSE) + votes = null + candidates = null if(expedite) animate_hatch_king() return - marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP DETECTED IN [get_area_name(loc)].\n\nESTIMATED TIME UNTIL COMPLETION - ONE MINUTE.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') + marine_announcement("ALERT.\n\nUNUSUAL ENERGY BUILDUP DETECTED IN [get_area_name(loc)].\n\nESTIMATED TIME UNTIL COMPLETION - 20 SECONDS.", "[MAIN_AI_SYSTEM] Biological Scanner", 'sound/misc/notice1.ogg') var/datum/hive_status/hive for(var/cur_hive_num in GLOB.hive_datum) hive = GLOB.hive_datum[cur_hive_num] if(!length(hive.totalXenos)) continue if(cur_hive_num == hive_number) - xeno_announcement(SPAN_XENOANNOUNCE("The King will hatch in approximately one minute."), cur_hive_num, XENO_GENERAL_ANNOUNCE) + xeno_announcement(SPAN_XENOANNOUNCE("The King will hatch in approximately twenty seconds."), cur_hive_num, XENO_GENERAL_ANNOUNCE) else - xeno_announcement(SPAN_XENOANNOUNCE("Another hive's King will hatch in approximately one minute."), cur_hive_num, XENO_GENERAL_ANNOUNCE) - - timer = addtimer(CALLBACK(src, PROC_REF(animate_hatch_king)), 1 MINUTES, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME) + xeno_announcement(SPAN_XENOANNOUNCE("Another hive's King will hatch in approximately twenty seconds."), cur_hive_num, XENO_GENERAL_ANNOUNCE) /// Causes the cocoon to change visually for hatching and initiates the next timer. /obj/effect/alien/resin/king_cocoon/proc/animate_hatch_king() diff --git a/code/modules/cm_aliens/hivebuffs/hivebuff.dm b/code/modules/cm_aliens/hivebuffs/hivebuff.dm index 2b140771e946..00c7d193d47b 100644 --- a/code/modules/cm_aliens/hivebuffs/hivebuff.dm +++ b/code/modules/cm_aliens/hivebuffs/hivebuff.dm @@ -102,7 +102,7 @@ if(!_check_num_required_pylons()) to_chat(purchasing_mob, SPAN_XENONOTICE("Our hive does not have the required number of available pylons! We require [number_of_required_pylons]")) return FALSE - + if(!_check_danger()) to_chat(purchasing_mob, SPAN_XENONOTICE("There is not enough danger to warrant hive buffs.")) return FALSE @@ -394,7 +394,7 @@ /datum/hivebuff/game_ender_caste name = "His Grace" - desc = "A huge behemoth of a Xenomorph which can tear its way through defences and flesh alike. Requires open space to grow." + desc = "A huge behemoth of a Xenomorph which can tear its way through defences and flesh alike. Requires open space around the hive core to spawn." tier = HIVEBUFF_TIER_MAJOR radial_icon = "king" @@ -403,7 +403,6 @@ special_fail_message = "Only one hatchery may exist at a time." cooldown_duration = 15 MINUTES // This buff ceases instantly so we need to incorporation the spawning time too number_of_required_pylons = 2 - must_select_pylon = TRUE /datum/hivebuff/game_ender_caste/New() roundtime_to_enable = GLOB.king_acquisition_time @@ -415,11 +414,15 @@ special_fail_message = "Only one King may exist at a time." return FALSE + if(!hive.hive_location) + special_fail_message = "You must first construct a hive core." + return FALSE + return !hive.has_hatchery /datum/hivebuff/game_ender_caste/on_engage(obj/effect/alien/resin/special/pylon/purchased_pylon) var/turf/spawn_turf - for(var/turf/potential_turf in orange(5, purchased_pylon)) + for(var/turf/potential_turf in orange(5, hive.hive_location)) var/failed = FALSE for(var/x_offset in -1 to 1) for(var/y_offset in -1 to 1) @@ -437,6 +440,9 @@ for(var/obj/structure/struct in turf_to_check) if(struct.density) failed = TRUE + break + for(var/obj/effect/alien/resin/special in turf_to_check) + failed = TRUE break if(!failed) spawn_turf = potential_turf @@ -454,42 +460,71 @@ return TRUE -/datum/hivebuff/defence - name = "Boon of Defence" - desc = "Increases all xenomorph armour by 2.5 for 5 minutes" +/datum/hivebuff/fire + name = "Boon of Fire Resistance" + desc = "Makes all xenomorphs immune to fire for 5 minutes." tier = HIVEBUFF_TIER_MINOR - engage_flavourmessage = "The Queen has imbued us with greater chitin." + engage_flavourmessage = "The Queen has imbued us with flame-resistant chitin." duration = 5 MINUTES number_of_required_pylons = 1 radial_icon = "shield" -/datum/hivebuff/defence/apply_buff_effects(mob/living/carbon/xenomorph/xeno) - xeno.armor_modifier += XENO_ARMOR_MOD_TINY - xeno.recalculate_armor() +/datum/hivebuff/fire/apply_buff_effects(mob/living/carbon/xenomorph/xeno) + if(!xeno.caste) + return -/datum/hivebuff/defence/remove_buff_effects(mob/living/carbon/xenomorph/xeno) - xeno.armor_modifier -= XENO_ARMOR_MOD_TINY - xeno.recalculate_armor() + if(!(xeno.caste.fire_immunity & FIRE_IMMUNITY_NO_IGNITE)) + RegisterSignal(xeno, COMSIG_LIVING_PREIGNITION, PROC_REF(fire_immune)) -/datum/hivebuff/defence/major - name = "Major Boon of Defence" - desc = "Increases all xenomorph armour by 5 for 10 minutes" + if(xeno.caste.fire_immunity == FIRE_IMMUNITY_NONE) + RegisterSignal(xeno, list(COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED), PROC_REF(flamer_crossed_immune)) + + +/datum/hivebuff/fire/remove_buff_effects(mob/living/carbon/xenomorph/xeno) + if(!(xeno.caste.fire_immunity & FIRE_IMMUNITY_NO_IGNITE)) + UnregisterSignal(xeno, COMSIG_LIVING_PREIGNITION) + if(xeno.caste.fire_immunity == FIRE_IMMUNITY_NONE) + UnregisterSignal(xeno, list( + COMSIG_LIVING_FLAMER_CROSSED, + COMSIG_LIVING_FLAMER_FLAMED + )) + +/datum/hivebuff/fire/proc/flamer_crossed_immune(mob/living/living, datum/reagent/reagent) + SIGNAL_HANDLER + + if(reagent.fire_penetrating) + return + + . |= COMPONENT_NO_IGNITE + + +/datum/hivebuff/fire/proc/fire_immune(mob/living/living) + SIGNAL_HANDLER + + if(living.fire_reagent?.fire_penetrating && !HAS_TRAIT(living, TRAIT_ABILITY_BURROWED)) + return + + return COMPONENT_CANCEL_IGNITION + +/datum/hivebuff/adaptability + name = "Boon of Adaptability" + desc = "Allows each xenomorph to change to a different caste of the same tier." tier = HIVEBUFF_TIER_MAJOR - engage_flavourmessage = "The Queen has imbued us with even greater chitin." - duration = 10 MINUTES + engage_flavourmessage = "The Queen has blessed us with adaptability." + duration = 0 cost = 2 number_of_required_pylons = 2 radial_icon = "shield_m" -/datum/hivebuff/defence/major/apply_buff_effects(mob/living/carbon/xenomorph/xeno) - xeno.armor_modifier += XENO_ARMOR_MOD_VERY_SMALL - xeno.recalculate_armor() +/datum/hivebuff/adaptability/apply_buff_effects(mob/living/carbon/xenomorph/xeno) + if(xeno.caste.tier > 3) + return -/datum/hivebuff/defence/major/remove_buff_effects(mob/living/carbon/xenomorph/xeno) - xeno.armor_modifier -= XENO_ARMOR_MOD_VERY_SMALL - xeno.recalculate_armor() + add_verb(xeno, /mob/living/carbon/xenomorph/proc/transmute_verb) + var/datum/action/xeno_action/onclick/transmute/transmute_action = new() + transmute_action.give_to(xeno) /datum/hivebuff/attack name = "Boon of Aggression" diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 9c847c2bf874..04ba89f0d920 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -268,6 +268,49 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) return TRUE +/mob/living/carbon/xenomorph/proc/transmute_verb() + set name = "Transmute" + set desc = "Transmute into a different caste of the same tier" + set category = "Alien" + + if(!check_state()) + return + if(is_ventcrawling) + to_chat(src, SPAN_XENOWARNING("We can't transmute here.")) + return + if(!isturf(loc)) + to_chat(src, SPAN_XENOWARNING("We can't transmute here.")) + return + if(health < maxHealth) + to_chat(src, SPAN_XENOWARNING("We are too weak to transmute, we must regain our health first.")) + return + if(tier == 0 || tier == 4) + to_chat(src, SPAN_XENOWARNING("We can't transmute.")) + return + if(lock_evolve) + if(banished) + to_chat(src, SPAN_WARNING("We are banished and cannot reach the hivemind.")) + else + to_chat(src, SPAN_WARNING("We can't transmute.")) + return FALSE + + var/newcaste + var/list/options = list() + + if(tier == 1) + options = XENO_T1_CASTES + else if (tier == 2) + options = XENO_T2_CASTES + else if (tier == 3) + options = XENO_T3_CASTES + + newcaste = tgui_input_list(src, "Choose a caste you want to transmute to.", "Transmute", options, theme="hive_status") + + if(!newcaste) + return + + transmute(newcaste, "We transmute into a new form.") + // The queen de-evo, but on yourself. /mob/living/carbon/xenomorph/verb/Deevolve() set name = "De-Evolve" @@ -351,7 +394,7 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) if(new_xeno.ckey) GLOB.deevolved_ckeys += new_xeno.ckey -/mob/living/carbon/xenomorph/proc/transmute(newcaste) +/mob/living/carbon/xenomorph/proc/transmute(newcaste, message="We regress into our previous form.") // 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)) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index 0746b614c140..875af41eeb82 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -500,6 +500,25 @@ if(xeno && !xeno.is_mob_incapacitated() || !xeno.buckled || !xeno.evolving && xeno.plasma_stored >= plasma_cost) return TRUE +/datum/action/xeno_action/onclick/transmute + name = "Transmute" + action_icon_state = "transmute" + action_type = XENO_ACTION_CLICK + +/datum/action/xeno_action/onclick/transmute/action_activate() + . = ..() + var/mob/living/carbon/xenomorph/xeno = owner + xeno.transmute_verb() + +/datum/action/xeno_action/onclick/transmute/can_use_action() + if(!owner) + return FALSE + var/mob/living/carbon/xenomorph/xeno = owner + // Perform check_state(TRUE) silently: + if(xeno && !xeno.is_mob_incapacitated() || !xeno.buckled || !xeno.evolving && xeno.plasma_stored >= plasma_cost) + return TRUE + + /datum/action/xeno_action/onclick/tacmap name = "View Tactical Map" action_icon_state = "toggle_queen_zoom" diff --git a/icons/mob/hud/actions_xeno.dmi b/icons/mob/hud/actions_xeno.dmi index 578909103c1a..b98194a9cab1 100644 Binary files a/icons/mob/hud/actions_xeno.dmi and b/icons/mob/hud/actions_xeno.dmi differ