mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-22 08:01:06 +00:00
changes: Maps are no longer compiled in, instead loaded directly from the DMMs at runtime. Z level defines have been moved from the config to map datums. Unit tests now use typecaches. DMMS now actually works. DMMS has been updated slightly. DMMS is now capable of loading simple lists of non-text types. DMMS is now faster when loading many types without mapped in attributes and when loading area instances. Asteroid generation is now defined on the map datum instead of being hard-coded in SSasteroid. Holodeck presets are now defined on the map datum. Atmos machinery now uses Initialize().
582 lines
19 KiB
Plaintext
582 lines
19 KiB
Plaintext
#define LOBBY_TIME 180
|
|
|
|
var/datum/controller/subsystem/ticker/SSticker
|
|
|
|
/datum/controller/subsystem/ticker
|
|
// -- Subsystem stuff --
|
|
name = "Ticker"
|
|
|
|
priority = SS_PRIORITY_TICKER
|
|
flags = SS_NO_TICK_CHECK | SS_FIRE_IN_LOBBY
|
|
init_order = SS_INIT_LOBBY
|
|
|
|
wait = 1 SECOND
|
|
|
|
// -- Gameticker --
|
|
var/const/restart_timeout = 600
|
|
var/current_state = GAME_STATE_PREGAME
|
|
|
|
var/hide_mode = 0
|
|
var/datum/game_mode/mode = null
|
|
var/post_game = 0
|
|
|
|
var/login_music // music played in pregame lobby
|
|
|
|
var/list/datum/mind/minds = list()//The people in the game. Used for objective tracking.
|
|
|
|
var/Bible_icon_state // icon_state the chaplain has chosen for his bible
|
|
var/Bible_item_state // item_state the chaplain has chosen for his bible
|
|
var/Bible_name // name of the bible
|
|
var/Bible_deity_name
|
|
|
|
var/random_players = 0 // if set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
|
|
|
|
var/pregame_timeleft = 0
|
|
|
|
var/delay_end = 0 //if set to nonzero, the round will not restart on it's own
|
|
|
|
var/triai = 0 //Global holder for Triumvirate
|
|
var/tipped = 0 //Did we broadcast the tip of the day yet?
|
|
var/selected_tip // What will be the tip of the day?
|
|
|
|
var/round_end_announced = 0 // Spam Prevention. Announce round end only once.
|
|
|
|
//station_explosion used to be a variable for every mob's hud. Which was a waste!
|
|
//Now we have a general cinematic centrally held within the gameticker....far more efficient!
|
|
var/obj/screen/cinematic = null
|
|
|
|
var/list/possible_lobby_tracks = list(
|
|
'sound/music/space.ogg',
|
|
'sound/music/traitor.ogg',
|
|
'sound/music/title2.ogg',
|
|
'sound/music/clouds.s3m',
|
|
'sound/music/space_oddity.ogg'
|
|
)
|
|
|
|
var/lobby_ready = FALSE
|
|
var/is_revote = FALSE
|
|
|
|
var/list/roundstart_callbacks
|
|
|
|
/datum/controller/subsystem/ticker/New()
|
|
NEW_SS_GLOBAL(SSticker)
|
|
|
|
/datum/controller/subsystem/ticker/Initialize(timeofday)
|
|
pregame()
|
|
|
|
/datum/controller/subsystem/ticker/stat_entry()
|
|
var/state = ""
|
|
switch (current_state)
|
|
if (GAME_STATE_PREGAME)
|
|
state = "PRE"
|
|
if (GAME_STATE_SETTING_UP)
|
|
state = "SETUP"
|
|
if (GAME_STATE_PLAYING)
|
|
state = "PLAY"
|
|
if (GAME_STATE_FINISHED)
|
|
state = "FIN"
|
|
else
|
|
state = "UNK"
|
|
..("State: [state]")
|
|
|
|
/datum/controller/subsystem/ticker/Recover()
|
|
// Copy stuff over so we don't lose any state.
|
|
current_state = SSticker.current_state
|
|
|
|
hide_mode = SSticker.hide_mode
|
|
mode = SSticker.mode
|
|
post_game = SSticker.post_game
|
|
|
|
login_music = SSticker.login_music
|
|
|
|
minds = SSticker.minds
|
|
|
|
Bible_icon_state = SSticker.Bible_icon_state
|
|
Bible_item_state = SSticker.Bible_item_state
|
|
Bible_deity_name = SSticker.Bible_deity_name
|
|
|
|
random_players = SSticker.random_players
|
|
|
|
pregame_timeleft = SSticker.pregame_timeleft
|
|
|
|
delay_end = SSticker.delay_end
|
|
|
|
triai = SSticker.triai
|
|
tipped = SSticker.tipped
|
|
selected_tip = SSticker.selected_tip
|
|
|
|
round_end_announced = SSticker.round_end_announced
|
|
|
|
cinematic = SSticker.cinematic
|
|
|
|
/datum/controller/subsystem/ticker/fire()
|
|
if (!lobby_ready)
|
|
lobby_ready = TRUE
|
|
return
|
|
|
|
switch (current_state)
|
|
if (GAME_STATE_PREGAME, GAME_STATE_SETTING_UP)
|
|
pregame_tick()
|
|
if (GAME_STATE_PLAYING)
|
|
game_tick()
|
|
|
|
/datum/controller/subsystem/ticker/proc/pregame_tick()
|
|
if (round_progressing)
|
|
pregame_timeleft--
|
|
|
|
if (current_state == GAME_STATE_PREGAME && pregame_timeleft == config.vote_autogamemode_timeleft)
|
|
if (!SSvote.time_remaining)
|
|
SSvote.autogamemode()
|
|
pregame_timeleft--
|
|
return
|
|
|
|
if (pregame_timeleft <= 10 && !tipped)
|
|
send_tip_of_the_round()
|
|
tipped = TRUE
|
|
|
|
if (pregame_timeleft <= 0 || current_state == GAME_STATE_SETTING_UP)
|
|
current_state = GAME_STATE_SETTING_UP
|
|
wait = 2 SECONDS
|
|
if (!setup())
|
|
// Something fucked up.
|
|
wait = 1 SECOND
|
|
is_revote = TRUE
|
|
pregame()
|
|
|
|
/datum/controller/subsystem/ticker/proc/game_tick()
|
|
if(current_state != GAME_STATE_PLAYING)
|
|
return 0
|
|
|
|
mode.process()
|
|
|
|
var/game_finished = 0
|
|
var/mode_finished = 0
|
|
if (config.continous_rounds)
|
|
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
|
|
mode_finished = (!post_game && mode.check_finished())
|
|
else
|
|
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || universe_has_ended
|
|
mode_finished = game_finished
|
|
|
|
if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game))
|
|
current_state = GAME_STATE_FINISHED
|
|
|
|
declare_completion()
|
|
|
|
spawn(50)
|
|
callHook("roundend")
|
|
|
|
if (universe_has_ended)
|
|
if(mode.station_was_nuked)
|
|
feedback_set_details("end_proper","nuke")
|
|
else
|
|
feedback_set_details("end_proper","universe destroyed")
|
|
if(!delay_end)
|
|
world << "<span class='notice'><b>Rebooting due to destruction of station in [restart_timeout/10] seconds</b></span>"
|
|
else
|
|
feedback_set_details("end_proper","proper completion")
|
|
if(!delay_end)
|
|
world << "<span class='notice'><b>Restarting in [restart_timeout/10] seconds</b></span>"
|
|
|
|
if(!delay_end)
|
|
sleep(restart_timeout)
|
|
if(!delay_end)
|
|
world.Reboot()
|
|
else
|
|
world << "<span class='notice'><b>An admin has delayed the round end</b></span>"
|
|
else
|
|
world << "<span class='notice'><b>An admin has delayed the round end</b></span>"
|
|
|
|
else if (mode_finished)
|
|
post_game = 1
|
|
|
|
mode.cleanup()
|
|
|
|
//call a transfer shuttle vote
|
|
spawn(50)
|
|
if(!round_end_announced) // Spam Prevention. Now it should announce only once.
|
|
world << "<span class='danger'>The round has ended!</span>"
|
|
round_end_announced = 1
|
|
SSvote.autotransfer()
|
|
|
|
return 1
|
|
|
|
/datum/controller/subsystem/ticker/proc/declare_completion()
|
|
set waitfor = FALSE
|
|
|
|
world << "<br><br><br><H1>A round of [mode.name] has ended!</H1>"
|
|
for(var/mob/Player in player_list)
|
|
if(Player.mind && !isnewplayer(Player))
|
|
if(Player.stat != DEAD)
|
|
var/turf/playerTurf = get_turf(Player)
|
|
if(emergency_shuttle.departed && emergency_shuttle.evac)
|
|
if(isNotAdminLevel(playerTurf.z))
|
|
Player << "<font color='blue'><b>You managed to survive, but were marooned on [station_name()] as [Player.real_name]...</b></font>"
|
|
else
|
|
Player << "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></font>"
|
|
else if(isAdminLevel(playerTurf.z))
|
|
Player << "<font color='green'><b>You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].</b></font>"
|
|
else if(issilicon(Player))
|
|
Player << "<font color='green'><b>You remain operational after the events on [station_name()] as [Player.real_name].</b></font>"
|
|
else
|
|
Player << "<font color='blue'><b>You missed the crew transfer after the events on [station_name()] as [Player.real_name].</b></font>"
|
|
else
|
|
if(istype(Player,/mob/dead/observer))
|
|
var/mob/dead/observer/O = Player
|
|
if(!O.started_as_observer)
|
|
Player << "<font color='red'><b>You did not survive the events on [station_name()]...</b></font>"
|
|
else
|
|
Player << "<font color='red'><b>You did not survive the events on [station_name()]...</b></font>"
|
|
world << "<br>"
|
|
|
|
for (var/mob/living/silicon/ai/aiPlayer in mob_list)
|
|
if (aiPlayer.stat != 2)
|
|
world << "<b>[aiPlayer.name] (Played by: [aiPlayer.key])'s laws at the end of the round were:</b>"
|
|
else
|
|
world << "<b>[aiPlayer.name] (Played by: [aiPlayer.key])'s laws when it was deactivated were:</b>"
|
|
aiPlayer.show_laws(1)
|
|
|
|
if (aiPlayer.connected_robots.len)
|
|
var/robolist = "<b>The AI's loyal minions were:</b> "
|
|
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
|
|
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.key]), ":" (Played by: [robo.key]), "]"
|
|
world << "[robolist]"
|
|
|
|
var/dronecount = 0
|
|
|
|
for (var/mob/living/silicon/robot/robo in mob_list)
|
|
|
|
if(istype(robo,/mob/living/silicon/robot/drone))
|
|
dronecount++
|
|
continue
|
|
|
|
if (!robo.connected_ai)
|
|
if (robo.stat != 2)
|
|
world << "<b>[robo.name] (Played by: [robo.key]) survived as an AI-less borg! Its laws were:</b>"
|
|
else
|
|
world << "<b>[robo.name] (Played by: [robo.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>"
|
|
|
|
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
|
|
robo.laws.show_laws(world)
|
|
|
|
if(dronecount)
|
|
world << "<b>There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance [dronecount>1 ? "drones" : "drone"] at the end of this round.</b>"
|
|
|
|
mode.declare_completion()//To declare normal completion.
|
|
|
|
//Ask the event manager to print round end information
|
|
SSevents.RoundEnd()
|
|
|
|
//Print a list of antagonists to the server log
|
|
var/list/total_antagonists = list()
|
|
//Look into all mobs in world, dead or alive
|
|
for(var/datum/mind/Mind in minds)
|
|
var/temprole = Mind.special_role
|
|
if(temprole) //if they are an antagonist of some sort.
|
|
if(temprole in total_antagonists) //If the role exists already, add the name to it
|
|
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
|
|
else
|
|
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
|
|
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
|
|
|
|
//Now print them all into the log!
|
|
log_game("Antagonists at round end were...")
|
|
for(var/i in total_antagonists)
|
|
log_game("[i]s[total_antagonists[i]].")
|
|
|
|
SSfeedback.print_round_end_message()
|
|
|
|
return 1
|
|
|
|
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
|
|
var/m
|
|
if(selected_tip)
|
|
m = selected_tip
|
|
else
|
|
var/list/randomtips = file2list("config/tips.txt")
|
|
if(randomtips.len)
|
|
m = pick(randomtips)
|
|
|
|
if(m)
|
|
world << "<font color='purple'><b>Tip of the round: \
|
|
</b>[html_encode(m)]</font>"
|
|
|
|
/datum/controller/subsystem/ticker/proc/pregame()
|
|
set waitfor = FALSE
|
|
sleep(1) // Sleep so the MC has a chance to update its init time.
|
|
if (!login_music)
|
|
login_music = pick(possible_lobby_tracks)
|
|
|
|
if (is_revote)
|
|
pregame_timeleft = LOBBY_TIME
|
|
log_debug("SSticker: lobby reset due to game setup failure, using pregame time [LOBBY_TIME]s.")
|
|
else
|
|
var/mc_init_time = round(Master.initialization_time_taken, 1)
|
|
var/dynamic_time = LOBBY_TIME - mc_init_time
|
|
|
|
if (dynamic_time <= config.vote_autogamemode_timeleft)
|
|
pregame_timeleft = config.vote_autogamemode_timeleft + 10
|
|
log_debug("SSticker: dynamic set pregame time [dynamic_time]s was less than or equal to configured autogamemode vote time [config.vote_autogamemode_timeleft]s, clamping.")
|
|
else
|
|
pregame_timeleft = dynamic_time
|
|
log_debug("SSticker: dynamic set pregame time [dynamic_time]s was greater than configured autogamemode time, not clamping.")
|
|
|
|
world << "<B><FONT color='blue'>Welcome to the pre-game lobby!</FONT></B>"
|
|
world << "Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds."
|
|
|
|
/datum/controller/subsystem/ticker/proc/setup()
|
|
//Create and announce mode
|
|
if(master_mode == ROUNDTYPE_STR_SECRET)
|
|
src.hide_mode = ROUNDTYPE_SECRET
|
|
else if (master_mode == ROUNDTYPE_STR_MIXED_SECRET)
|
|
src.hide_mode = ROUNDTYPE_MIXED_SECRET
|
|
|
|
var/list/runnable_modes = config.get_runnable_modes(master_mode)
|
|
if(master_mode in list(ROUNDTYPE_STR_RANDOM, ROUNDTYPE_STR_SECRET, ROUNDTYPE_STR_MIXED_SECRET))
|
|
if(!runnable_modes.len)
|
|
current_state = GAME_STATE_PREGAME
|
|
world << "<B>Unable to choose playable game mode.</B> Reverting to pre-game lobby."
|
|
return 0
|
|
if(secret_force_mode != ROUNDTYPE_STR_SECRET && secret_force_mode != ROUNDTYPE_STR_MIXED_SECRET)
|
|
src.mode = config.pick_mode(secret_force_mode)
|
|
if(!src.mode)
|
|
var/list/weighted_modes = list()
|
|
var/list/probabilities = list()
|
|
|
|
if (master_mode == ROUNDTYPE_STR_SECRET)
|
|
probabilities = config.probabilities_secret
|
|
else if (master_mode == ROUNDTYPE_STR_MIXED_SECRET)
|
|
probabilities = config.probabilities_mixed_secret
|
|
else
|
|
// master_mode == ROUNDTYPE_STR_RANDOM
|
|
probabilities = config.probabilities_secret.Copy()
|
|
probabilities |= config.probabilities_mixed_secret
|
|
|
|
for(var/datum/game_mode/GM in runnable_modes)
|
|
weighted_modes[GM.config_tag] = probabilities[GM.config_tag]
|
|
src.mode = gamemode_cache[pickweight(weighted_modes)]
|
|
else
|
|
src.mode = config.pick_mode(master_mode)
|
|
|
|
if(!src.mode)
|
|
current_state = GAME_STATE_PREGAME
|
|
world << "<span class='danger'>Serious error in mode setup!</span> Reverting to pre-game lobby."
|
|
return 0
|
|
|
|
SSjobs.ResetOccupations()
|
|
src.mode.create_antagonists()
|
|
src.mode.pre_setup()
|
|
SSjobs.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
|
|
|
|
if(!src.mode.can_start())
|
|
world << "<B>Unable to start [mode.name].</B> Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby."
|
|
current_state = GAME_STATE_PREGAME
|
|
mode.fail_setup()
|
|
mode = null
|
|
SSjobs.ResetOccupations()
|
|
return 0
|
|
|
|
var/starttime = REALTIMEOFDAY
|
|
|
|
if(hide_mode)
|
|
world << "<B>The current game mode is - [hide_mode == ROUNDTYPE_SECRET ? "Secret" : "Mixed Secret"]!</B>"
|
|
if(runnable_modes.len)
|
|
var/list/tmpmodes = new
|
|
for (var/datum/game_mode/M in runnable_modes)
|
|
tmpmodes+=M.name
|
|
tmpmodes = sortList(tmpmodes)
|
|
if(tmpmodes.len)
|
|
world << "<B>Possibilities:</B> [english_list(tmpmodes)]"
|
|
else
|
|
src.mode.announce()
|
|
|
|
setup_economy()
|
|
current_state = GAME_STATE_PLAYING
|
|
create_characters() //Create player characters and transfer them
|
|
collect_minds()
|
|
equip_characters()
|
|
data_core.manifest()
|
|
|
|
Master.RoundStart()
|
|
round_start_time = world.time
|
|
|
|
callHook("roundstart")
|
|
|
|
spawn(0)//Forking here so we dont have to wait for this to finish
|
|
mode.post_setup()
|
|
//Cleanup some stuff
|
|
for(var/obj/effect/landmark/start/S in landmarks_list)
|
|
//Deleting Startpoints but we need the ai point to AI-ize people later
|
|
if (S.name != "AI")
|
|
qdel(S)
|
|
world << "<FONT color='blue'><B>Enjoy the game!</B></FONT>"
|
|
world << sound('sound/AI/welcome.ogg') // Skie
|
|
//Holiday Round-start stuff ~Carn
|
|
Holiday_Game_Start()
|
|
|
|
log_debug("SSticker: Running [LAZYLEN(roundstart_callbacks)] round-start callbacks.")
|
|
run_callback_list(roundstart_callbacks)
|
|
roundstart_callbacks = null
|
|
|
|
log_debug("SSticker: Round-start setup took [(REALTIMEOFDAY - starttime)/10] seconds.")
|
|
|
|
return 1
|
|
|
|
/datum/controller/subsystem/ticker/proc/run_callback_list(list/callbacklist)
|
|
set waitfor = FALSE
|
|
|
|
if (!callbacklist)
|
|
return
|
|
|
|
for (var/thing in callbacklist)
|
|
var/datum/callback/callback = thing
|
|
callback.Invoke()
|
|
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed = 0, override = null, list/affected_levels = current_map.station_levels)
|
|
if (cinematic)
|
|
return //already a cinematic in progress!
|
|
|
|
//initialise our cinematic screen object
|
|
cinematic = new /obj/screen{
|
|
icon = 'icons/effects/station_explosion.dmi';
|
|
icon_state = "station_intact";
|
|
layer = 20;
|
|
mouse_opacity = 0;
|
|
screen_loc = "1,0"
|
|
}
|
|
|
|
var/obj/structure/bed/temp_buckle = new
|
|
//Incredibly hackish. It creates a bed within the gameticker (lol) to stop mobs running around
|
|
if(station_missed)
|
|
for(var/mob/living/M in living_mob_list)
|
|
M.buckled = temp_buckle //buckles the mob so it can't do anything
|
|
if(M.client)
|
|
M.client.screen += cinematic //show every client the cinematic
|
|
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
|
|
for(var/mob/living/M in living_mob_list)
|
|
M.buckled = temp_buckle
|
|
if(M.client)
|
|
M.client.screen += cinematic
|
|
|
|
var/turf/Mloc = M.loc
|
|
if (!Mloc)
|
|
continue
|
|
|
|
if (!istype(Mloc))
|
|
Mloc = get_turf(M)
|
|
|
|
if (Mloc.z in affected_levels)
|
|
M.dust()
|
|
|
|
CHECK_TICK
|
|
|
|
//Now animate the cinematic
|
|
switch(station_missed)
|
|
if(1) //nuke was nearby but (mostly) missed
|
|
if( mode && !override )
|
|
override = mode.name
|
|
switch( override )
|
|
if("mercenary") //Nuke wasn't on station when it blew up
|
|
flick("intro_nuke",cinematic)
|
|
sleep(35)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
flick("station_intact_fade_red",cinematic)
|
|
cinematic.icon_state = "summary_nukefail"
|
|
else
|
|
flick("intro_nuke",cinematic)
|
|
sleep(35)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
//flick("end",cinematic)
|
|
|
|
|
|
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
|
sleep(50)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
|
|
else //station was destroyed
|
|
if( mode && !override )
|
|
override = mode.name
|
|
switch( override )
|
|
if("mercenary") //Nuke Ops successfully bombed the station
|
|
flick("intro_nuke",cinematic)
|
|
sleep(35)
|
|
flick("station_explode_fade_red",cinematic)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
cinematic.icon_state = "summary_nukewin"
|
|
if("AI malfunction") //Malf (screen,explosion,summary)
|
|
flick("intro_malf",cinematic)
|
|
sleep(76)
|
|
flick("station_explode_fade_red",cinematic)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
cinematic.icon_state = "summary_malf"
|
|
if("blob") //Station nuked (nuke,explosion,summary)
|
|
flick("intro_nuke",cinematic)
|
|
sleep(35)
|
|
flick("station_explode_fade_red",cinematic)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
cinematic.icon_state = "summary_selfdes"
|
|
else //Station nuked (nuke,explosion,summary)
|
|
flick("intro_nuke",cinematic)
|
|
sleep(35)
|
|
flick("station_explode_fade_red", cinematic)
|
|
world << sound('sound/effects/explosionfar.ogg')
|
|
cinematic.icon_state = "summary_selfdes"
|
|
|
|
//If its actually the end of the round, wait for it to end.
|
|
//Otherwise if its a verb it will continue on afterwards.
|
|
sleep(300)
|
|
|
|
if(cinematic)
|
|
QDEL_NULL(cinematic) //end the cinematic
|
|
if(temp_buckle)
|
|
QDEL_NULL(temp_buckle) //release everybody
|
|
|
|
// Round setup stuff.
|
|
|
|
/datum/controller/subsystem/ticker/proc/create_characters()
|
|
for(var/mob/new_player/player in player_list)
|
|
if(player && player.ready && player.mind)
|
|
if(player.mind.assigned_role=="AI")
|
|
player.close_spawn_windows()
|
|
player.AIize()
|
|
else if(!player.mind.assigned_role)
|
|
continue
|
|
else
|
|
player.create_character()
|
|
qdel(player)
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/ticker/proc/collect_minds()
|
|
for(var/mob/living/player in player_list)
|
|
if(player.mind)
|
|
minds += player.mind
|
|
|
|
/datum/controller/subsystem/ticker/proc/equip_characters()
|
|
var/captainless = TRUE
|
|
for(var/mob/living/carbon/human/player in player_list)
|
|
if(player && player.mind && player.mind.assigned_role)
|
|
if(player.mind.assigned_role == "Captain")
|
|
captainless = FALSE
|
|
if(!player_is_antag(player.mind, only_offstation_roles = 1))
|
|
SSjobs.EquipRank(player, player.mind.assigned_role, 0)
|
|
UpdateFactionList(player)
|
|
equip_custom_items(player)
|
|
|
|
CHECK_TICK
|
|
if(captainless)
|
|
for(var/mob/M in player_list)
|
|
if(!istype(M,/mob/new_player))
|
|
M << "Captainship not forced on anyone."
|
|
|
|
// Registers a callback to run on round-start.
|
|
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/callback)
|
|
if (!istype(callback))
|
|
return
|
|
|
|
LAZYADD(roundstart_callbacks, callback)
|
|
|
|
|
|
#undef LOBBY_TIME
|