Files
Bubberstation/code/game/gamemodes/game_mode.dm
MrMelbert 298b5d3719 Doubles the time you can get the "Long shift" achievement, makes it not grant on admin restarts (#77195)
## About The Pull Request

- "Long shift" can now be earned from sub 10 minute rounds rather than
sub 5 minute rounds

- Admin restarts no longer give out "Long shift"

## Why It's Good For The Game

I do not think this achievement can *possibly* be earned right now. Like
at all.

Nuke Ops and cult are the only antags that can possibly do it and it's
incredibly infeasible (requiring that they nuke the station or summon
Nar'sie in just 3 minutes!)

So I bumped up the timer to 10 minutes. This means that ops can get it
if they nuke the station in 8 minutes, cult can get it if they REALLY
speedrun, and revs can get it if they beeline the heads.

I checked the DB for stats on this achievement and it's only been earned
in 3 rounds across the last year - `208780` (admin restart due to a bug)
`192892` (admin restart due to a bug?) `186192` (admin restart).

So I also prevented admin forcing the round to end. (I don't know if it
catches admin reboots directly I'll have to check that.)

## Changelog

🆑 Melbert
balance: The "Long Shift" achievement is now feasibly obtainable, and
admins can no longer trigger it unknowingly
/🆑
2023-07-29 13:00:16 -06:00

229 lines
9.0 KiB
Plaintext

/*
* GAMEMODES (by Rastaf0)
*
* In the new mode system all special roles are fully supported.
* You can have proper wizards/traitors/changelings/cultists during any mode.
* Only two things really depends on gamemode:
* 1. Starting roles, equipment and preparations
* 2. Conditions of finishing the round.
*
*/
/datum/game_mode
///Attempts to select players for special roles the mode might have.
/datum/game_mode/proc/pre_setup()
return TRUE
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
report = !CONFIG_GET(flag/no_intercept_report)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME)
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles))
var/delay = CONFIG_GET(number/reopen_roundstart_suicide_roles_delay)
if(delay)
delay = (delay SECONDS)
else
delay = (4 MINUTES) //default to 4 minutes if the delay isn't defined.
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reopen_roundstart_suicide_roles)), delay)
if(SSdbcore.Connect())
var/list/to_set = list()
var/arguments = list()
if(SSticker.mode)
to_set += "game_mode = :game_mode"
arguments["game_mode"] = SSticker.mode
if(GLOB.revdata.originmastercommit)
to_set += "commit_hash = :commit_hash"
arguments["commit_hash"] = GLOB.revdata.originmastercommit
if(to_set.len)
arguments["round_id"] = GLOB.round_id
var/datum/db_query/query_round_game_mode = SSdbcore.NewQuery(
"UPDATE [format_table_name("round")] SET [to_set.Join(", ")] WHERE id = :round_id",
arguments
)
query_round_game_mode.Execute()
qdel(query_round_game_mode)
return TRUE
///Handles late-join antag assignments
/datum/game_mode/proc/make_antag_chance(mob/living/carbon/human/character)
return
/// Checks if the round should be ending, called every ticker tick
/datum/game_mode/proc/check_finished()
if(!SSticker.setup_done)
return FALSE
if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
return TRUE
if(GLOB.station_was_nuked)
return TRUE
if(GLOB.revolutionary_win)
return TRUE
return FALSE
/*
* Generate a list of station goals available to purchase to report to the crew.
*
* Returns a formatted string all station goals that are available to the station.
*/
/datum/game_mode/proc/generate_station_goal_report()
if(!GLOB.station_goals.len)
return
. = "<hr><b>Special Orders for [station_name()]:</b><BR>"
var/list/goal_reports = list()
for(var/datum/station_goal/station_goal as anything in GLOB.station_goals)
station_goal.on_report()
goal_reports += station_goal.get_report()
. += goal_reports.Join("<hr>")
return
/*
* Generate a list of active station traits to report to the crew.
*
* Returns a formatted string of all station traits (that are shown) affecting the station.
*/
/datum/game_mode/proc/generate_station_trait_report()
var/trait_list_string = ""
for(var/datum/station_trait/station_trait as anything in SSstation.station_traits)
if(!station_trait.show_in_report)
continue
trait_list_string += "[station_trait.get_report()]<BR>"
if(trait_list_string != "")
return "<hr><b>Identified shift divergencies:</b><BR>" + trait_list_string
return
/datum/game_mode/proc/generate_report_footnote()
var/footnote_pile = ""
for(var/datum/command_footnote/footnote in SScommunications.command_report_footnotes)
footnote_pile += "[footnote.message]<BR>"
footnote_pile += "<i>[footnote.signature]</i><BR>"
footnote_pile += "<BR>"
return "<hr><b>Additional Notes: </b><BR><BR>" + footnote_pile
/proc/reopen_roundstart_suicide_roles()
var/include_command = CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_positions)
var/list/reopened_jobs = list()
for(var/mob/living/quitter in GLOB.suicided_mob_list)
var/datum/job/job = SSjob.GetJob(quitter.job)
if(!job || !(job.job_flags & JOB_REOPEN_ON_ROUNDSTART_LOSS))
continue
if(!include_command && job.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
continue
job.current_positions = max(job.current_positions - 1, 0)
reopened_jobs += quitter.job
if(CONFIG_GET(flag/reopen_roundstart_suicide_roles_command_report))
if(reopened_jobs.len)
var/reopened_job_report_positions
for(var/dead_dudes_job in reopened_jobs)
reopened_job_report_positions = "[reopened_job_report_positions ? "[reopened_job_report_positions]\n":""][dead_dudes_job]"
var/suicide_command_report = "<font size = 3><b>Central Command Human Resources Board</b><br>\
Notice of Personnel Change</font><hr>\
To personnel management staff aboard [station_name()]:<br><br>\
Our medical staff have detected a series of anomalies in the vital sensors \
of some of the staff aboard your station.<br><br>\
Further investigation into the situation on our end resulted in us discovering \
a series of rather... unforturnate decisions that were made on the part of said staff.<br><br>\
As such, we have taken the liberty to automatically reopen employment opportunities for the positions of the crew members \
who have decided not to partake in our research. We will be forwarding their cases to our employment review board \
to determine their eligibility for continued service with the company (and of course the \
continued storage of cloning records within the central medical backup server.)<br><br>\
<i>The following positions have been reopened on our behalf:<br><br>\
[reopened_job_report_positions]</i>"
print_command_report(suicide_command_report, "Central Command Personnel Update")
//////////////////////////
//Reports player logouts//
//////////////////////////
/proc/display_roundstart_logout_report()
var/list/msg = list("[span_boldnotice("Roundstart logout report")]\n\n")
for(var/i in GLOB.mob_living_list)
var/mob/living/L = i
var/mob/living/carbon/C = L
if (istype(C) && !C.last_mind)
continue // never had a client
if(L.ckey && !GLOB.directory[L.ckey])
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Disconnected</b></font>)\n"
if(L.ckey && L.client)
var/failed = FALSE
if(L.client.inactivity >= ROUNDSTART_LOGOUT_AFK_THRESHOLD) //Connected, but inactive (alt+tabbed or something)
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (<font color='#ffcc00'><b>Connected, Inactive</b></font>)\n"
failed = TRUE //AFK client
if(!failed && L.stat)
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
msg += "<b>[L.name]</b> ([L.key]), the [L.job] ([span_boldannounce("Suicide")])\n"
failed = TRUE //Disconnected client
if(!failed && (L.stat == UNCONSCIOUS || L.stat == HARD_CRIT))
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dying)\n"
failed = TRUE //Unconscious
if(!failed && L.stat == DEAD)
msg += "<b>[L.name]</b> ([L.key]), the [L.job] (Dead)\n"
failed = TRUE //Dead
continue //Happy connected client
for(var/mob/dead/observer/D in GLOB.dead_mob_list)
if(D.mind && D.mind.current == L)
if(L.stat == DEAD)
if(HAS_TRAIT(L, TRAIT_SUICIDED)) //Suicider
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Suicide")])\n"
continue //Disconnected client
else
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] (Dead)\n"
continue //Dead mob, ghost abandoned
else
if(D.can_reenter_corpse)
continue //Adminghost, or cult/wizard ghost
else
msg += "<b>[L.name]</b> ([ckey(D.mind.key)]), the [L.job] ([span_boldannounce("Ghosted")])\n"
continue //Ghosted while alive
var/concatenated_message = msg.Join()
log_admin(concatenated_message)
to_chat(GLOB.admins, concatenated_message)
/datum/game_mode/proc/generate_station_goals(greenshift)
var/goal_budget = greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget)
var/list/possible = subtypesof(/datum/station_goal)
if(SSmapping.is_planetary())
for(var/datum/station_goal/goal in possible)
if(goal.requires_space)
///Removes all goals that require space if space is not present
possible -= goal
var/goal_weights = 0
while(possible.len && goal_weights < goal_budget)
var/datum/station_goal/picked = pick_n_take(possible)
goal_weights += initial(picked.weight)
GLOB.station_goals += new picked
//Set result and news report here
/datum/game_mode/proc/set_round_result()
SSticker.mode_result = "undefined"
// Something nuked the station - it wasn't nuke ops (they set their own via their rulset)
if(GLOB.station_was_nuked)
SSticker.news_report = STATION_NUKED
if(SSsupermatter_cascade.cascade_initiated)
SSticker.news_report = SUPERMATTER_CASCADE
// Only show this one if we have nothing better to show
if(EMERGENCY_ESCAPED_OR_ENDGAMED && !SSticker.news_report)
SSticker.news_report = SSshuttle.emergency?.is_hijacked() ? SHUTTLE_HIJACK : STATION_EVACUATED
/// Mode specific admin panel.
/datum/game_mode/proc/admin_panel()
return