Files
Bubberstation/code/controllers/subsystem/processing/station.dm

187 lines
7.8 KiB
Plaintext

PROCESSING_SUBSYSTEM_DEF(station)
name = "Station"
init_order = INIT_ORDER_STATION
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME
wait = 5 SECONDS
///A list of currently active station traits
var/list/station_traits = list()
///Assoc list of trait type || assoc list of traits with weighted value. Used for picking traits from a specific category.
var/list/selectable_traits_by_types = list(STATION_TRAIT_POSITIVE = list(), STATION_TRAIT_NEUTRAL = list(), STATION_TRAIT_NEGATIVE = list())
///Currently active announcer. Starts as a type but gets initialized after traits are selected
var/datum/centcom_announcer/announcer = /datum/centcom_announcer/default
///A list of trait roles that should be protected from antag
var/list/antag_protected_roles = list()
///A list of trait roles that should never be able to roll antag
var/list/antag_restricted_roles = list()
/// 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)
SetupTraits()
//display_lobby_traits() SKYRAT EDIT REMOVAL
#endif
announcer = new announcer() //Initialize the station's announcer datum
SSparallax.post_station_setup() //Apply station effects that parallax might have
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))
return
if (fexists(FUTURE_STATION_TRAITS_FILE))
var/forced_traits_contents = file2text(FUTURE_STATION_TRAITS_FILE)
fdel(FUTURE_STATION_TRAITS_FILE)
var/list/forced_traits_text_paths = json_decode(forced_traits_contents)
forced_traits_text_paths = SANITIZE_LIST(forced_traits_text_paths)
for (var/trait_text_path in forced_traits_text_paths)
var/station_trait_path = text2path(trait_text_path)
if (!ispath(station_trait_path, /datum/station_trait) || station_trait_path == /datum/station_trait)
var/message = "Invalid station trait path [station_trait_path] was requested in the future station traits!"
log_game(message)
message_admins(message)
continue
setup_trait(station_trait_path)
return
for(var/datum/station_trait/trait_typepath as anything in subtypesof(/datum/station_trait))
// If forced, (probably debugging), just set it up now, keep it out of the pool.
if(initial(trait_typepath.force))
setup_trait(trait_typepath)
continue
if(initial(trait_typepath.abstract_type) == trait_typepath)
continue //Dont add abstract ones to it
if(!(initial(trait_typepath.trait_flags) & STATION_TRAIT_PLANETARY) && SSmapping.is_planetary()) // we're on a planet but we can't do planet ;_;
continue
if(!(initial(trait_typepath.trait_flags) & STATION_TRAIT_SPACE_BOUND) && !SSmapping.is_planetary()) //we're in space but we can't do space ;_;
continue
if(!(initial(trait_typepath.trait_flags) & STATION_TRAIT_REQUIRES_AI) && !CONFIG_GET(flag/allow_ai)) //can't have AI traits without AI
continue
if(ispath(trait_typepath, /datum/station_trait/random_event_weight_modifier)) //Don't add event modifiers for events that can't occur on our map.
var/datum/station_trait/random_event_weight_modifier/random_trait_typepath = trait_typepath
var/datum/round_event_control/event_to_check = initial(random_trait_typepath.event_control_path)
if(event_to_check)
event_to_check = new event_to_check()
if(!event_to_check.valid_for_map())
continue
selectable_traits_by_types[initial(trait_typepath.trait_type)][trait_typepath] = initial(trait_typepath.weight)
var/positive_trait_budget = text2num(pick_weight(CONFIG_GET(keyed_list/positive_station_traits)))
var/neutral_trait_budget = text2num(pick_weight(CONFIG_GET(keyed_list/neutral_station_traits)))
var/negative_trait_budget = text2num(pick_weight(CONFIG_GET(keyed_list/negative_station_traits)))
#ifdef MAP_TEST
positive_trait_budget = 0
neutral_trait_budget = 0
negative_trait_budget = 0
#endif
pick_traits(STATION_TRAIT_POSITIVE, positive_trait_budget)
pick_traits(STATION_TRAIT_NEUTRAL, neutral_trait_budget)
pick_traits(STATION_TRAIT_NEGATIVE, negative_trait_budget)
/**
* Picks traits of a specific category (e.g. bad or good), initializes them, adds them to the list of traits,
* then removes them from possible traits as to not roll twice and subtracts their cost from the budget.
* All until the whole budget is spent or no more traits can be picked with it.
*/
/datum/controller/subsystem/processing/station/proc/pick_traits(trait_sign, budget)
if(!budget)
return
///A list of traits of the same trait sign
var/list/selectable_traits = selectable_traits_by_types[trait_sign]
while(budget)
///Remove any station trait with a cost bigger than the budget
for(var/datum/station_trait/proto_trait as anything in selectable_traits)
if(initial(proto_trait.cost) > budget)
selectable_traits -= proto_trait
///We have spare budget but no trait that can be bought with what's left of it
if(!length(selectable_traits))
return
//Rolls from the table for the specific trait type
var/datum/station_trait/trait_type = pick_weight(selectable_traits)
selectable_traits -= trait_type
budget -= initial(trait_type.cost)
setup_trait(trait_type)
///Creates a given trait of a specific type, while also removing any blacklisted ones from the future pool.
/datum/controller/subsystem/processing/station/proc/setup_trait(datum/station_trait/trait_type)
if(locate(trait_type) in station_traits)
return
var/datum/station_trait/trait_instance = new trait_type()
station_traits += trait_instance
log_game("Station Trait: [trait_instance.name] chosen for this round.")
if(!trait_instance.blacklist)
return
for(var/i in trait_instance.blacklist)
var/datum/station_trait/trait_to_remove = i
selectable_traits_by_types[initial(trait_to_remove.trait_type)] -= trait_to_remove
/* SKYRAT EDIT REMOVAL
/// Update station trait lobby buttons for clients who joined before we initialised this subsystem
/datum/controller/subsystem/processing/station/proc/display_lobby_traits()
for (var/mob/dead/new_player/player as anything in GLOB.new_player_list)
var/datum/hud/new_player/observer_hud = player.hud_used
if (!istype(observer_hud))
continue
observer_hud.show_station_trait_buttons()
*/