From c76df7f37ad3166867ccd4d6b69c48333e5a67d0 Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:47:09 -0500 Subject: [PATCH] Station Goals are now handled by SSstation instead of a global list (#81177) ## About The Pull Request You can now get station goals in a slightly better way over using a `locate() in` call on a global list. The Meteor Satellite goal no longer stores a giant list of ALL OBJECTS in view. And now correctly only counts turfs. ## Changelog :cl: fix: Meteor Satellites no longer erroneously count every piece of paper as a protected turf. fix: As a result the station goal is slightly more difficult /:cl: --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/__HELPERS/roundend.dm | 11 +++-- code/controllers/subsystem/dynamic/dynamic.dm | 12 +++--- .../subsystem/processing/station.dm | 43 ++++++++++++++++++- code/controllers/subsystem/ticker.dm | 1 - .../machinery/satellite/satellite_control.dm | 7 ++- code/modules/admin/topic.dm | 1 - code/modules/admin/verbs/debug.dm | 4 +- code/modules/station_goals/dna_vault.dm | 4 +- code/modules/station_goals/generate_goals.dm | 12 ------ code/modules/station_goals/meteor_shield.dm | 21 ++++++--- code/modules/station_goals/station_goal.dm | 20 +++++---- 11 files changed, 90 insertions(+), 46 deletions(-) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 93ba8bb2f1c..a3734cfd7a6 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -491,11 +491,14 @@ GLOBAL_LIST_INIT(achievements_unlocked, list()) return "" /datum/controller/subsystem/ticker/proc/goal_report() + var/list/goals = SSstation.get_station_goals() + if(!length(goals)) + return null + var/list/parts = list() - if(GLOB.station_goals.len) - for(var/datum/station_goal/goal as anything in GLOB.station_goals) - parts += goal.get_result() - return "
" + for(var/datum/station_goal/goal as anything in SSstation.get_station_goals()) + parts += goal.get_result() + return "
" ///Generate a report for how much money is on station, as well as the richest crewmember on the station. /datum/controller/subsystem/ticker/proc/market_report() diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm index 5024194412d..f7c37cb41e3 100644 --- a/code/controllers/subsystem/dynamic/dynamic.dm +++ b/code/controllers/subsystem/dynamic/dynamic.dm @@ -329,16 +329,16 @@ SUBSYSTEM_DEF(dynamic) if(ruleset.weight <= 0 || ruleset.cost <= 0) continue min_threat = min(ruleset.cost, min_threat) + var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat && shown_threat < min_threat) //if both shown and real threat are below any ruleset, its extended time + SSstation.generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget)) - generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget)) - - if (GLOB.station_goals.len > 0) - var/list/texts = list("
Special Orders for [station_name()]:
") - for(var/datum/station_goal/station_goal as anything in GLOB.station_goals) + var/list/datum/station_goal/goals = SSstation.get_station_goals() + if(length(goals)) + var/list/texts = list("
Special Orders for [station_name()]:
") + for(var/datum/station_goal/station_goal as anything in goals) station_goal.on_report() texts += station_goal.get_report() - . += texts.Join("
") var/list/trait_list_strings = list() diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index 99af6d867f1..34c4a00f81d 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -16,8 +16,10 @@ PROCESSING_SUBSYSTEM_DEF(station) ///A list of trait roles that should never be able to roll antag var/list/antag_restricted_roles = list() -/datum/controller/subsystem/processing/station/Initialize() + /// Assosciative list of station goal type -> goal instance + var/list/datum/station_goal/goals_by_type = list() +/datum/controller/subsystem/processing/station/Initialize() //If doing unit tests we don't do none of that trait shit ya know? // Autowiki also wants consistent outputs, for example making sure the vending machine page always reports the normal products #if !defined(UNIT_TESTS) && !defined(AUTOWIKI) @@ -30,6 +32,45 @@ PROCESSING_SUBSYSTEM_DEF(station) return SS_INIT_SUCCESS +/datum/controller/subsystem/processing/station/Recover() + station_traits = SSstation.station_traits + selectable_traits_by_types = SSstation.selectable_traits_by_types + announcer = SSstation.announcer + antag_protected_roles = SSstation.antag_protected_roles + antag_restricted_roles = SSstation.antag_restricted_roles + goals_by_type = SSstation.goals_by_type + ..() + +/// This gets called by SSdynamic during initial gamemode setup. +/// This is done because for a greenshift we want all goals to be generated +/datum/controller/subsystem/processing/station/proc/generate_station_goals(goal_budget) + var/list/possible = subtypesof(/datum/station_goal) + + var/goal_weights = 0 + var/chosen_goals = list() + var/is_planetary = SSmapping.is_planetary() + while(possible.len && goal_weights < goal_budget) + var/datum/station_goal/picked = pick_n_take(possible) + if(picked::requires_space && is_planetary) + continue + + goal_weights += initial(picked.weight) + chosen_goals += picked + + for(var/chosen in chosen_goals) + new chosen() + +/// Returns all station goals that are currently active +/datum/controller/subsystem/processing/station/proc/get_station_goals() + var/list/goals = list() + for(var/goal_type in goals_by_type) + goals += goals_by_type[goal_type] + return goals + +/// Returns a specific station goal by type +/datum/controller/subsystem/processing/station/proc/get_station_goal(goal_type) + return goals_by_type[goal_type] + ///Rolls for the amount of traits and adds them to the traits list /datum/controller/subsystem/processing/station/proc/SetupTraits() if (CONFIG_GET(flag/forbid_station_traits)) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 9d2fd01732e..e3d9be937e2 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -226,7 +226,6 @@ SUBSYSTEM_DEF(ticker) return TRUE return FALSE - /datum/controller/subsystem/ticker/proc/setup() to_chat(world, span_boldannounce("Starting game...")) var/init_start = world.timeofday diff --git a/code/game/machinery/satellite/satellite_control.dm b/code/game/machinery/satellite/satellite_control.dm index e8482fe91df..c0875d9e26a 100644 --- a/code/game/machinery/satellite/satellite_control.dm +++ b/code/game/machinery/satellite/satellite_control.dm @@ -44,10 +44,9 @@ )) data["notice"] = notice - - var/datum/station_goal/station_shield/goal = locate() in GLOB.station_goals - if(goal) - data["meteor_shield"] = 1 + var/datum/station_goal/station_shield/goal = SSstation.get_station_goal(/datum/station_goal/station_shield) + if(!isnull(goal)) + data["meteor_shield"] = TRUE data["meteor_shield_coverage"] = goal.get_coverage() data["meteor_shield_coverage_max"] = goal.coverage_goal return data diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 6196e2c94b6..9c826dc216c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1350,7 +1350,6 @@ return G.report_message = description message_admins("[key_name(usr)] created \"[G.name]\" station goal.") - GLOB.station_goals += G modify_goals() else if(href_list["change_lag_switch"]) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 260bfb16bf3..126d8756762 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -546,8 +546,8 @@ /datum/admins/proc/modify_goals() var/dat = "" - for(var/datum/station_goal/S in GLOB.station_goals) - dat += "[S.name] - Announce | Remove
" + for(var/datum/station_goal/goal as anything in SSstation.get_station_goals()) + dat += "[goal.name] - Announce | Remove
" dat += "
Add New Goal" usr << browse(dat, "window=goals;size=400x400") diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index 83fb1f0ea7f..5c146758d12 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -101,8 +101,8 @@ F.parent = src fillers += F - var/datum/station_goal/dna_vault/dna_vault_goal = locate() in GLOB.station_goals - if (!isnull(dna_vault_goal)) + var/datum/station_goal/dna_vault/dna_vault_goal = SSstation.get_station_goal(/datum/station_goal/dna_vault) + if(!isnull(dna_vault_goal)) animals_max = dna_vault_goal.animal_count plants_max = dna_vault_goal.plant_count dna_max = dna_vault_goal.human_count diff --git a/code/modules/station_goals/generate_goals.dm b/code/modules/station_goals/generate_goals.dm index 102212c1212..b37543d6de8 100644 --- a/code/modules/station_goals/generate_goals.dm +++ b/code/modules/station_goals/generate_goals.dm @@ -1,13 +1 @@ /// Creates the initial station goals. -/proc/generate_station_goals(goal_budget) - var/list/possible = subtypesof(/datum/station_goal) - // Remove all goals that require space if space is not present - if(SSmapping.is_planetary()) - for(var/datum/station_goal/goal as anything in possible) - if(initial(goal.requires_space)) - 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 diff --git a/code/modules/station_goals/meteor_shield.dm b/code/modules/station_goals/meteor_shield.dm index 3b87ef74578..84a61395a4b 100644 --- a/code/modules/station_goals/meteor_shield.dm +++ b/code/modules/station_goals/meteor_shield.dm @@ -14,8 +14,9 @@ // Satellites be actived to generate a shield that will block unorganic matter from passing it. /datum/station_goal/station_shield name = "Station Shield" - var/coverage_goal = 500 requires_space = TRUE + var/coverage_goal = 500 + VAR_PRIVATE/cached_coverage_length /datum/station_goal/station_shield/get_report() return list( @@ -37,17 +38,24 @@ /datum/station_goal/station_shield/check_completion() if(..()) return TRUE - if(get_coverage() >= coverage_goal) + update_coverage() + if(cached_coverage_length >= coverage_goal) return TRUE return FALSE -/datum/station_goal/proc/get_coverage() +/datum/station_goal/station_shield/proc/get_coverage() + return cached_coverage_length + +/// Gets the coverage of all active meteor shield satellites +/// Can be expensive, ensure you need this before calling it +/datum/station_goal/station_shield/proc/update_coverage() var/list/coverage = list() for(var/obj/machinery/satellite/meteor_shield/shield_satt as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/satellite/meteor_shield)) if(!shield_satt.active || !is_station_level(shield_satt.z)) continue - coverage |= view(shield_satt.kill_range, shield_satt) - return coverage.len + for(var/turf/covered in view(shield_satt.kill_range, shield_satt)) + coverage |= covered + cached_coverage_length = length(coverage) /obj/machinery/satellite/meteor_shield name = "\improper Meteor Shield Satellite" @@ -109,6 +117,9 @@ if(obj_flags & EMAGGED) update_emagged_meteor_sat(user) + var/datum/station_goal/station_shield/goal = SSstation.get_station_goal(/datum/station_goal/station_shield) + goal?.update_coverage() + /obj/machinery/satellite/meteor_shield/Destroy() . = ..() if(obj_flags & EMAGGED) diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm index 30ed0b78b6c..d7fd5e7f752 100644 --- a/code/modules/station_goals/station_goal.dm +++ b/code/modules/station_goals/station_goal.dm @@ -1,6 +1,3 @@ -/// List of available station goals for the crew to be working on -GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal) - /datum/station_goal var/name = "Generic Goal" var/weight = 1 //In case of multiple goals later. @@ -30,13 +27,8 @@ GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal) else return "
  • [name] : [span_redtext("Failed!")]
  • " -/datum/station_goal/Destroy() - GLOB.station_goals -= src - return ..() - /datum/station_goal/Topic(href, href_list) ..() - if(!check_rights(R_ADMIN) || !usr.client.holder.CheckAdminHref(href, href_list)) return @@ -45,3 +37,15 @@ GLOBAL_LIST_EMPTY_TYPED(station_goals, /datum/station_goal) send_report() else if(href_list["remove"]) qdel(src) + +/datum/station_goal/New() + if(type in SSstation.goals_by_type) + stack_trace("Creating a new station_goal of type [type] when one already exists in SSstation.goals_by_type this is not supported anywhere. I trust you tho") + else + SSstation.goals_by_type[type] = src + return ..() + +/datum/station_goal/Destroy(force) + if(SSstation.goals_by_type[type] == src) + SSstation.goals_by_type -= type + return ..()