Files
vgstation13/code/game/gamemodes/gameticker.dm
SECBATON GRIFFON d0bf5682c1 Speeds up lights on at roundstart (#36623)
* Speeds up lights on at roundstart

* cleaner

* for all of em

* this was faster

* speeds this up too

* updates desc

* updates the area if used

* even more speed cutdown!!!

* makes it do itself too

* moar logging

* adds moody light

* unnecessary addition

* correct name

* kills this

* makes brighter

* back to pre conflict merge state
2024-06-11 12:14:23 -04:00

789 lines
31 KiB
Plaintext

var/datum/controller/gameticker/ticker
/datum/controller/gameticker
var/remaining_time = 0
var/const/restart_timeout = 60 SECONDS //Right now, this is padded out by the end credit's audio starting time (at the time of writing this, 10 seconds)
var/current_state = GAME_STATE_PREGAME
var/gamestart_time = -1 //In seconds. Set by ourselves in setup()
var/shuttledocked_time = -1 //In seconds. Set by emergency_shuttle/proc/shuttle_phase()
var/gameend_time = -1 //In seconds. Set by ourselves in process()
var/pregame_timeleft = 0
var/delay_end = 0 //if set to nonzero, the round will not restart on its own
var/hide_mode = 0
var/datum/gamemode/mode = null
var/event_time = null
var/event = 0
var/list/achievements = list()
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 OFFICIAL chaplain has chosen for his bible
var/Bible_item_state // item_state the OFFICIAL chaplain has chosen for his bible
var/Bible_name // name of the bible
var/Bible_deity_name = "Space Jesus" // Default deity
var/datum/religion/chap_rel // Official religion of chappy
var/list/datum/religion/religions = list() // Religion(s) in the game
var/list/runescape_skulls = list() // Keeping track of the runescape skulls that appear over mobs when enabled
var/random_players = 0 // if set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
var/hardcore_mode = 0 //If set to nonzero, hardcore mode is enabled (current hardcore mode features: damage from hunger)
//Use the hardcore_mode_on macro - if(hardcore_mode_on) to_chat(user,"You're hardcore!")
var/datum/rune_controller/rune_controller
var/triai = 0 //Global holder for Triumvirate
var/explosion_in_progress
var/station_was_nuked
var/no_life_on_station
var/revolutionary_victory //If on, Castle can be voted if the conditions are right
var/malfunctioning_AI_victory //If on, will play a different credits song
var/list/datum/role/antag_types = list() // Associative list of all the antag types in the round (List[id] = roleNumber1) //Seems to be totally unused?
// Hack
var/obj/machinery/media/jukebox/superjuke/thematic/theme = null
// Tag mode!
var/tag_mode_enabled = FALSE
#define LOBBY_TICKING 1
#define LOBBY_TICKING_RESTARTED 2
/datum/controller/gameticker/proc/pregame()
var/path = "sound/music/login/"
if(Holiday == APRIL_FOOLS_DAY)
path = "sound/music/aprilfools/"
else if(SNOW_THEME)
path = "sound/music/xmas/"
else if(map.nameShort == "castle")
path = "sound/music/castle/"
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) == "/")
filenames -= filename
if (map.nameShort == "lamprey")
login_music = file("sound/music/lampreytheme.ogg")
else if (map.nameShort == "dorf")
login_music = file("sound/music/b12_combined_start.ogg")
else
login_music = file("[path][pick(filenames)]")
send2maindiscord("**Server is loaded** and in pre-game lobby at `[config.server? "byond://[config.server]" : "byond://[world.address]:[world.port]"]`", TRUE)
do
#ifdef GAMETICKER_LOBBY_DURATION
var/delay_timetotal = GAMETICKER_LOBBY_DURATION
#else
var/delay_timetotal = DEFAULT_LOBBY_TIME
#endif
if(current_state <= GAME_STATE_PREGAME)
pregame_timeleft = world.timeofday + delay_timetotal
to_chat(world, "<B><span class='notice'>Welcome to the pre-game lobby!</span></B>")
to_chat(world, "Please, setup your character and select ready. Game will start in [(delay_timetotal) / 10] seconds.")
while(current_state <= GAME_STATE_PREGAME)
for(var/i=0, i<10, i++)
sleep(1)
vote.process()
watchdog.check_for_update()
if (world.timeofday < (863800 - delay_timetotal) && pregame_timeleft > 863950) // having a remaining time > the max of time of day is bad....
pregame_timeleft -= 864000
if(!going && !remaining_time)
remaining_time = pregame_timeleft - world.timeofday
if(going == LOBBY_TICKING_RESTARTED)
pregame_timeleft = world.timeofday + remaining_time
going = LOBBY_TICKING
remaining_time = 0
if(going && world.timeofday >= pregame_timeleft)
current_state = GAME_STATE_SETTING_UP
while (!setup())
#undef LOBBY_TICKING
#undef LOBBY_TICKING_RESTARTED
/datum/controller/gameticker/proc/IsThematic(var/playlist)
if(!theme)
return 0
if(theme.playlist_id == playlist)
return 1
return 0
/datum/controller/gameticker/proc/StartThematic(var/playlist)
if(!theme)
theme = new(locate(1,1,map.zCentcomm))
theme.playlist_id=playlist
theme.playing=1
theme.update_music()
theme.update_icon()
/datum/controller/gameticker/proc/StopThematic()
if(!theme)
return
theme.playing=0
theme.update_music()
theme.update_icon()
/datum/controller/gameticker/proc/setup()
var/total_tick = get_game_time()
//Create and announce mode
if(master_mode=="secret")
hide_mode = 1
var/list/datum/gamemode/runnable_modes
if((master_mode=="random"))
runnable_modes = config.get_runnable_modes()
if (runnable_modes.len==0)
current_state = GAME_STATE_PREGAME
to_chat(world, "<B>Unable to choose playable game mode.</B> Reverting to pre-game lobby.")
return 0
if(secret_force_mode != "secret")
var/datum/gamemode/M = config.pick_mode(secret_force_mode)
if(M.can_start())
mode = config.pick_mode(secret_force_mode)
job_master.ResetOccupations()
if(!mode)
mode = pickweight(runnable_modes)
if(mode)
var/mtype = mode.type
mode = new mtype
else if (master_mode=="secret")
mode = config.pick_mode("Dynamic Mode") //Huzzah
else
mode = config.pick_mode(master_mode)
//log_startup_progress("gameticker.mode is [src.mode.name].")
mode = new mode.type
if (!mode.can_start())
to_chat(world, "<B>Unable to start [mode.name].</B> Not enough players, [mode.minimum_player_count] players needed. Reverting to pre-game lobby.")
del(mode)
current_state = GAME_STATE_PREGAME
job_master.ResetOccupations()
return 0
//Configure mode and assign player to special mode stuff
job_master.DivideOccupations() //Distribute jobs
var/can_continue = mode.Setup()//Setup special modes
if(!can_continue)
current_state = GAME_STATE_PREGAME
to_chat(world, "<B>Error setting up [master_mode].</B> Reverting to pre-game lobby.")
log_admin("The gamemode setup for [mode.name] errored out.")
world.log << "The gamemode setup for [mode.name] errored out."
del(mode)
job_master.ResetOccupations()
return 0
//After antagonists have been removed from new_players in player_list, create crew
var/list/new_characters = list() //list of created crew for transferring
var/list/new_players_ready = list() //unique list of people who have readied up, so we can delete mob/new_player later (ready is lost on mind transfer)
var/list/roundstart_occupied_area_paths = list() //List of typepaths of areas in departments that are occupied at roundstart, used to handle the lights being on or off.
for(var/mob/M in player_list)
if(!istype(M, /mob/new_player/))
var/mob/living/L = M
L.store_position()
M.close_spawn_windows()
continue
var/mob/new_player/np = M
if(!(np.ready && np.mind && np.mind.assigned_role))
//If they aren't ready, update new player panels so they say join instead of ready up.
np.new_player_panel()
continue
var/datum/preferences/prefs = M.client.prefs
var/key = M.key
new_players_ready |= M
//Create player characters
switch(np.mind.assigned_role)
if("Cyborg", "Mobile MMI", "AI")
var/mob/living/silicon/S = np.create_roundstart_silicon(prefs)
S.store_position()
log_admin("([key]) started the game as a [S.mind.assigned_role].")
new_characters[key] = S
roundstart_occupied_area_paths |= get_department_area_typepaths(S)
if("MODE")
//antags aren't new players
else
var/mob/living/carbon/human/H = np.create_human(prefs)
H.store_position()
EquipCustomItems(H)
H.update_icons()
new_characters[key] = H
roundstart_occupied_area_paths |= get_department_area_typepaths(H)
CHECK_TICK
//Now that we have all of the occupied areas, we handle the lights being on or off, before actually putting the players into their bodies.
if(config.roundstart_lights_on || roundstart_occupied_area_paths.len)
var/light_tick = get_game_time()
var/area/A
for(var/obj/item/device/flashlight/lamp/lampychan in lamps)
A = get_area(lampychan)
if(config.roundstart_lights_on || (A.type in roundstart_occupied_area_paths))
lampychan.toggle_onoff(1)
for(var/obj/machinery/light_switch/LS in lightswitches)
A = get_area(LS)
if(config.roundstart_lights_on || (A.type in roundstart_occupied_area_paths))
LS.toggle_switch(1, FALSE, FALSE)
roundstart_occupied_area_paths -= A.type // lights are covered by this so skip these areas
if(roundstart_occupied_area_paths.len)
for(var/obj/machinery/light/lightykun in alllights)
A = get_area(lightykun)
if(config.roundstart_lights_on || (A.type in roundstart_occupied_area_paths))
lightykun.on = 1
lightykun.update()
//Force the lighting subsystem to update.
SSlighting.fire(FALSE, FALSE)
log_admin("Turned the lights on in [(get_game_time() - light_tick) / 10] seconds.")
message_admins("Turned the lights on in [(get_game_time() - light_tick) / 10] seconds.")
var/list/clowns = list()
var/already_an_ai = FALSE
//Transfer characters to players
for(var/i = 1, i <= new_characters.len, i++)
var/mob/M = new_characters[new_characters[i]]
var/key = new_characters[i]
M.key = key
if(istype(M, /mob/living/carbon/human/))
var/mob/living/carbon/human/H = M
if (H.client)
message_admins("[H.key]")
H.overlay_fullscreen("client_fadein", /obj/abstract/screen/fullscreen/client_fadein)
H.clear_fullscreen("client_fadein", 3 SECONDS)
job_master.PostJobSetup(H)
//minds are linked to accounts... And accounts are linked to jobs.
var/rank = M.mind.assigned_role
if(rank == "Clown")
clowns += M
if(rank == "AI" || isAI(M))
already_an_ai = TRUE
var/datum/job/job = job_master.GetJob(rank)
if(job)
job.equip(M, job.priority) // Outfit datum.
//delete the new_player mob for those who readied
for(var/mob/np in new_players_ready)
qdel(np)
if(!already_an_ai && clowns.len >= 2 && prob(1))
var/mob/living/carbon/human/H = pick(clowns)
if(istype(H))
H.make_fake_ai()
if(ape_mode == APE_MODE_EVERYONE) //this likely doesn't work properly, why does it only apply to humans?
for(var/mob/living/carbon/human/player in player_list)
player.apeify()
if(hide_mode)
var/list/modes = new
for (var/datum/gamemode/M in runnable_modes)
modes+=M.name
modes = sortList(modes)
if(Holiday == APRIL_FOOLS_DAY)
to_chat(world, "<B>The current game mode is - [pick("Chivalry","Crab Battle","Bay Transfer","Dwarf Fortress","Ian Says","Admins Funhouse","Meteor","Xenoarchaeology Appreciation","Clowns versus [pick("Mimes","Assistants","the Universe")]","Dino wars","Malcolm in the Middle","Six hours of extended where one person with all the access refuses to call the shuttle while everyone else goes braindead","Monkey Study","Nations","Nations by Hasbro","High roleplay Extended","DarkRP","Babies Day out","Ians Day out","Shortstaffed medical")]!</B>")
else
to_chat(world, "<B>The current game mode is - Secret!</B>")
to_chat(world, "<B>Possibilities:</B> [english_list(modes)]")
var/list/no_records = list("MODE","Mobile MMI","Trader","AI")
for(var/mob/living/carbon/human/player in player_list)
if(!(player.mind.assigned_role in no_records))
data_core.manifest_inject(player)
mode.PostSetup() //provides antag objectives
gamestart_time = world.time / 10
current_state = GAME_STATE_PLAYING
#if UNIT_TESTS_AUTORUN
run_unit_tests()
#endif
if(config.sql_enabled)
spawn(3000)
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
//mode.Clean_Antags()
//start_events() //handles random events and space dust.
//new random event system is handled from the MC.
stat_collection.round_start_time = world.realtime
Master.RoundStart()
wageSetup()
post_roundstart()
log_admin("Roundstart complete in [(get_game_time() - total_tick) / 10] seconds.")
message_admins("Roundstart complete in [(get_game_time() - total_tick) / 10] seconds.")
return 1
/mob/living/carbon/human/proc/make_fake_ai()
var/obj/effect/landmark/start/S = null
for(var/obj/effect/landmark/start/S2 in landmarks_list)
if(S2.name == "AI")
S = S2
break
if(!S)
message_admins("[formatJumpTo(key_name(src))] tried to become a fake AI but there was no AI spawn point to do it with!")
return
var/turf/T = get_turf(S)
ASSERT(T)
forceMove(T)
mind.assigned_role = "AI"
var/obj/structure/curtain/open/clownai/cc = new(T)
cc.name = src.name
qdel(head)
head = null
var/obj/item/clothing/head/cardborg/cb = new(T)
if(iswizard(src))
cb.wizard_garb = TRUE
equip_to_slot_or_drop(cb, slot_head)
var/obj/item/weapon/card/id/ID = null
var/obj/item/I = get_item_by_slot(slot_wear_id)
if(istype(I,/obj/item/weapon/card/id))
ID = I
else if(istype(I,/obj/item/device/pda))
var/obj/item/device/pda/P = I
ID = P.id
if(!ID)
ID = new(T)
ID.registered_name = src.real_name
equip_to_slot_or_drop(ID, slot_wear_id)
ID.assignment = "AI"
ID.UpdateName()
var/obj/item/device/radio/headset/H = get_item_by_slot(slot_ears)
if(!H)
H = new(T)
equip_to_slot_or_drop(H, slot_ears)
if(!iswizard(src)) // make it less unfair i guess
var/obj/item/device/encryptionkey/ai/EK
if(!H.keyslot1)
H.keyslot1 = new /obj/item/device/encryptionkey/ai(H)
EK = H.keyslot1
else
if(H.keyslot2)
EK = new /obj/item/device/encryptionkey/ai(T)
else
H.keyslot2 = new /obj/item/device/encryptionkey/ai(H)
EK = H.keyslot2
EK.translate_binary = TRUE // helps too
H.recalculateChannels()
var/turf_found = FALSE
for(var/dir in cardinal)
var/turf/T2 = get_step(src,dir)
if(T2.Cross(src)) // something that this user can pass through gets the security console
turf_found = TRUE
var/obj/structure/curtain/open/clownai/floor/F = new(T2)
F.closed_state = T2.icon_state // floor look consistency
var/obj/machinery/computer/security/SC = new(T2)
SC.density = 0 // makes exposing them a bit easier
break
if(!turf_found)
message_admins("[formatJumpTo(key_name(src))] tried to spawn a security cameras console nearby while becoming a fake AI but there was no room for one!")
to_chat(src,"<b>You [!iswizard(src) ? "have been assigned to be" : "are now"] the station's \"AI\"!</b>")
to_chat(src,"<b>You can open doors through the security cameras console in front of you by clicking on them. The curtains near you will also disguise you as the AI core itself. Alt-click the one on you to change the core appearance.</b>")
if(!iswizard(src))
to_chat(src,"<b>Since you are imitating a station AI, you are now more important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
/datum/controller/gameticker
//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/abstract/screen/cinematic = null
//Plus it provides an easy way to make cinematics for other events. Just use this as a template :)
/datum/controller/gameticker/proc/station_explosion_cinematic(var/station_missed=0, var/override = null)
if( cinematic )
return //already a cinematic in progress!
for (var/datum/html_interface/hi in html_interfaces)
hi.closeAll()
//initialise our cinematic screen object
cinematic = new(src)
cinematic.icon = 'icons/effects/station_explosion.dmi'
cinematic.icon_state = "station_intact"
cinematic.plane = HUD_PLANE
cinematic.mouse_opacity = 0
cinematic.screen_loc = "1,0"
for(var/mob/M in player_list)
if(M.client)
M.client.screen += cinematic //show every client the cinematic
if (istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/C = M
C.apply_radiation(rand(50, 250),RAD_EXTERNAL)
//Now animate the cinematic
switch(station_missed)
if(1) //nuke was nearby but (mostly) missed
if( mode && !override )
override = mode.name
switch( override )
if("nuclear emergency") //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
world << sound('sound/effects/explosionfar.ogg')
else //station was destroyed
if( mode && !override )
override = mode.name
switch( override )
if("nuclear emergency") //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"
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(cinematic)
qdel(cinematic) //end the cinematic
/datum/controller/gameticker/proc/station_nolife_cinematic(var/override = null)
if( cinematic )
return //already a cinematic in progress!
for (var/datum/html_interface/hi in html_interfaces)
hi.closeAll()
//initialise our cinematic screen object
cinematic = new(src)
cinematic.icon = 'icons/effects/station_explosion.dmi'
cinematic.icon_state = "station_nolife"
cinematic.plane = HUD_PLANE
cinematic.mouse_opacity = 0
cinematic.screen_loc = "1,0"
//actually turn everything off
power_failure(0)
//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(cinematic) //end the cinematic
no_life_on_station = TRUE
/datum/controller/gameticker/proc/process()
if(current_state != GAME_STATE_PLAYING)
return 0
mode.process()
if(world.time > nanocoins_lastchange)
nanocoins_lastchange = world.time + rand(3000,15000)
nanocoins_rates = (rand(1,30))/10
//runescape skull updates
if (runescape_skull_display)
for (var/entry in runescape_skulls)
var/datum/runescape_skull_data/the_data = runescape_skulls[entry]
the_data.process()
/*emergency_shuttle.process()*/
watchdog.check_for_update()
var/force_round_end=0
// If server's empty, force round end.
if(watchdog.waiting && player_list.len == 0)
force_round_end=1
var/mode_finished = mode.check_finished() || (emergency_shuttle.location == 2 && emergency_shuttle.alert == 1) || force_round_end
if(!explosion_in_progress && mode_finished)
current_state = GAME_STATE_FINISHED
spawn
declare_completion()
gameend_time = world.time / 10
if(!vote.map_paths)
vote.initiate_vote("map","The Server", popup = 1)
var/options = jointext(vote.choices, " ")
feedback_set("map vote choices", options)
if (station_was_nuked)
feedback_set_details("end_proper","nuke")
if(!delay_end && !watchdog.waiting)
to_chat(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 && !watchdog.waiting)
to_chat(world, "<span class='notice'><B>Restarting in [restart_timeout/10] seconds</B></span>")
end_credits.on_round_end()
if(blackbox)
if(player_list.len)
spawn(restart_timeout + 1)
blackbox.save_all_data_to_sql()
else
blackbox.save_all_data_to_sql()
stat_collection.Process()
if (watchdog.waiting)
to_chat(world, "<span class='notice'><B>Server will shut down for an automatic update in [player_list.len ? "[(restart_timeout/10)] seconds." : "a few seconds."]</B></span>")
if(player_list.len)
sleep(restart_timeout) //waiting for a mapvote to end
if(!delay_end)
watchdog.signal_ready()
else
to_chat(world, "<span class='notice'><B>An admin has delayed the round end</B></span>")
delay_end = 2
else if(!delay_end)
sleep(restart_timeout)
if(!delay_end)
world.Reboot()
else
to_chat(world, "<span class='notice'><B>An admin has delayed the round end</B></span>")
delay_end = 2
else
to_chat(world, "<span class='notice'><B>An admin has delayed the round end</B></span>")
delay_end = 2
return 1
/datum/controller/gameticker/proc/init_snake_leaderboard()
for(var/x=1;x<=PDA_APP_SNAKEII_MAXSPEED;x++)
snake_station_highscores += x
snake_station_highscores[x] = list()
snake_best_players += x
snake_best_players[x] = list()
var/list/templist1 = snake_station_highscores[x]
var/list/templist2 = snake_best_players[x]
for(var/y=1;y<=PDA_APP_SNAKEII_MAXLABYRINTH;y++)
templist1 += y
templist1[y] = 0
templist2 += y
templist2[y] = "none"
/datum/controller/gameticker/proc/init_minesweeper_leaderboard()
minesweeper_station_highscores["beginner"] = 999
minesweeper_station_highscores["intermediate"] = 999
minesweeper_station_highscores["expert"] = 999
minesweeper_best_players["beginner"] = "none"
minesweeper_best_players["intermediate"] = "none"
minesweeper_best_players["expert"] = "none"
/datum/controller/gameticker/proc/declare_completion()
if(!ooc_allowed)
to_chat(world, "<B>The OOC channel has been automatically re-enabled!</B>")
ooc_allowed = TRUE
score.main()
return 1
/datum/controller/gameticker/proc/bomberman_declare_completion()
var/icon/bomberhead = icon('icons/obj/clothing/hats.dmi', "bomberman")
var/icon/bronze = icon('icons/obj/bomberman.dmi', "bronze")
var/icon/silver = icon('icons/obj/bomberman.dmi', "silver")
var/icon/gold = icon('icons/obj/bomberman.dmi', "gold")
var/icon/platinum = icon('icons/obj/bomberman.dmi', "platinum")
var/list/bronze_tier = list()
for (var/mob/living/carbon/M in player_list)
if(locate(/obj/item/weapon/bomberman/) in M)
bronze_tier += M
var/list/silver_tier = list()
for (var/mob/M in bronze_tier)
if(M.z == map.zCentcomm)
silver_tier += M
bronze_tier -= M
var/list/gold_tier = list()
for (var/mob/M in silver_tier)
var/turf/T = get_turf(M)
if(istype(T.loc, /area/shuttle/escape/centcom))
gold_tier += M
silver_tier -= M
var/list/platinum_tier = list()
for (var/mob/living/carbon/human/M in gold_tier)
if(istype(M.wear_suit, /obj/item/clothing/suit/space/bomberman) && istype(M.head, /obj/item/clothing/head/helmet/space/bomberman))
var/obj/item/clothing/suit/space/bomberman/C1 = M.wear_suit
var/obj/item/clothing/head/helmet/space/bomberman/C2 = M.head
if(C1.never_removed && C2.never_removed)
platinum_tier += M
gold_tier -= M
var/list/special_tier = list()
for (var/mob/living/silicon/robot/mommi/M in player_list)
if(istype(M.head_state, /obj/item/clothing/head/helmet/space/bomberman) && istype(M.tool_state, /obj/item/weapon/bomberman/))
special_tier += M
var/text = {"<img class='icon' src='data:image/png;base64,[iconsouth2base64(bomberhead)]'> <font size=5><b>Bomberman Mode Results</b></font> <img class='icon' src='data:image/png;base64,[iconsouth2base64(bomberhead)]'>"}
if(!platinum_tier.len && !gold_tier.len && !silver_tier.len && !bronze_tier.len)
text += "<br><span class='danger'>DRAW!</span>"
if(platinum_tier.len)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(platinum)]'> <b>Platinum Trophy</b> (never removed his clothes, kept his bomb dispenser until the end, and escaped on the shuttle):"}
for (var/mob/M in platinum_tier)
var/icon/flat = getFlatIconDeluxe(sort_image_datas(get_content_image_datas(M)), override_dir = SOUTH)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(flat)]'> <b>[M.key]</b> as <b>[M.real_name]</b>"}
if(gold_tier.len)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(gold)]'> <b>Gold Trophy</b> (kept his bomb dispenser until the end, and escaped on the shuttle):"}
for (var/mob/M in gold_tier)
var/icon/flat = getFlatIconDeluxe(sort_image_datas(get_content_image_datas(M)), override_dir = SOUTH)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(flat)]'> <b>[M.key]</b> as <b>[M.real_name]</b>"}
if(silver_tier.len)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(silver)]'> <b>Silver Trophy</b> (kept his bomb dispenser until the end, and escaped in a pod):"}
for (var/mob/M in silver_tier)
var/icon/flat = getFlatIconDeluxe(sort_image_datas(get_content_image_datas(M)), override_dir = SOUTH)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(flat)]'> <b>[M.key]</b> as <b>[M.real_name]</b>"}
if(bronze_tier.len)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(bronze)]'> <b>Bronze Trophy</b> (kept his bomb dispenser until the end):"}
for (var/mob/M in bronze_tier)
var/icon/flat = getFlatIconDeluxe(sort_image_datas(get_content_image_datas(M)), override_dir = SOUTH)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(flat)]'> <b>[M.key]</b> as <b>[M.real_name]</b>"}
if(special_tier.len)
text += "<br><b>Special Mention</b> to those adorable MoMMis:"
for (var/mob/M in special_tier)
var/icon/flat = getFlatIconDeluxe(sort_image_datas(get_content_image_datas(M)), override_dir = SOUTH)
text += {"<br><img class='icon' src='data:image/png;base64,[iconsouth2base64(flat)]'> <b>[M.key]</b> as <b>[M.name]</b>"}
return text
/datum/controller/gameticker/proc/achievement_declare_completion()
if(!ticker.achievements.len)
return
var/text = "<br><FONT size = 5><b>Additionally, the following players earned achievements:</b></FONT>"
for(var/datum/achievement/achievement in ticker.achievements)
text += {"<br>[bicon(achievement.item)] <b>[achievement.ckey]</b> as <b>[achievement.mob_name]</b> won <b>[achievement.award_name]</b>, <b>[achievement.award_desc]!</b>"}
return text
/datum/controller/gameticker/proc/get_all_heads()
var/list/heads = list()
for(var/mob/player in mob_list)
if(player.mind && (player.mind.assigned_role in command_positions))
heads += player.mind
return heads
/datum/controller/gameticker/proc/get_assigned_head_roles()
var/list/roles = list()
for(var/mob/player in mob_list)
if(player.mind && (player.mind.assigned_role in command_positions))
roles += player.mind.assigned_role
return roles
/datum/controller/gameticker/proc/post_roundstart()
//Handle all the cyborg syncing
var/list/active_ais = active_ais()
if(active_ais.len)
for(var/mob/living/silicon/robot/R in cyborg_list)
if(!R.connected_ai)
R.connect_AI(select_active_ai_with_fewest_borgs())
to_chat(R, R.connected_ai?"<b>You have synchronized with an AI. Their name will be stated shortly. Other AIs can be ignored.</b>":"<b>You are not synchronized with an AI, and therefore are not required to heed the instructions of any unless you are synced to them.</b>")
R.lawsync()
spawn (ROUNDSTART_LOGOUT_REPORT_TIME)
display_roundstart_logout_report()
spawn (rand(INTERCEPT_TIME_LOW , INTERCEPT_TIME_HIGH))
mode.send_intercept()
spawn()
feedback_set_details("round_start","[time2text(world.realtime)]")
if(ticker && ticker.mode)
feedback_set_details("game_mode","[ticker.mode]")
feedback_set_details("server_ip","[world.internet_address]:[world.port]")
//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 and the Trader point to throw new ones
if (S.name != "AI" && S.name != "Trader")
qdel(S)
var/list/obj/effect/landmark/spacepod/random/L = list()
for(var/obj/effect/landmark/spacepod/random/SS in landmarks_list)
if(istype(SS))
L += SS
if(L.len)
var/obj/effect/landmark/spacepod/random/S = pick(L)
new /obj/spacepod/random(S.loc)
for(var/obj in L)
if(istype(obj, /obj/effect/landmark/spacepod/random))
qdel(obj)
to_chat(world, "<span class='notice'><B>Enjoy the game!</B></span>")
roundstart_timestamp = world.time
//Holiday Round-start stuff ~Carn
Holiday_Game_Start()
if(0 == admins.len)
send2adminirc("Round has started with no admins online.")
send2admindiscord("**Round has started with no admins online.**", TRUE)
send2maindiscord("**The game has started**")
// world << sound('sound/AI/welcome.ogg')// Skie //Out with the old, in with the new. - N3X15
if(!config.shut_up_automatic_diagnostic_and_announcement_system)
var/welcome_sentence=list('sound/AI/vox_login.ogg')
welcome_sentence += pick(
'sound/AI/vox_reminder1.ogg',
'sound/AI/vox_reminder2.ogg',
'sound/AI/vox_reminder3.ogg',
'sound/AI/vox_reminder4.ogg',
'sound/AI/vox_reminder5.ogg',
'sound/AI/vox_reminder6.ogg',
'sound/AI/vox_reminder7.ogg',
'sound/AI/vox_reminder8.ogg',
'sound/AI/vox_reminder9.ogg',
'sound/AI/vox_reminder10.ogg',
'sound/AI/vox_reminder11.ogg',
'sound/AI/vox_reminder12.ogg',
'sound/AI/vox_reminder13.ogg',
'sound/AI/vox_reminder14.ogg',
'sound/AI/vox_reminder15.ogg')
for(var/sound in welcome_sentence)
play_vox_sound(sound,map.zMainStation,null)
create_random_orders(3) //Populate the order system so cargo has something to do
// -- Tag mode!
/datum/controller/gameticker/proc/tag_mode(var/mob/user)
tag_mode_enabled = TRUE
to_chat(world, "<h1>Tag mode enabled!<h1>")
to_chat(world, "<span class='notice'>Tag mode is a 'gamemode' about a changeling clown infiltrated in a station populated by Mimes. His goal is to destroy it. Any mime killing the clown will in turn become the changeling.</span>")
to_chat(world, "<span class='notice'>The game ends when all mimes are dead, or when the shuttle is called.</span>")
to_chat(world, "<span class='notice'>Have fun!</span>")
// This is /datum/forced_ruleset thing. This shit exists ONLY for pre-roundstart rulesets. Yes. This is a thing.
var/datum/forced_ruleset/tag_mode = new
tag_mode.name = "Tag mode"
tag_mode.calledBy = "[key_name(user)]"
forced_roundstart_ruleset += tag_mode
admin_disable_rulesets = TRUE
log_admin("Dynamic rulesets are disabled in Tag Mode.")
message_admins("Dynamic rulesets are disabled in Tag Mode.")
/datum/controller/gameticker/proc/cancel_tag_mode(var/mob/user)
tag_mode_enabled = FALSE
to_chat(world, "<h1>Tag mode has been cancelled.<h1>")
admin_disable_rulesets = FALSE
log_admin("Dynamic rulesets have been re-enabled.")
message_admins("Dynamic rulesets have been re-enabled.")
forced_roundstart_ruleset = list()
/world/proc/has_round_started()
return ticker && ticker.current_state >= GAME_STATE_PLAYING