Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xenomorph Endgame changes #8026

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/__DEFINES/client_prefs.dm
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 7 additions & 1 deletion code/modules/client/preferences_savefile.dm
Original file line number Diff line number Diff line change
@@ -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!
Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions code/modules/client/preferences_toggles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Git-Nivrak marked this conversation as resolved.
Show resolved Hide resolved
)
var/role = tgui_input_list(usr, "Toggle which candidacy?", "Select role", be_special_flags)
if(!role)
Expand Down
151 changes: 106 additions & 45 deletions code/modules/cm_aliens/XenoStructures.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -912,6 +918,7 @@

votes = null
chosen_candidate = null
candidates = null
Git-Nivrak marked this conversation as resolved.
Show resolved Hide resolved

. = ..()

Expand All @@ -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
Expand All @@ -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
Git-Nivrak marked this conversation as resolved.
Show resolved Hide resolved

/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
Expand All @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -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]

Expand All @@ -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
Git-Nivrak marked this conversation as resolved.
Show resolved Hide resolved


/**
* Finalizes the vote for King opting to use a series of fallbacks in case a candidate declines.
Expand All @@ -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
Expand All @@ -1103,70 +1167,67 @@
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))

for(var/mob/candidate in observer_list_copy)
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()
Expand Down
Loading