Files
Bubberstation/code/modules/deathmatch/deathmatch_lobby.dm
+37 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

627 lines
21 KiB
Plaintext

/datum/deathmatch_lobby
/// Ckey of the host
var/host
/// Assoc list of ckey to list()
var/list/players = list()
/// Assoc list of ckey to list()
var/list/observers = list()
/// The current chosen map
var/datum/lazy_template/deathmatch/map
/// Our turf reservation AKA where the arena is
var/datum/turf_reservation/location
/// Whether the lobby is currently playing
var/playing = DEATHMATCH_NOT_PLAYING
/// Number of total ready players
var/ready_count
/// List of loadouts, either gotten from the deathmatch controller or the map
var/list/loadouts
/// Current map player spawn locations, cleared after spawning
var/list/player_spawns = list()
/// A list of paths of modifiers enabled for the match.
var/list/modifiers = list()
/// Is the modifiers modal menu open (for the host)
var/mod_menu_open = FALSE
/// artificial time padding when we start loading to give lighting a breather (admin starts will set this to 0)
var/start_time = 8 SECONDS
/datum/deathmatch_lobby/New(mob/player)
. = ..()
if (!player)
stack_trace("Attempted to create a deathmatch lobby without a host.")
return qdel(src)
host = player.ckey
map = GLOB.deathmatch_game.maps[pick(GLOB.deathmatch_game.maps)]
log_game("[host] created a deathmatch lobby.")
if (map.allowed_loadouts)
loadouts = map.allowed_loadouts
else
loadouts = GLOB.deathmatch_game.loadouts
add_player(player, loadouts[1], TRUE)
ui_interact(player)
addtimer(CALLBACK(src, PROC_REF(lobby_afk_probably)), 5 MINUTES) // being generous here
/datum/deathmatch_lobby/Destroy(force, ...)
. = ..()
for (var/key in players+observers)
var/datum/tgui/ui = SStgui.get_open_ui(get_mob_by_ckey(key), src)
if (ui) ui.close()
remove_ckey_from_play(key)
if(playing && !isnull(location))
clear_reservation()
players = null
observers = null
map?.template_in_use = FALSE //just incase
map = null
location = null
loadouts = null
modifiers = null
/datum/deathmatch_lobby/proc/start_game()
if (playing)
return
if(map.template_in_use)
to_chat(get_mob_by_ckey(host), span_warning("This map is currently loading for another lobby. Please wait until that other map finishes loading. It would be a disaster if these two mixed up."))
return
playing = DEATHMATCH_PRE_PLAYING
map.template_in_use = TRUE
RegisterSignal(map, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(find_spawns_and_start_delay))
location = map.lazy_load()
if (!location)
to_chat(get_mob_by_ckey(host), span_warning("Couldn't reserve/load a map location (all locations used?), try again later, or contact a coder."))
playing = FALSE
map.template_in_use = FALSE
UnregisterSignal(map, COMSIG_LAZY_TEMPLATE_LOADED)
return FALSE
/datum/deathmatch_lobby/proc/find_spawns_and_start_delay(datum/lazy_template/source, list/atoms)
SIGNAL_HANDLER
for(var/thing in atoms)
if(istype(thing, /obj/effect/landmark/deathmatch_player_spawn))
player_spawns += thing
UnregisterSignal(source, COMSIG_LAZY_TEMPLATE_LOADED)
map.template_in_use = FALSE
addtimer(CALLBACK(src, PROC_REF(start_game_after_delay)), start_time)
/datum/deathmatch_lobby/proc/start_game_after_delay()
if (!length(player_spawns) || length(player_spawns) < length(players))
stack_trace("Failed to get spawns when loading deathmatch map [map.name] for lobby [host].")
clear_reservation()
playing = FALSE
return FALSE
for(var/modpath in modifiers)
GLOB.deathmatch_game.modifiers[modpath].on_start_game(src)
for (var/key in players)
var/mob/dead/observer/observer = players[key]["mob"]
if (isnull(observer) || !observer.client)
log_game("Removed player [key] from deathmatch lobby [host], as they couldn't be found.")
remove_ckey_from_play(key)
continue
// pick spawn and remove it.
var/picked_spawn = pick_n_take(player_spawns)
spawn_observer_as_player(key, get_turf(picked_spawn))
qdel(picked_spawn)
// Remove rest of spawns.
QDEL_LIST(player_spawns)
for (var/observer_key in observers)
var/mob/observer = observers[observer_key]["mob"]
observer.forceMove(pick(location.reserved_turfs))
playing = DEATHMATCH_PLAYING
addtimer(CALLBACK(src, PROC_REF(game_took_too_long)), initial(map.automatic_gameend_time))
log_game("Deathmatch game [host] started.")
announce(span_reallybig("GO!"))
if(length(modifiers))
var/list/modifier_names = list()
for(var/datum/deathmatch_modifier/modifier as anything in modifiers)
modifier_names += uppertext(initial(modifier.name))
announce(span_boldnicegreen("THIS MATCH MODIFIERS: [english_list(modifier_names, and_text = " ,")]."))
return TRUE
/datum/deathmatch_lobby/proc/spawn_observer_as_player(ckey, loc)
var/list/players_info = players[ckey]
var/mob/dead/observer/observer = players_info["mob"]
if (isnull(observer) || !observer.client)
remove_ckey_from_play(ckey)
return
//Bubber edit - storing time of death before deathmatch
player_previous_death_times[observer.ckey] = list("previous_time_of_death" = observer.persistent_client.time_of_death)
//Bubber edit end
// equip player
var/datum/outfit/deathmatch_loadout/loadout = players_info["loadout"]
if (!(loadout in loadouts))
loadout = loadouts[1]
var/mob/living/carbon/human/new_player = new(loc)
observer.client?.prefs.safe_transfer_prefs_to(new_player)
new_player.dna.update_dna_identity()
new_player.updateappearance(icon_update = TRUE, mutcolor_update = TRUE, mutations_overlay_update = TRUE)
new_player.add_traits(list(TRAIT_CANNOT_CRYSTALIZE, TRAIT_PERMANENTLY_MORTAL, TRAIT_TEMPORARY_BODY), INNATE_TRAIT)
if(observer.mind)
new_player.AddComponent( \
/datum/component/temporary_body, \
old_mind = observer.mind, \
)
new_player.equipOutfit(loadout) // Loadout
new_player.PossessByPlayer(ckey)
players_info["mob"] = new_player
for(var/datum/deathmatch_modifier/modifier as anything in modifiers)
GLOB.deathmatch_game.modifiers[modifier].apply(new_player, src)
// BUBBER EDIT BEGIN - No more abductors talking to station!
if(isabductor(new_player))
var/obj/item/organ/tongue/abductor/tongue = new_player.get_organ_slot(ORGAN_SLOT_TONGUE)
if(istype(tongue, /obj/item/organ/tongue/abductor))
tongue.mothership = "deathmatch"
// BUBBER EDIT END
// register death handling.
register_player_signals(new_player)
/datum/deathmatch_lobby/proc/register_player_signals(new_player)
RegisterSignals(new_player, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING, COMSIG_MOB_GHOSTIZED), PROC_REF(player_died))
RegisterSignal(new_player, COMSIG_LIVING_ON_WABBAJACKED, PROC_REF(player_wabbajacked))
/datum/deathmatch_lobby/proc/unregister_player_signals(new_player)
UnregisterSignal(new_player, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING, COMSIG_MOB_GHOSTIZED, COMSIG_LIVING_ON_WABBAJACKED))
/datum/deathmatch_lobby/proc/game_took_too_long()
if (!location || QDELING(src))
return
announce(span_reallybig("The players have took too long! Game ending!"))
end_game()
/datum/deathmatch_lobby/proc/lobby_afk_probably()
if (QDELING(src) || playing)
return
announce(span_warning("Lobby ([host]) was closed due to not starting after 5 minutes, being potentially AFK. Please be faster next time."))
GLOB.deathmatch_game.remove_lobby(host)
/datum/deathmatch_lobby/proc/end_game()
if (!location)
CRASH("Reservation of deathmatch game [host] deleted during game.")
var/mob/winner
if(players.len)
var/list/winner_info = players[pick(players)]
if(!isnull(winner_info["mob"]))
winner = winner_info["mob"] //only one should remain anyway but incase of a draw
announce(span_reallybig("THE GAME HAS ENDED.<BR>THE WINNER IS: [winner ? winner.real_name : "no one"]."))
for(var/ckey in players)
var/mob/loser = players[ckey]["mob"]
unregister_player_signals(loser)
players[ckey]["mob"] = null
loser.ghostize(can_reenter_corpse = FALSE)
qdel(loser)
//bubber edit - give them their death timer back
var/mob/player_mob = get_mob_by_ckey(ckey)
player_mob.persistent_client.time_of_death = player_previous_death_times[ckey]["previous_time_of_death"]
//bubber edit end
for(var/datum/deathmatch_modifier/modifier in modifiers)
GLOB.deathmatch_game.modifiers[modifier].on_end_game(src)
clear_reservation()
GLOB.deathmatch_game.remove_lobby(host)
log_game("Deathmatch game [host] ended.")
/datum/deathmatch_lobby/proc/player_wabbajacked(mob/living/player, mob/living/new_mob)
SIGNAL_HANDLER
unregister_player_signals(player)
players[player.ckey]["mob"] = new_mob
register_player_signals(new_mob)
/datum/deathmatch_lobby/proc/player_died(mob/living/player, gibbed)
SIGNAL_HANDLER
if(isnull(player) || QDELING(src) || HAS_TRAIT_FROM(player, TRAIT_NO_TRANSFORM, MAGIC_TRAIT)) //this trait check fixes polymorphing
return
var/ckey = player.ckey ? player.ckey : player.mind?.key
if(!islist(players[ckey])) // potentially the player info could hold a reference to this mob so we can figure the ckey out without worrying about ghosting and suicides n such
for(var/potential_ckey in players)
var/list/player_info = players[potential_ckey]
if(player_info["mob"] && player_info["mob"] == player)
ckey = potential_ckey
break
if(!islist(players[ckey])) // if we STILL didnt find a good ckey
return
players -= ckey
var/mob/dead/observer/ghost = !player.client ? player.get_ghost() : player.ghostize() //this doesnt work on those who used the ghost verb
if(!isnull(ghost))
add_observer(ghost, (host == ckey))
announce(span_reallybig("[player.real_name] HAS DIED.<br>[players.len] REMAIN."))
//Bubber Edit - retain respawn timer
var/mob/dead_player_mob = get_mob_by_ckey(ckey)
dead_player_mob.persistent_client.time_of_death = player_previous_death_times[ckey]["previous_time_of_death"]
//BUBBER EDIT END
if(!gibbed && !QDELING(player) && !isdead(player))
if(!HAS_TRAIT(src, TRAIT_DEATHMATCH_EXPLOSIVE_IMPLANTS))
unregister_player_signals(player)
player.dust(just_ash = TRUE, drop_items = TRUE, force = TRUE)
if (players.len <= 1)
end_game()
/datum/deathmatch_lobby/proc/add_observer(mob/mob, host = FALSE)
if (players[mob.ckey])
CRASH("Tried to add [mob.ckey] as an observer while being a player.")
observers[mob.ckey] = list("mob" = mob, "host" = host)
/datum/deathmatch_lobby/proc/add_player(mob/mob, loadout, host = FALSE)
if (observers[mob.ckey])
CRASH("Tried to add [mob.ckey] as a player while being an observer.")
players[mob.ckey] = list("mob" = mob, "host" = host, "ready" = FALSE, "loadout" = loadout)
/datum/deathmatch_lobby/proc/remove_ckey_from_play(ckey)
var/is_likely_player = (ckey in players)
var/list/main_list = is_likely_player ? players : observers
var/list/info = main_list[ckey]
if(is_likely_player && islist(info))
ready_count -= info["ready"]
main_list -= ckey
/datum/deathmatch_lobby/proc/announce(message)
for (var/key in players+observers)
var/mob/player = get_mob_by_ckey(key)
if (!player.client)
remove_ckey_from_play(key)
continue
to_chat(player.client, message)
/datum/deathmatch_lobby/proc/leave(ckey)
if (host == ckey)
var/total_count = players.len + observers.len
if (total_count <= 1) // <= just in case.
GLOB.deathmatch_game.remove_lobby(host)
return
else
if (players[ckey] && players.len <= 1)
for (var/key in observers)
if (host == key)
continue
host = key
observers[key]["host"] = TRUE
break
else
for (var/key in players)
if (host == key)
continue
host = key
players[key]["host"] = TRUE
break
GLOB.deathmatch_game.passoff_lobby(ckey, host)
remove_ckey_from_play(ckey)
/datum/deathmatch_lobby/proc/join(mob/player)
if (playing || !player)
return
if(!(player.ckey in (players+observers)))
if (players.len >= map.max_players)
add_observer(player)
else
add_player(player, loadouts[1])
ui_interact(player)
/datum/deathmatch_lobby/proc/spectate(mob/player)
if (!playing || !location || !player)
return
if (!observers[player.ckey])
add_observer(player)
player.forceMove(pick(location.reserved_turfs))
/datum/deathmatch_lobby/proc/change_map(new_map)
if (!new_map || !GLOB.deathmatch_game.maps[new_map])
return
map = GLOB.deathmatch_game.maps[new_map]
var/max_players = map.max_players
for (var/possible_unlucky_loser in players)
max_players--
if (max_players < 0)
var/loser_mob = players[possible_unlucky_loser]["mob"]
remove_ckey_from_play(possible_unlucky_loser)
add_observer(loser_mob)
loadouts = map.allowed_loadouts ? map.allowed_loadouts : GLOB.deathmatch_game.loadouts
for (var/player_key in players)
if (players[player_key]["loadout"] in loadouts)
continue
players[player_key]["loadout"] = loadouts[1]
for(var/deathmatch_mod in modifiers)
GLOB.deathmatch_game.modifiers[deathmatch_mod].on_map_changed(src)
/datum/deathmatch_lobby/proc/clear_reservation()
if(isnull(location) || isnull(map))
return
for(var/turf/victimized_turf as anything in location.reserved_turfs) //remove this once clearing turf reservations is actually reliable
victimized_turf.empty()
map.reservations -= location
qdel(location)
/datum/deathmatch_lobby/Topic(href, href_list) //This handles the chat Join button href, supposedly
var/mob/dead/observer/ghost = usr
if (!istype(ghost))
return
if(href_list["join"])
join(ghost)
/datum/deathmatch_lobby/ui_state(mob/user)
return GLOB.observer_state
/// fills the lobby with fake players for the sake of UI debug, can only be called via VV
/datum/deathmatch_lobby/proc/fakefill(count)
for(var/i = 1 to count)
players["[rand(1,999)]"] = list("mob" = usr, "host" = FALSE, "ready" = FALSE, "loadout" = pick(loadouts))
/datum/deathmatch_lobby/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, null)
if(!ui)
ui = new(user, src, "DeathmatchLobby")
ui.open()
/datum/deathmatch_lobby/ui_static_data(mob/user)
. = list()
.["maps"] = list()
for (var/map_key in GLOB.deathmatch_game.maps)
.["maps"] += map_key
.["maps"] = sort_list(.["maps"])
/datum/deathmatch_lobby/ui_data(mob/user)
var/list/data = list()
var/is_player = !isnull(players[user.ckey])
var/is_host = (user.ckey == host)
var/is_admin = check_rights_for(user.client, R_ADMIN)
var/has_auth = is_host || is_admin
data["active_mods"] = "No modifiers selected"
data["admin"] = is_admin
data["host"] = is_host
data["loadouts"] = list("Randomize")
for (var/datum/outfit/deathmatch_loadout/loadout as anything in loadouts)
data["loadouts"] += loadout::display_name
data["map"] = list()
data["map"]["name"] = map.name
data["map"]["desc"] = map.desc
data["map"]["time"] = map.automatic_gameend_time
data["map"]["min_players"] = map.min_players
data["map"]["max_players"] = map.max_players
data["mod_menu_open"] = mod_menu_open
data["modifiers"] = has_auth ? get_modifier_list(is_host, mod_menu_open) : list()
data["observers"] = get_observer_list()
data["players"] = get_player_list()
data["playing"] = playing
data["self"] = user.ckey
if(length(modifiers))
var/list/mod_names = list()
for(var/datum/deathmatch_modifier/modpath as anything in modifiers)
mod_names += modpath::name
data["active_mods"] = "Selected modifiers: [english_list(mod_names)]"
if(is_player && !isnull(players[user.ckey]["loadout"]))
var/datum/outfit/deathmatch_loadout/loadout = players[user.ckey]["loadout"]
data["loadoutdesc"] = loadout::desc
else
data["loadoutdesc"] = "You are an observer! As an observer, you can hear lobby announcements."
return data
/datum/deathmatch_lobby/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || !isobserver(usr))
return
switch(action)
if ("start_game")
if (usr.ckey != host)
return FALSE
if (map.min_players > players.len)
to_chat(usr, span_warning("Not enough players to start yet."))
return FALSE
start_game()
return TRUE
if ("leave_game")
if (playing)
return FALSE
leave(usr.ckey)
ui.close()
GLOB.deathmatch_game.ui_interact(usr)
return TRUE
if ("change_loadout")
if (playing)
return FALSE
if (params["player"] != usr.ckey && host != usr.ckey)
return FALSE
if (params["loadout"] == "Randomize")
players[params["player"]]["loadout"] = pick(loadouts)
return TRUE
for (var/datum/outfit/deathmatch_loadout/possible_loadout as anything in loadouts)
if (params["loadout"] != initial(possible_loadout.display_name))
continue
players[params["player"]]["loadout"] = possible_loadout
break
return TRUE
if ("observe")
if (playing)
return FALSE
if (players[usr.ckey])
remove_ckey_from_play(usr.ckey)
add_observer(usr, host == usr.ckey)
return TRUE
else if (observers[usr.ckey] && players.len < map.max_players)
remove_ckey_from_play(usr.ckey)
add_player(usr, loadouts[1], host == usr.ckey)
return TRUE
if ("ready")
players[usr.ckey]["ready"] ^= 1 // Toggle.
ready_count += (players[usr.ckey]["ready"] * 2) - 1 // scared?
if (ready_count >= players.len && players.len >= map.min_players)
start_game()
return TRUE
if ("host") // Host functions
if (playing || (usr.ckey != host && !check_rights(R_ADMIN)))
return FALSE
var/uckey = params["id"]
switch (params["func"])
if ("Kick")
leave(uckey)
var/umob = get_mob_by_ckey(uckey)
var/datum/tgui/uui = SStgui.get_open_ui(umob, src)
uui?.close()
GLOB.deathmatch_game.ui_interact(umob)
return TRUE
if ("Transfer host")
if (host == uckey)
return FALSE
GLOB.deathmatch_game.passoff_lobby(host, uckey)
host = uckey
return TRUE
if ("Toggle observe")
var/umob = get_mob_by_ckey(uckey)
if (players[uckey])
remove_ckey_from_play(uckey)
add_observer(umob, host == uckey)
else if (observers[uckey] && players.len < map.max_players)
remove_ckey_from_play(uckey)
add_player(umob, loadouts[1], host == uckey)
return TRUE
if ("change_map")
if (!(params["map"] in GLOB.deathmatch_game.maps))
return FALSE
change_map(params["map"])
return TRUE
if("open_mod_menu")
mod_menu_open = TRUE
return TRUE
if("exit_mod_menu")
mod_menu_open = FALSE
return TRUE
if("toggle_modifier")
var/datum/deathmatch_modifier/modpath = text2path(params["modpath"])
if(!ispath(modpath))
return TRUE
if(usr.ckey != host && !check_rights(R_ADMIN))
return TRUE
var/datum/deathmatch_modifier/chosen_modifier = GLOB.deathmatch_game.modifiers[modpath]
if(modpath in modifiers)
unselect_modifier(chosen_modifier)
return TRUE
if(chosen_modifier.selectable(src))
select_modifier(chosen_modifier)
return TRUE
if ("admin") // Admin functions
if (!check_rights(R_ADMIN))
message_admins("[usr.key] has attempted to use admin functions in a deathmatch lobby without being an admin!")
log_admin("[key_name(usr)] tried to use the deathmatch lobby admin functions without authorization.")
return
switch (params["func"])
if ("Force start")
log_admin("[key_name(usr)] force started deathmatch lobby [host].")
start_time = 0
start_game()
return FALSE
/// Selects the passed modifier.
/datum/deathmatch_lobby/proc/select_modifier(datum/deathmatch_modifier/modifier)
modifier.on_select(src)
modifiers += modifier.type
/// Deselects the passed modifier.
/datum/deathmatch_lobby/proc/unselect_modifier(datum/deathmatch_modifier/modifier)
modifier.unselect(src)
modifiers -= modifier.type
/datum/deathmatch_lobby/ui_close(mob/user)
. = ..()
if(user.ckey == host)
mod_menu_open = FALSE
/// Helper proc to get modifier data
/datum/deathmatch_lobby/proc/get_modifier_list(is_host, mod_menu_open)
var/list/modifier_list = list()
if(!mod_menu_open)
return modifier_list
for(var/modpath in GLOB.deathmatch_game.modifiers)
var/datum/deathmatch_modifier/mod = GLOB.deathmatch_game.modifiers[modpath]
UNTYPED_LIST_ADD(modifier_list, list(
"name" = mod.name,
"desc" = mod.description,
"modpath" = "[modpath]",
"selected" = (modpath in modifiers),
"selectable" = is_host && mod.selectable(src),
))
return modifier_list
/// Helper proc for getting observer data
/datum/deathmatch_lobby/proc/get_observer_list()
var/list/observer_list = list()
for (var/observer_key in observers)
var/list/observer_info = observers[observer_key]
var/mob/observer_mob = observer_info["mob"]
if (isnull(observer_mob) || !observer_mob.client)
leave(observer_key)
continue
var/list/observer = observer_info.Copy()
observer["key"] = observer_key
UNTYPED_LIST_ADD(observer_list, observer)
return observer_list
/// Helper proc for getting player data
/datum/deathmatch_lobby/proc/get_player_list()
var/list/player_list = list()
for (var/player_key in players)
var/list/player_info = players[player_key]
var/mob/player_mob = player_info["mob"]
if (isnull(player_mob) || !player_mob.client)
leave(player_key)
continue
var/list/player = player_info.Copy()
var/datum/outfit/deathmatch_loadout/dm_loadout = player_info["loadout"]
player["loadout"] = dm_loadout::display_name
player["key"] = player_key
UNTYPED_LIST_ADD(player_list, player)
return player_list