Files
Bubberstation/code/modules/events/heart_attack.dm
SkyratBot 0fe8982690 [MIRROR] Disease Outbreak/Heart Attack candidate lists clear themselves before generating [MDB IGNORE] (#19513)
* Disease Outbreak/Heart Attack candidate lists clear themselves before generating (#73596)

## About The Pull Request

When canSpawnEvent is run for the disease outbreak event, it would
generate_candidates() and add whoever was a valid infectee to a list.
Unfortunately, this list would not be cleared until the event was
actually run, meaning the candidate list could become malformed if the
event was cancelled, interrupted, or otherwise stopped before it could
properly start.

Additionally, this issue would arise if the admin setup process was
begun without actually running the event, or if two admins were
attempting to press buttons at the same time.

The list could contain duplicates, or players who were valid candidates
on the first candidacy check, but not at the present moment. The list
now clears itself every time it is generated, meaning that a fresh
candidate list is made every time one is needed.

Since the heart attack event uses the same candidate generating system
as the disease event, the change has been made there as well.

## Why It's Good For The Game

Closes #73552, hopefully? I can't imagine it's an issue with how the
candidates are selected, and am like 99% sure it's just the list getting
fudged somehow.

## Changelog
🆑
fix: The disease outbreak/heart attack event candidate list will now
clear itself before generating.
/🆑

* Disease Outbreak/Heart Attack candidate lists clear themselves before generating

---------

Co-authored-by: Rhials <Datguy33456@gmail.com>
2023-02-24 01:17:47 -08:00

97 lines
4.9 KiB
Plaintext

/datum/round_event_control/heart_attack
name = "Random Heart Attack"
typepath = /datum/round_event/heart_attack
weight = 20
max_occurrences = 2
min_players = 40 // To avoid shafting lowpop
category = EVENT_CATEGORY_HEALTH
description = "A random crewmember's heart gives out."
admin_setup = /datum/event_admin_setup/heart_attack
///Candidates for recieving a healthy dose of heart disease
var/list/heart_attack_candidates = list()
/datum/round_event_control/heart_attack/can_spawn_event(players_amt)
. = ..()
if(!.)
return .
generate_candidates() //generating candidates and checking in can_spawn_event prevents extreme edge case of there being the 40 minimum players, with all being ineligible for a heart attack, wasting the event
if(length(heart_attack_candidates))
return TRUE
/**
* Performs initial analysis of which living players are eligible to be selected for a heart attack.
*
* Traverses player_list and checks entries against a series of reviews to see if they should even be considered for a heart attack,
* and at what weight should they be eligible to recieve it. The check for whether or not a heart attack should be "blocked" by something is done
* later, at the round_event level, so this proc mostly just checks users for whether or not a heart attack should be possible.
*/
/datum/round_event_control/heart_attack/proc/generate_candidates()
heart_attack_candidates.Cut()
for(var/mob/living/carbon/human/candidate in shuffle(GLOB.player_list))
if(candidate.stat == DEAD || HAS_TRAIT(candidate, TRAIT_CRITICAL_CONDITION) || !candidate.can_heartattack() || (/datum/disease/heart_failure in candidate.diseases) || candidate.undergoing_cardiac_arrest())
continue
if(!(candidate.mind.assigned_role.job_flags & JOB_CREW_MEMBER))//only crewmembers can get one, a bit unfair for some ghost roles and it wastes the event
continue
if(candidate.satiety <= -60 && !candidate.has_status_effect(/datum/status_effect/exercised)) //Multiple junk food items recently //No foodmaxxing for the achievement
heart_attack_candidates[candidate] = 3
else
heart_attack_candidates[candidate] = 1
/datum/round_event/heart_attack
///A list of prime candidates for heart attacking
var/list/victims = list()
///Number of heart attacks to distribute
var/quantity = 1
/datum/round_event/heart_attack/start()
var/datum/round_event_control/heart_attack/heart_control = control
victims += heart_control.heart_attack_candidates
heart_control.heart_attack_candidates.Cut()
while(quantity > 0 && length(victims))
if(attack_heart())
quantity--
/**
* Picks a victim from a list and attempts to give them a heart attack
*
* Performs a pick_weight on a list of potential victims. Once selected, the "winner"
* will recieve heart disease. Returns TRUE if a heart attack is successfully given, and
* FALSE if something blocks it.
*/
/datum/round_event/heart_attack/proc/attack_heart()
var/mob/living/carbon/human/winner = pick_weight(victims)
if(winner.has_status_effect(/datum/status_effect/exercised)) //Stuff that should "block" a heart attack rather than just deny eligibility for one goes here.
winner.visible_message(span_warning("[winner] grunts and clutches their chest for a moment, catching their breath."), span_medal("Your chest lurches in pain for a brief moment, which quickly fades. \
You feel like you've just avoided a serious health disaster."), span_hear("You hear someone's breathing sharpen for a moment, followed by a sigh of relief."), 4)
winner.playsound_local(get_turf(winner), 'sound/health/slowbeat.ogg', 40, 0, channel = CHANNEL_HEARTBEAT, use_reverb = FALSE)
winner.Stun(3 SECONDS)
if(winner.client)
winner.client.give_award(/datum/award/achievement/misc/healthy, winner)
message_admins("[winner] has just survived a random heart attack!") //time to spawn them a trophy :)
victims -= winner
else
var/datum/disease/heart_disease = new /datum/disease/heart_failure()
winner.ForceContractDisease(heart_disease, FALSE, TRUE)
announce_to_ghosts(winner)
victims -= winner
return TRUE
return FALSE
/datum/event_admin_setup/heart_attack
///Number of candidates to be smote
var/quantity = 1
/datum/event_admin_setup/heart_attack/prompt_admins()
var/datum/round_event_control/heart_attack/heart_control = event_control
heart_control.generate_candidates() //can_spawn_event() is bypassed by admin_setup, so this makes sure that the candidates are still generated
if(!length(heart_control.heart_attack_candidates))
tgui_alert(usr, "There are no candidates eligible to recieve a heart attack!", "Error")
return ADMIN_CANCEL_EVENT
quantity = tgui_input_number(usr, "There are [length(heart_control.heart_attack_candidates)] crewmembers eligible for a heart attack. Please select how many people's days you wish to ruin.", "Shia Hato Atakku!", 1, length(heart_control.heart_attack_candidates))
/datum/event_admin_setup/heart_attack/apply_to_event(datum/round_event/heart_attack/event)
event.quantity = quantity