@@ -1,6 +1,7 @@
|
||||
#define VALUE_MODE_NUM 0
|
||||
#define VALUE_MODE_TEXT 1
|
||||
#define VALUE_MODE_FLAG 2
|
||||
#define VALUE_MODE_NUM_LIST 3
|
||||
|
||||
#define KEY_MODE_TEXT 0
|
||||
#define KEY_MODE_TYPE 1
|
||||
@@ -191,6 +192,18 @@
|
||||
if(VALUE_MODE_TEXT)
|
||||
new_value = key_value
|
||||
continue_check_value = new_value
|
||||
if(VALUE_MODE_NUM_LIST)
|
||||
// this is all copy+pasted from number list up there, but it's super basic so I don't see it being changed soon
|
||||
var/list/new_list = list()
|
||||
var/list/values = splittext(key_value," ")
|
||||
for(var/I in values)
|
||||
var/temp = text2num(I)
|
||||
if(isnull(temp))
|
||||
log_admin("invalid number list entry in [key_name]: [I]")
|
||||
continue_check_value = FALSE
|
||||
new_list += temp
|
||||
new_value = new_list
|
||||
continue_check_value = new_list.len
|
||||
if(continue_check_value && continue_check_key && ValidateListEntry(new_key, new_value))
|
||||
config_entry_value[new_key] = new_value
|
||||
return TRUE
|
||||
@@ -198,3 +211,27 @@
|
||||
|
||||
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
|
||||
return var_name != "splitter" && ..()
|
||||
|
||||
//snowflake for donator things being on one line smh
|
||||
/datum/config_entry/multi_keyed_flag
|
||||
vv_VAS = FALSE
|
||||
abstract_type = /datum/config_entry/multi_keyed_flag
|
||||
config_entry_value = list()
|
||||
var/delimiter = "|"
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, delimiter))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
str_val = trim(str_val)
|
||||
var/list/keys = splittext(str_val, delimiter)
|
||||
for(var/i in keys)
|
||||
config_entry_value[process_key(i)] = TRUE
|
||||
return length(keys)? TRUE : FALSE
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/proc/process_key(key)
|
||||
return trim(key)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
if(_directory)
|
||||
directory = _directory
|
||||
if(entries)
|
||||
CRASH("[THIS_PROC_TYPE_WEIRD] called more than once!")
|
||||
CRASH("/datum/controller/configuration/Load() called more than once!")
|
||||
InitEntries()
|
||||
LoadModes()
|
||||
if(fexists("[directory]/config.txt") && LoadEntries("config.txt") <= 1)
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/datum/config_entry/keyed_list/donator_group
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
abstract_type = /datum/config_entry/keyed_list/donator_group
|
||||
/datum/config_entry/multi_keyed_flag/donator_group
|
||||
abstract_type = /datum/config_entry/multi_keyed_flag/donator_group
|
||||
|
||||
//If we're in the middle of a config load, only do the regeneration afterwards to prevent this from wasting a massive amount of CPU for list regenerations.
|
||||
/datum/config_entry/keyed_list/donator_group/ValidateAndSet(str_val, during_load)
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/ValidateAndSet(str_val, during_load)
|
||||
. = ..()
|
||||
if(. && during_load)
|
||||
if(. && !during_load)
|
||||
regenerate_donator_grouping_list()
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/OnPostload()
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/process_key(key)
|
||||
return ckey(key)
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/OnPostload()
|
||||
. = ..()
|
||||
regenerate_donator_grouping_list()
|
||||
|
||||
//This is kinda weird in that the config entries are defined here but all the handling/calculations are in __HELPERS/donator_groupings.dm
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_1_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_1_donators
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_2_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_2_donators
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_3_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_3_donators
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/datum/config_entry/flag/dynamic_voting
|
||||
|
||||
/datum/config_entry/number/dynamic_high_pop_limit
|
||||
config_entry_value = 55
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_pop_per_requirement
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_min
|
||||
config_entry_value = 15
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_max
|
||||
config_entry_value = 35
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_min
|
||||
config_entry_value = 5
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_max
|
||||
config_entry_value = 25
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_min
|
||||
config_entry_value = 20
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_max
|
||||
config_entry_value = 40
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_min
|
||||
config_entry_value = 10
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_max
|
||||
config_entry_value = 30
|
||||
min_val = 1
|
||||
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_cost
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_weight
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_requirements
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM_LIST
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_high_population_requirement
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/number_list/dynamic_second_rule_requirements
|
||||
|
||||
/datum/config_entry/number_list/dynamic_third_rule_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_second_rule_high_pop_requirement
|
||||
config_entry_value = 50
|
||||
|
||||
/datum/config_entry/number/dynamic_third_rule_high_pop_requirement
|
||||
config_entry_value = 70
|
||||
|
||||
/datum/config_entry/number_list/dynamic_hijack_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_high_population_requirement
|
||||
config_entry_value = 25
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_glorious_death_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_assassinate_cost
|
||||
config_entry_value = 2
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_requirement
|
||||
config_entry_value = 60
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_cost
|
||||
config_entry_value = 10
|
||||
min_val = 0
|
||||
@@ -66,10 +66,17 @@
|
||||
|
||||
/datum/config_entry/flag/disable_human_mood
|
||||
|
||||
/datum/config_entry/flag/disable_borg_flash_knockdown //Should borg flashes be capable of knocking humanoid entities down?
|
||||
|
||||
/datum/config_entry/flag/weaken_secborg //Brings secborgs and k9s back in-line with the other borg modules
|
||||
|
||||
/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
|
||||
|
||||
/datum/config_entry/flag/disable_peaceborg
|
||||
|
||||
/datum/config_entry/number/minimum_secborg_alert //Minimum alert level for secborgs to be chosen.
|
||||
config_entry_value = 3
|
||||
|
||||
/datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
@@ -132,6 +139,14 @@
|
||||
min_val = 0
|
||||
max_val = 1
|
||||
|
||||
/datum/config_entry/number/suicide_reenter_round_timer
|
||||
config_entry_value = 30
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/roundstart_suicide_time_limit
|
||||
config_entry_value = 30
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/shuttle_refuel_delay
|
||||
config_entry_value = 12000
|
||||
min_val = 0
|
||||
|
||||
@@ -141,6 +141,11 @@
|
||||
/datum/config_entry/flag/load_legacy_ranks_only //Loads admin ranks only from legacy admin_ranks.txt, while enabled ranks are mirrored to the database
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/flag/mentors_mobname_only
|
||||
|
||||
/datum/config_entry/flag/mentor_legacy_system //Defines whether the server uses the legacy mentor system with mentors.txt or the SQL system
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/string/hostedby
|
||||
|
||||
/datum/config_entry/flag/norespawn
|
||||
@@ -175,6 +180,9 @@
|
||||
/datum/config_entry/string/banappeals
|
||||
|
||||
/datum/config_entry/string/wikiurl
|
||||
config_entry_value = "https://katlin.dog/citadel-wiki"
|
||||
|
||||
/datum/config_entry/string/wikiurltg
|
||||
config_entry_value = "http://www.tgstation13.org/wiki"
|
||||
|
||||
/datum/config_entry/string/forumurl
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
SUBSYSTEM_DEF(adjacent_air)
|
||||
name = "Atmos Adjacency"
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
wait = 10
|
||||
priority = FIRE_PRIORITY_ATMOS_ADJACENCY
|
||||
var/list/queue = list()
|
||||
|
||||
/datum/controller/subsystem/adjacent_air/stat_entry()
|
||||
#ifdef TESTING
|
||||
..("P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]")
|
||||
#else
|
||||
..("P:[length(queue)]")
|
||||
#endif
|
||||
|
||||
/datum/controller/subsystem/adjacent_air/Initialize()
|
||||
while(length(queue))
|
||||
fire(mc_check = FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/adjacent_air/fire(resumed = FALSE, mc_check = TRUE)
|
||||
|
||||
var/list/queue = src.queue
|
||||
|
||||
while (length(queue))
|
||||
var/turf/currT = queue[1]
|
||||
queue.Cut(1,2)
|
||||
|
||||
currT.ImmediateCalculateAdjacentTurfs()
|
||||
|
||||
if(mc_check)
|
||||
if(MC_TICK_CHECK)
|
||||
break
|
||||
else
|
||||
CHECK_TICK
|
||||
@@ -1,6 +1,6 @@
|
||||
SUBSYSTEM_DEF(chat)
|
||||
name = "Chat"
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
flags = SS_TICKER
|
||||
wait = 1
|
||||
priority = FIRE_PRIORITY_CHAT
|
||||
init_order = INIT_ORDER_CHAT
|
||||
@@ -29,6 +29,7 @@ SUBSYSTEM_DEF(chat)
|
||||
target = GLOB.clients
|
||||
|
||||
//Some macros remain in the string even after parsing and fuck up the eventual output
|
||||
var/original_message = message
|
||||
message = replacetext(message, "\improper", "")
|
||||
message = replacetext(message, "\proper", "")
|
||||
if(handle_whitespace)
|
||||
@@ -45,6 +46,12 @@ SUBSYSTEM_DEF(chat)
|
||||
for(var/I in target)
|
||||
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
//Send it to the old style output window.
|
||||
SEND_TEXT(C, original_message)
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
continue
|
||||
|
||||
@@ -57,6 +64,12 @@ SUBSYSTEM_DEF(chat)
|
||||
else
|
||||
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
//Send it to the old style output window.
|
||||
SEND_TEXT(C, original_message)
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
return
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ SUBSYSTEM_DEF(job)
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/occupations = list() //List of all jobs
|
||||
var/list/name_occupations = list() //Dict of all jobs, keys are titles
|
||||
var/list/datum/job/name_occupations = list() //Dict of all jobs, keys are titles
|
||||
var/list/type_occupations = list() //Dict of all jobs, keys are types
|
||||
var/list/unassigned = list() //Players who need jobs
|
||||
var/initial_players_to_assign = 0 //used for checking against population caps
|
||||
@@ -14,6 +14,8 @@ SUBSYSTEM_DEF(job)
|
||||
|
||||
var/overflow_role = "Assistant"
|
||||
|
||||
var/list/level_order = list(JP_HIGH,JP_MEDIUM,JP_LOW)
|
||||
|
||||
/datum/controller/subsystem/job/Initialize(timeofday)
|
||||
SSmapping.HACK_LoadMapConfig()
|
||||
if(!occupations.len)
|
||||
@@ -119,7 +121,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(player.mind && job.title in player.mind.restricted_roles)
|
||||
JobDebug("FOC incompatible with antagonist role, Player: [player]")
|
||||
continue
|
||||
if(player.client.prefs.job_preferences["[job.title]"] == level)
|
||||
if(player.client.prefs.job_preferences[job.title] == level)
|
||||
JobDebug("FOC pass, Player: [player], Level:[level]")
|
||||
candidates += player
|
||||
return candidates
|
||||
@@ -181,7 +183,7 @@ SUBSYSTEM_DEF(job)
|
||||
//it locates a head or runs out of levels to check
|
||||
//This is basically to ensure that there's atleast a few heads in the round
|
||||
/datum/controller/subsystem/job/proc/FillHeadPosition()
|
||||
for(var/level = 1 to 3)
|
||||
for(var/level in level_order)
|
||||
for(var/command_position in GLOB.command_positions)
|
||||
var/datum/job/job = GetJob(command_position)
|
||||
if(!job)
|
||||
@@ -218,7 +220,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(!job)
|
||||
return 0
|
||||
for(var/i = job.total_positions, i > 0, i--)
|
||||
for(var/level = 1 to 3)
|
||||
for(var/level in level_order)
|
||||
var/list/candidates = list()
|
||||
candidates = FindOccupationCandidates(job, level)
|
||||
if(candidates.len)
|
||||
@@ -304,8 +306,7 @@ SUBSYSTEM_DEF(job)
|
||||
|
||||
// Loop through all levels from high to low
|
||||
var/list/shuffledoccupations = shuffle(occupations)
|
||||
var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW)
|
||||
for(var/level in levels)
|
||||
for(var/level in level_order)
|
||||
//Check the head jobs first each level
|
||||
CheckHeadPositions(level)
|
||||
|
||||
@@ -334,7 +335,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(job.required_playtime_remaining(player.client))
|
||||
JobDebug("DO player not enough xp, Player: [player], Job:[job.title]")
|
||||
continue
|
||||
|
||||
|
||||
if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
|
||||
JobDebug("DO non-human failed, Player: [player], Job:[job.title]")
|
||||
continue
|
||||
@@ -344,7 +345,7 @@ SUBSYSTEM_DEF(job)
|
||||
continue
|
||||
|
||||
// If the player wants that job on this level, then try give it to him.
|
||||
if(player.client.prefs.job_preferences["[job.title]"] == level)
|
||||
if(player.client.prefs.job_preferences[job.title] == level)
|
||||
// If the job isn't filled
|
||||
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
|
||||
JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]")
|
||||
@@ -475,7 +476,6 @@ SUBSYSTEM_DEF(job)
|
||||
to_chat(M, "<b>[job.custom_spawn_text]</b>")
|
||||
if(CONFIG_GET(number/minimal_access_threshold))
|
||||
to_chat(M, "<span class='notice'><B>As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></span>")
|
||||
|
||||
if(job && H)
|
||||
if(job.dresscodecompliant)// CIT CHANGE - dress code compliance
|
||||
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
|
||||
@@ -551,7 +551,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(job.required_playtime_remaining(player.client))
|
||||
young++
|
||||
continue
|
||||
switch(player.client.prefs.job_preferences["[job.title]"])
|
||||
switch(player.client.prefs.job_preferences[job.title])
|
||||
if(JP_HIGH)
|
||||
high++
|
||||
if(JP_MEDIUM)
|
||||
@@ -658,6 +658,46 @@ SUBSYSTEM_DEF(job)
|
||||
message_admins(msg)
|
||||
CRASH(msg)
|
||||
|
||||
/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff)
|
||||
var/mob/the_mob = N
|
||||
if(!the_mob)
|
||||
the_mob = M // cause this doesn't get assigned if player is a latejoiner
|
||||
if(the_mob.client && the_mob.client.prefs && (the_mob.client.prefs.chosen_gear && the_mob.client.prefs.chosen_gear.len))
|
||||
if(!ishuman(M))//no silicons allowed
|
||||
return
|
||||
for(var/i in the_mob.client.prefs.chosen_gear)
|
||||
var/datum/gear/G = i
|
||||
G = GLOB.loadout_items[slot_to_string(initial(G.category))][initial(G.name)]
|
||||
if(!G)
|
||||
continue
|
||||
var/permitted = TRUE
|
||||
if(G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
|
||||
permitted = FALSE
|
||||
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
|
||||
permitted = FALSE
|
||||
if(!equipbackpackstuff && G.category == SLOT_IN_BACKPACK)//snowflake check since plopping stuff in the backpack doesnt work for pre-job equip loadout stuffs
|
||||
permitted = FALSE
|
||||
if(equipbackpackstuff && G.category != SLOT_IN_BACKPACK)//ditto
|
||||
permitted = FALSE
|
||||
if(!permitted)
|
||||
continue
|
||||
var/obj/item/I = new G.path
|
||||
if(!M.equip_to_slot_if_possible(I, G.category, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // If the job's dresscode compliant, try to put it in its slot, first
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
var/obj/item/storage/backpack/B = C.back
|
||||
if(!B || !SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, I, null, TRUE, TRUE)) // Otherwise, try to put it in the backpack, for carbons.
|
||||
I.forceMove(get_turf(C))
|
||||
else if(!M.equip_to_slot_if_possible(I, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) // Otherwise, try to put it in the backpack
|
||||
I.forceMove(get_turf(M)) // If everything fails, just put it on the floor under the mob.
|
||||
|
||||
/datum/controller/subsystem/job/proc/FreeRole(rank)
|
||||
if(!rank)
|
||||
return
|
||||
var/datum/job/job = GetJob(rank)
|
||||
if(!job)
|
||||
return FALSE
|
||||
job.current_positions = max(0, job.current_positions - 1)
|
||||
|
||||
///////////////////////////////////
|
||||
//Keeps track of all living heads//
|
||||
@@ -698,4 +738,4 @@ SUBSYSTEM_DEF(job)
|
||||
. |= player.mind
|
||||
|
||||
/datum/controller/subsystem/job/proc/JobDebug(message)
|
||||
log_job_debug(message)
|
||||
log_job_debug(message)
|
||||
@@ -3,6 +3,7 @@ SUBSYSTEM_DEF(jukeboxes)
|
||||
wait = 5
|
||||
var/list/songs = list()
|
||||
var/list/activejukeboxes = list()
|
||||
var/list/freejukeboxchannels = list()
|
||||
|
||||
/datum/track
|
||||
var/song_name = "generic"
|
||||
@@ -21,23 +22,39 @@ SUBSYSTEM_DEF(jukeboxes)
|
||||
/datum/controller/subsystem/jukeboxes/proc/addjukebox(obj/jukebox, datum/track/T, jukefalloff = 1)
|
||||
if(!istype(T))
|
||||
CRASH("[src] tried to play a song with a nonexistant track")
|
||||
var/channeltoreserve = CHANNEL_JUKEBOX_START + activejukeboxes.len - 1
|
||||
if(channeltoreserve > CHANNEL_JUKEBOX)
|
||||
var/channeltoreserve = pick(freejukeboxchannels)
|
||||
if(!channeltoreserve)
|
||||
return FALSE
|
||||
freejukeboxchannels -= channeltoreserve
|
||||
var/list/youvegotafreejukebox = list(T, channeltoreserve, jukebox, jukefalloff)
|
||||
activejukeboxes.len++
|
||||
activejukeboxes[activejukeboxes.len] = list(T, channeltoreserve, jukebox, jukefalloff)
|
||||
activejukeboxes[activejukeboxes.len] = youvegotafreejukebox
|
||||
|
||||
//Due to changes in later versions of 512, SOUND_UPDATE no longer properly plays audio when a file is defined in the sound datum. As such, we are now required to init the audio before we can actually do anything with it.
|
||||
//Downsides to this? This means that you can *only* hear the jukebox audio if you were present on the server when it started playing, and it means that it's now impossible to add loops to the jukebox track list.
|
||||
var/sound/song_to_init = sound(T.song_path)
|
||||
song_to_init.status = SOUND_MUTE
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(!(M.client.prefs.toggles & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
|
||||
M.playsound_local(M, null, 100, channel = youvegotafreejukebox[2], S = song_to_init)
|
||||
return activejukeboxes.len
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/proc/removejukebox(IDtoremove)
|
||||
if(islist(activejukeboxes[IDtoremove]))
|
||||
var/jukechannel = activejukeboxes[IDtoremove][2]
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
M.stop_sound_channel(activejukeboxes[IDtoremove][2])
|
||||
M.stop_sound_channel(jukechannel)
|
||||
freejukeboxchannels |= jukechannel
|
||||
activejukeboxes.Cut(IDtoremove, IDtoremove+1)
|
||||
return TRUE
|
||||
else
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Tried to remove jukebox with invalid ID</span>")
|
||||
CRASH("Tried to remove jukebox with invalid ID")
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/proc/findjukeboxindex(obj/jukebox)
|
||||
if(activejukeboxes.len)
|
||||
@@ -57,6 +74,8 @@ SUBSYSTEM_DEF(jukeboxes)
|
||||
T.song_beat = text2num(L[3])
|
||||
T.song_associated_id = L[4]
|
||||
songs |= T
|
||||
for(var/i in CHANNEL_JUKEBOX_START to CHANNEL_JUKEBOX)
|
||||
freejukeboxchannels |= i
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/jukeboxes/fire()
|
||||
@@ -64,14 +83,15 @@ SUBSYSTEM_DEF(jukeboxes)
|
||||
return
|
||||
for(var/list/jukeinfo in activejukeboxes)
|
||||
if(!jukeinfo.len)
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Active jukebox without any associated metadata</span>")
|
||||
EXCEPTION("Active jukebox without any associated metadata.")
|
||||
continue
|
||||
var/datum/track/juketrack = jukeinfo[1]
|
||||
if(!istype(juketrack))
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. After jukebox track grabbing</span>")
|
||||
EXCEPTION("Invalid jukebox track datum.")
|
||||
continue
|
||||
var/obj/jukebox = jukeinfo[3]
|
||||
if(!istype(jukebox))
|
||||
to_chat(world, "<span class='warning'>If you see this, screenshot it and send it to a dev. Nonexistant or invalid jukebox in active jukebox list")
|
||||
EXCEPTION("Nonexistant or invalid object associated with jukebox.")
|
||||
continue
|
||||
var/sound/song_played = sound(juketrack.song_path)
|
||||
var/area/currentarea = get_area(jukebox)
|
||||
|
||||
@@ -14,6 +14,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/ruins_templates = list()
|
||||
var/list/space_ruins_templates = list()
|
||||
var/list/lava_ruins_templates = list()
|
||||
var/datum/space_level/isolated_ruins_z //Created on demand during ruin loading.
|
||||
|
||||
var/list/shuttle_templates = list()
|
||||
var/list/shelter_templates = list()
|
||||
@@ -25,6 +26,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/datum/turf_reservations //list of turf reservations
|
||||
var/list/used_turfs = list() //list of turf = datum/turf_reservation
|
||||
|
||||
var/list/reservation_ready = list()
|
||||
var/clearing_reserved_turfs = FALSE
|
||||
|
||||
// Z-manager stuff
|
||||
@@ -33,6 +35,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/z_list
|
||||
var/datum/space_level/transit
|
||||
var/datum/space_level/empty_space
|
||||
var/num_of_res_levels = 1
|
||||
|
||||
//dlete dis once #39770 is resolved
|
||||
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
|
||||
@@ -53,6 +56,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
if(!config || config.defaulted)
|
||||
to_chat(world, "<span class='boldannounce'>Unable to load next or default map config, defaulting to Box Station</span>")
|
||||
config = old_config
|
||||
GLOB.year_integer += config.year_offset
|
||||
GLOB.announcertype = (config.announcertype == "standard" ? (prob(1) ? "medibot" : "classic") : config.announcertype)
|
||||
loadWorld()
|
||||
repopulate_sorted_areas()
|
||||
process_teleport_locs() //Sets up the wizard teleport locations
|
||||
@@ -92,7 +97,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
// Set up Z-level transitions.
|
||||
setup_map_transitions()
|
||||
generate_station_area_list()
|
||||
initialize_reserved_level()
|
||||
initialize_reserved_level(transit.z_value)
|
||||
return ..()
|
||||
|
||||
/* Nuke threats, for making the blue tiles on the station go RED
|
||||
@@ -439,7 +444,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
GLOB.the_gateway.wait = world.time
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override)
|
||||
UNTIL(initialized && !clearing_reserved_turfs)
|
||||
UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
|
||||
var/datum/turf_reservation/reserve = new type
|
||||
if(turf_type_override)
|
||||
reserve.turf_type = turf_type_override
|
||||
@@ -449,6 +454,12 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
for(var/i in levels_by_trait(ZTRAIT_RESERVED))
|
||||
if(reserve.Reserve(width, height, i))
|
||||
return reserve
|
||||
//If we didn't return at this point, theres a good chance we ran out of room on the exisiting reserved z levels, so lets try a new one
|
||||
num_of_res_levels += 1
|
||||
var/datum/space_level/newReserved = add_new_zlevel("Transit/Reserved [num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE))
|
||||
initialize_reserved_level(newReserved.z_value)
|
||||
if(reserve.Reserve(width, height, newReserved.z_value))
|
||||
return reserve
|
||||
else
|
||||
if(!level_trait(z, ZTRAIT_RESERVED))
|
||||
qdel(reserve)
|
||||
@@ -459,19 +470,22 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
QDEL_NULL(reserve)
|
||||
|
||||
//This is not for wiping reserved levels, use wipe_reservations() for that.
|
||||
/datum/controller/subsystem/mapping/proc/initialize_reserved_level()
|
||||
/datum/controller/subsystem/mapping/proc/initialize_reserved_level(z)
|
||||
UNTIL(!clearing_reserved_turfs) //regardless, lets add a check just in case.
|
||||
clearing_reserved_turfs = TRUE //This operation will likely clear any existing reservations, so lets make sure nothing tries to make one while we're doing it.
|
||||
for(var/i in levels_by_trait(ZTRAIT_RESERVED))
|
||||
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,i))
|
||||
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,i))
|
||||
var/block = block(A, B)
|
||||
for(var/t in block)
|
||||
// No need to empty() these, because it's world init and they're
|
||||
// already /turf/open/space/basic.
|
||||
var/turf/T = t
|
||||
T.flags_1 |= UNUSED_RESERVATION_TURF_1
|
||||
unused_turfs["[i]"] = block
|
||||
if(!level_trait(z,ZTRAIT_RESERVED))
|
||||
clearing_reserved_turfs = FALSE
|
||||
CRASH("Invalid z level prepared for reservations.")
|
||||
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z))
|
||||
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z))
|
||||
var/block = block(A, B)
|
||||
for(var/t in block)
|
||||
// No need to empty() these, because it's world init and they're
|
||||
// already /turf/open/space/basic.
|
||||
var/turf/T = t
|
||||
T.flags_1 |= UNUSED_RESERVATION_TURF_1
|
||||
unused_turfs["[z]"] = block
|
||||
reservation_ready["[z]"] = TRUE
|
||||
clearing_reserved_turfs = FALSE
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs)
|
||||
@@ -481,6 +495,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
LAZYINITLIST(unused_turfs["[T.z]"])
|
||||
unused_turfs["[T.z]"] |= T
|
||||
T.flags_1 |= UNUSED_RESERVATION_TURF_1
|
||||
GLOB.areas_by_type[world.area].contents += T
|
||||
CHECK_TICK
|
||||
|
||||
//DO NOT CALL THIS PROC DIRECTLY, CALL wipe_reservations().
|
||||
@@ -504,3 +519,9 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
for(var/B in areas)
|
||||
var/area/A = B
|
||||
A.reg_in_areas_in_z()
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/get_isolated_ruin_z()
|
||||
if(!isolated_ruins_z)
|
||||
isolated_ruins_z = add_new_zlevel("Isolated Ruins/Reserved", list(ZTRAIT_RESERVED = TRUE, ZTRAIT_ISOLATED_RUINS = TRUE))
|
||||
initialize_reserved_level(isolated_ruins_z.z_value)
|
||||
return isolated_ruins_z.z_value
|
||||
@@ -1,6 +1,6 @@
|
||||
SUBSYSTEM_DEF(npcpool)
|
||||
name = "NPC Pool"
|
||||
flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
|
||||
flags = SS_KEEP_TIMING | SS_NO_INIT
|
||||
priority = FIRE_PRIORITY_NPC
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ SUBSYSTEM_DEF(pai)
|
||||
candidate.comments = copytext(sanitize(candidate.comments),1,MAX_MESSAGE_LEN)
|
||||
|
||||
if("submit")
|
||||
if(isobserver(usr))
|
||||
var/mob/dead/observer/O = usr
|
||||
if(!O.can_reenter_round())
|
||||
return FALSE
|
||||
if(candidate)
|
||||
candidate.ready = 1
|
||||
for(var/obj/item/paicard/p in pai_card_list)
|
||||
@@ -148,6 +152,8 @@ SUBSYSTEM_DEF(pai)
|
||||
continue
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
if(!G.can_reenter_round()) // this should use notify_ghosts() instead one day.
|
||||
return FALSE
|
||||
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define FILE_ANTAG_REP "data/AntagReputation.json"
|
||||
#define MAX_RECENT_MAP_RECORD 10
|
||||
|
||||
SUBSYSTEM_DEF(persistence)
|
||||
name = "Persistence"
|
||||
@@ -11,11 +12,8 @@ SUBSYSTEM_DEF(persistence)
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/list/saved_modes = list(1,2,3)
|
||||
<<<<<<< HEAD
|
||||
var/list/saved_threat_levels = list(1,1,1)
|
||||
var/list/saved_maps
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
var/list/saved_trophies = list()
|
||||
var/list/spawned_objects = list()
|
||||
var/list/antag_rep = list()
|
||||
@@ -30,11 +28,8 @@ SUBSYSTEM_DEF(persistence)
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
LoadRecentModes()
|
||||
<<<<<<< HEAD
|
||||
LoadRecentThreats()
|
||||
LoadRecentMaps()
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
LoadPhotoPersistence()
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
LoadAntagReputation()
|
||||
@@ -173,7 +168,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
saved_modes = json["data"]
|
||||
|
||||
<<<<<<< HEAD
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentThreats()
|
||||
var/json_file = file("data/RecentThreatLevels.json")
|
||||
if(!fexists(json_file))
|
||||
@@ -192,8 +186,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
saved_maps = json["maps"]
|
||||
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
/datum/controller/subsystem/persistence/proc/LoadAntagReputation()
|
||||
var/json = file2text(FILE_ANTAG_REP)
|
||||
if(!json)
|
||||
@@ -235,11 +227,8 @@ SUBSYSTEM_DEF(persistence)
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
CollectRoundtype()
|
||||
<<<<<<< HEAD
|
||||
CollectThreatLevel()
|
||||
RecordMaps()
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
CollectAntagReputation()
|
||||
@@ -395,7 +384,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
<<<<<<< HEAD
|
||||
/datum/controller/subsystem/persistence/proc/CollectThreatLevel()
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
@@ -417,8 +405,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
/datum/controller/subsystem/persistence/proc/CollectAntagReputation()
|
||||
var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum)
|
||||
|
||||
|
||||
@@ -4,24 +4,32 @@ SUBSYSTEM_DEF(research)
|
||||
priority = FIRE_PRIORITY_RESEARCH
|
||||
wait = 10
|
||||
init_order = INIT_ORDER_RESEARCH
|
||||
//TECHWEB STATIC
|
||||
var/list/techweb_nodes = list() //associative id = node datum
|
||||
var/list/techweb_designs = list() //associative id = node datum
|
||||
var/list/datum/techweb/techwebs = list()
|
||||
var/datum/techweb/science/science_tech
|
||||
var/datum/techweb/admin/admin_tech
|
||||
var/datum/techweb_node/error_node/error_node //These two are what you get if a node/design is deleted and somehow still stored in a console.
|
||||
var/datum/design/error_design/error_design
|
||||
|
||||
//ERROR LOGGING
|
||||
var/list/invalid_design_ids = list() //associative id = number of times
|
||||
var/list/invalid_node_ids = list() //associative id = number of times
|
||||
var/list/invalid_node_boost = list() //associative id = error message
|
||||
|
||||
var/list/obj/machinery/rnd/server/servers = list()
|
||||
var/datum/techweb/science/science_tech
|
||||
var/datum/techweb/admin/admin_tech
|
||||
var/list/techweb_nodes = list() //associative id = node datum
|
||||
var/list/techweb_categories = list() //category name = list(node.id = node)
|
||||
var/list/techweb_designs = list() //associative id = node datum
|
||||
var/list/techweb_nodes_starting = list() //associative id = node datum
|
||||
|
||||
var/list/techweb_nodes_starting = list() //associative id = TRUE
|
||||
var/list/techweb_categories = list() //category name = list(node.id = TRUE)
|
||||
var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount))
|
||||
var/list/techweb_nodes_hidden = list() //Nodes that should be hidden by default.
|
||||
var/list/techweb_nodes_hidden = list() //Node ids that should be hidden by default.
|
||||
var/list/techweb_point_items = list( //path = list(point type = value)
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 2500),
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 5000), // Cit three more anomalys anomalys
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 7500),
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000),
|
||||
// - Slime Extracts! -
|
||||
// - Slime Extracts! -
|
||||
/obj/item/slime_extract/grey = list(TECHWEB_POINT_TYPE_GENERIC = 500), // Adds in slime core deconing
|
||||
/obj/item/slime_extract/metal = list(TECHWEB_POINT_TYPE_GENERIC = 750),
|
||||
/obj/item/slime_extract/purple = list(TECHWEB_POINT_TYPE_GENERIC = 750),
|
||||
@@ -294,6 +302,8 @@ SUBSYSTEM_DEF(research)
|
||||
science_tech = new /datum/techweb/science
|
||||
admin_tech = new /datum/techweb/admin
|
||||
autosort_categories()
|
||||
error_design = new
|
||||
error_node = new
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/research/fire()
|
||||
@@ -330,6 +340,191 @@ SUBSYSTEM_DEF(research)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/I = techweb_nodes[i]
|
||||
if(techweb_categories[I.category])
|
||||
techweb_categories[I.category][I.id] = I
|
||||
techweb_categories[I.category][I.id] = TRUE
|
||||
else
|
||||
techweb_categories[I.category] = list(I.id = I)
|
||||
techweb_categories[I.category] = list(I.id = TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_node_by_id(id)
|
||||
return techweb_nodes[id] || error_node
|
||||
|
||||
/datum/controller/subsystem/research/proc/techweb_design_by_id(id)
|
||||
return techweb_designs[id] || error_design
|
||||
|
||||
/datum/controller/subsystem/research/proc/on_design_deletion(datum/design/D)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/TN = techwebs[i]
|
||||
TN.on_design_deletion(TN)
|
||||
for(var/i in techwebs)
|
||||
var/datum/techweb/T = i
|
||||
T.recalculate_nodes(TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/on_node_deletion(datum/techweb_node/TN)
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/TN2 = techwebs[i]
|
||||
TN2.on_node_deletion(TN)
|
||||
for(var/i in techwebs)
|
||||
var/datum/techweb/T = i
|
||||
T.recalculate_nodes(TRUE)
|
||||
|
||||
/datum/controller/subsystem/research/proc/initialize_all_techweb_nodes(clearall = FALSE)
|
||||
if(islist(techweb_nodes) && clearall)
|
||||
QDEL_LIST(techweb_nodes)
|
||||
if(islist(techweb_nodes_starting && clearall))
|
||||
techweb_nodes_starting.Cut()
|
||||
var/list/returned = list()
|
||||
for(var/path in subtypesof(/datum/techweb_node))
|
||||
var/datum/techweb_node/TN = path
|
||||
if(isnull(initial(TN.id)))
|
||||
continue
|
||||
TN = new path
|
||||
if(returned[initial(TN.id)])
|
||||
stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected! Path: [path]")
|
||||
errored_datums[TN] = initial(TN.id)
|
||||
continue
|
||||
returned[initial(TN.id)] = TN
|
||||
if(TN.starting_node)
|
||||
techweb_nodes_starting[TN.id] = TRUE
|
||||
for(var/id in techweb_nodes)
|
||||
var/datum/techweb_node/TN = techweb_nodes[id]
|
||||
TN.Initialize()
|
||||
techweb_nodes = returned
|
||||
if (!verify_techweb_nodes()) //Verify all nodes have ids and such.
|
||||
stack_trace("Invalid techweb nodes detected")
|
||||
calculate_techweb_nodes()
|
||||
calculate_techweb_boost_list()
|
||||
if (!verify_techweb_nodes()) //Verify nodes and designs have been crosslinked properly.
|
||||
CRASH("Invalid techweb nodes detected")
|
||||
|
||||
/datum/controller/subsystem/research/proc/initialize_all_techweb_designs(clearall = FALSE)
|
||||
if(islist(techweb_designs) && clearall)
|
||||
QDEL_LIST(techweb_designs)
|
||||
var/list/returned = list()
|
||||
for(var/path in subtypesof(/datum/design))
|
||||
var/datum/design/DN = path
|
||||
if(isnull(initial(DN.id)))
|
||||
stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]")
|
||||
continue
|
||||
else if(initial(DN.id) == DESIGN_ID_IGNORE)
|
||||
continue
|
||||
DN = new path
|
||||
if(returned[initial(DN.id)])
|
||||
stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected! Path: [path]")
|
||||
errored_datums[DN] = initial(DN.id)
|
||||
continue
|
||||
returned[initial(DN.id)] = DN
|
||||
techweb_designs = returned
|
||||
verify_techweb_designs()
|
||||
|
||||
/datum/controller/subsystem/research/proc/verify_techweb_nodes()
|
||||
. = TRUE
|
||||
for(var/n in techweb_nodes)
|
||||
var/datum/techweb_node/N = techweb_nodes[n]
|
||||
if(!istype(N))
|
||||
WARNING("Invalid research node with ID [n] detected and removed.")
|
||||
techweb_nodes -= n
|
||||
research_node_id_error(n)
|
||||
. = FALSE
|
||||
for(var/p in N.prereq_ids)
|
||||
var/datum/techweb_node/P = techweb_nodes[p]
|
||||
if(!istype(P))
|
||||
WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.prereq_ids -= p
|
||||
research_node_id_error(p)
|
||||
. = FALSE
|
||||
for(var/d in N.design_ids)
|
||||
var/datum/design/D = techweb_designs[d]
|
||||
if(!istype(D))
|
||||
WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.design_ids -= d
|
||||
design_id_error(d)
|
||||
. = FALSE
|
||||
for(var/u in N.unlock_ids)
|
||||
var/datum/techweb_node/U = techweb_nodes[u]
|
||||
if(!istype(U))
|
||||
WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.")
|
||||
N.unlock_ids -= u
|
||||
research_node_id_error(u)
|
||||
. = FALSE
|
||||
for(var/p in N.boost_item_paths)
|
||||
if(!ispath(p))
|
||||
N.boost_item_paths -= p
|
||||
WARNING("[p] is not a valid path.")
|
||||
node_boost_error(N.id, "[p] is not a valid path.")
|
||||
. = FALSE
|
||||
var/list/points = N.boost_item_paths[p]
|
||||
if(islist(points))
|
||||
for(var/i in points)
|
||||
if(!isnum(points[i]))
|
||||
WARNING("[points[i]] is not a valid number.")
|
||||
node_boost_error(N.id, "[points[i]] is not a valid number.")
|
||||
. = FALSE
|
||||
else if(!point_types[i])
|
||||
WARNING("[i] is not a valid point type.")
|
||||
node_boost_error(N.id, "[i] is not a valid point type.")
|
||||
. = FALSE
|
||||
else if(!isnull(points))
|
||||
N.boost_item_paths -= p
|
||||
node_boost_error(N.id, "No valid list.")
|
||||
WARNING("No valid list.")
|
||||
. = FALSE
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/research/proc/verify_techweb_designs()
|
||||
for(var/d in techweb_designs)
|
||||
var/datum/design/D = techweb_designs[d]
|
||||
if(!istype(D))
|
||||
stack_trace("WARNING: Invalid research design with ID [d] detected and removed.")
|
||||
techweb_designs -= d
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/research/proc/research_node_id_error(id)
|
||||
if(invalid_node_ids[id])
|
||||
invalid_node_ids[id]++
|
||||
else
|
||||
invalid_node_ids[id] = 1
|
||||
|
||||
/datum/controller/subsystem/research/proc/design_id_error(id)
|
||||
if(invalid_design_ids[id])
|
||||
invalid_design_ids[id]++
|
||||
else
|
||||
invalid_design_ids[id] = 1
|
||||
|
||||
/datum/controller/subsystem/research/proc/calculate_techweb_nodes()
|
||||
for(var/design_id in techweb_designs)
|
||||
var/datum/design/D = techweb_designs[design_id]
|
||||
D.unlocked_by.Cut()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
node.unlock_ids = list()
|
||||
for(var/i in node.design_ids)
|
||||
var/datum/design/D = techweb_designs[i]
|
||||
node.design_ids[i] = TRUE
|
||||
D.unlocked_by += node.id
|
||||
if(node.hidden)
|
||||
techweb_nodes_hidden[node.id] = TRUE
|
||||
CHECK_TICK
|
||||
generate_techweb_unlock_linking()
|
||||
|
||||
/datum/controller/subsystem/research/proc/generate_techweb_unlock_linking()
|
||||
for(var/node_id in techweb_nodes) //Clear all unlock links to avoid duplication.
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
node.unlock_ids = list()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
for(var/prereq_id in node.prereq_ids)
|
||||
var/datum/techweb_node/prereq_node = techweb_node_by_id(prereq_id)
|
||||
prereq_node.unlock_ids[node.id] = node
|
||||
|
||||
/datum/controller/subsystem/research/proc/calculate_techweb_boost_list(clearall = FALSE)
|
||||
if(clearall)
|
||||
techweb_boost_items = list()
|
||||
for(var/node_id in techweb_nodes)
|
||||
var/datum/techweb_node/node = techweb_nodes[node_id]
|
||||
for(var/path in node.boost_item_paths)
|
||||
if(!ispath(path))
|
||||
continue
|
||||
if(length(techweb_boost_items[path]))
|
||||
techweb_boost_items[path][node.id] = node.boost_item_paths[path]
|
||||
else
|
||||
techweb_boost_items[path] = list(node.id = node.boost_item_paths[path])
|
||||
CHECK_TICK
|
||||
|
||||
@@ -37,6 +37,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/points = 5000 //number of trade-points we have
|
||||
var/centcom_message = "" //Remarks from CentCom on how well you checked the last order.
|
||||
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
|
||||
var/passive_supply_points_per_minute = 750
|
||||
|
||||
var/list/supply_packs = list()
|
||||
var/list/shoppinglist = list()
|
||||
@@ -111,6 +112,12 @@ SUBSYSTEM_DEF(shuttle)
|
||||
qdel(T, force=TRUE)
|
||||
CheckAutoEvac()
|
||||
|
||||
//Cargo stuff start
|
||||
var/fire_time_diff = max(0, world.time - last_fire) //Don't want this to be below 0, seriously.
|
||||
var/point_gain = (fire_time_diff / 600) * passive_supply_points_per_minute
|
||||
points += point_gain
|
||||
//Cargo stuff end
|
||||
|
||||
if(!SSmapping.clearing_reserved_turfs)
|
||||
while(transit_requesters.len)
|
||||
var/requester = popleft(transit_requesters)
|
||||
@@ -373,7 +380,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
emergency.setTimer(emergencyDockTime)
|
||||
priority_announce("Hostile environment resolved. \
|
||||
You have 3 minutes to board the Emergency Shuttle.",
|
||||
null, 'sound/ai/shuttledock.ogg', "Priority")
|
||||
null, "shuttledock", "Priority")
|
||||
|
||||
//try to move/request to dockHome if possible, otherwise dockAway. Mainly used for admin buttons
|
||||
/datum/controller/subsystem/shuttle/proc/toggleShuttle(shuttleId, dockHome, dockAway, timed)
|
||||
@@ -631,3 +638,11 @@ SUBSYSTEM_DEF(shuttle)
|
||||
C.update_hidden_docking_ports(remove_images, add_images)
|
||||
|
||||
QDEL_LIST(remove_images)
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/autoEnd() //CIT CHANGE - allows shift to end after 2 hours have passed.
|
||||
if((world.realtime - SSshuttle.realtimeofstart) > auto_call && EMERGENCY_IDLE_OR_RECALLED) //2 hours
|
||||
SSshuttle.emergency.request(silent = TRUE)
|
||||
priority_announce("The shift has come to an end and the shuttle called. [seclevel2num(get_security_level()) == SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [emergency.timeLeft(600)] minutes.", null, "shuttlecalled", "Priority")
|
||||
log_game("Round time limit reached. Shuttle has been auto-called.")
|
||||
message_admins("Round time limit reached. Shuttle called.")
|
||||
emergencyNoRecall = TRUE
|
||||
|
||||
@@ -43,6 +43,7 @@ SUBSYSTEM_DEF(throwing)
|
||||
var/atom/movable/thrownthing
|
||||
var/atom/target
|
||||
var/turf/target_turf
|
||||
var/target_zone
|
||||
var/init_dir
|
||||
var/maxrange
|
||||
var/speed
|
||||
@@ -146,6 +147,11 @@ SUBSYSTEM_DEF(throwing)
|
||||
if (callback)
|
||||
callback.Invoke()
|
||||
|
||||
if(!thrownthing.zfalling) // I don't think you can zfall while thrown but hey, just in case.
|
||||
var/turf/T = get_turf(thrownthing)
|
||||
if(T && thrownthing.has_gravity(T))
|
||||
T.zFall(thrownthing)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/datum/thrownthing/proc/hit_atom(atom/A)
|
||||
|
||||
@@ -303,7 +303,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
SSdbcore.SetRoundStart()
|
||||
|
||||
to_chat(world, "<span class='notice'><B>Welcome to [station_name()], enjoy your stay!</B></span>")
|
||||
SEND_SOUND(world, sound('sound/ai/welcome.ogg'))
|
||||
SEND_SOUND(world, sound(get_announcer_sound("welcome")))
|
||||
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
@@ -479,7 +479,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(SSticker.timeLeft < 900)
|
||||
SSticker.timeLeft = 900
|
||||
SSticker.modevoted = TRUE
|
||||
SSvote.initiate_vote("roundtype","server",TRUE)
|
||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||
SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE)
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
|
||||
@@ -40,7 +40,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
"cats" = strings(PHOBIA_FILE, "cats"),
|
||||
"syndicate"= strings(PHOBIA_FILE, "syndicate"),
|
||||
"eye" = strings(PHOBIA_FILE, "eye")
|
||||
)
|
||||
)
|
||||
|
||||
phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)),
|
||||
"security" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/bot/ed209)),
|
||||
@@ -166,7 +166,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
|
||||
"syndicate" = typecacheof(list(/obj/item/stack/tile/mineral/plastitanium, /obj/machinery/computer/shuttle/syndicate, /obj/machinery/computer/shuttle/syndicate/recall, /obj/machinery/computer/shuttle/syndicate/drop_pod, /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate, /obj/machinery/recharge_station,
|
||||
/obj/machinery/porta_turret/syndicate, /obj/structure/closet/syndicate, /obj/machinery/suit_storage_unit/syndicate, /obj/item/clothing/under/syndicate, /obj/item/folder/syndicate, /obj/item/documents/syndicate, /obj/item/clothing/glasses/phantomthief/syndicate, /obj/item/antag_spawner/nuke_ops, /obj/item/storage/box/syndicate,
|
||||
/obj/structure/fluff/empty_sleeper/syndicate, /obj/item/implant/radio/syndicate, /obj/item/clothing/head/helmet/space/syndicate, /obj/machinery/nuclearbomb/syndicate, /obj/item/grenade/syndieminibomb, /obj/item/storage/backpack/duffelbag/syndie, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver/syndie,
|
||||
/obj/structure/fluff/empty_sleeper/syndicate, /obj/item/implant/radio/syndicate, /obj/item/clothing/head/helmet/space/syndicate, /obj/machinery/nuclearbomb/syndicate, /obj/item/grenade/syndieminibomb, /obj/item/storage/backpack/duffelbag/syndie, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver,
|
||||
/obj/item/gun/ballistic/automatic/shotgun/bulldog, /obj/item/gun/ballistic/automatic/c20r, /obj/item/gun/ballistic/automatic/m90, /obj/item/gun/ballistic/automatic/l6_saw, /obj/item/storage/belt/grenade/full, /obj/item/gun/ballistic/automatic/sniper_rifle/syndicate, /obj/item/gun/energy/kinetic_accelerator/crossbow,
|
||||
/obj/item/melee/transforming/energy/sword/saber, /obj/item/twohanded/dualsaber, /obj/item/melee/powerfist, /obj/item/storage/box/syndie_kit, /obj/item/grenade/spawnergrenade/manhacks, /obj/item/grenade/chem_grenade/bioterrorfoam, /obj/item/reagent_containers/spray/chemsprayer/bioterror, /obj/item/ammo_box/magazine/m10mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/mecha/combat/gygax/dark, /obj/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate,
|
||||
|
||||
@@ -6,11 +6,9 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
|
||||
var/list/vis_overlay_cache
|
||||
var/list/currentrun
|
||||
var/datum/callback/rotate_cb
|
||||
|
||||
/datum/controller/subsystem/vis_overlays/Initialize()
|
||||
vis_overlay_cache = list()
|
||||
rotate_cb = CALLBACK(src, .proc/rotate_vis_overlay)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
|
||||
@@ -53,7 +51,7 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
|
||||
if(!thing.managed_vis_overlays)
|
||||
thing.managed_vis_overlays = list(overlay)
|
||||
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, rotate_cb)
|
||||
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay)
|
||||
else
|
||||
thing.managed_vis_overlays += overlay
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(vote)
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/list/winners = get_result()
|
||||
var/text
|
||||
var/was_roundtype_vote = mode == "roundtype"
|
||||
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
|
||||
if(winners.len > 0)
|
||||
if(question)
|
||||
text += "<b>[question]</b>"
|
||||
@@ -124,6 +124,9 @@ SUBSYSTEM_DEF(vote)
|
||||
message_admins(admintext)
|
||||
return .
|
||||
|
||||
#define PEACE "calm"
|
||||
#define CHAOS "chaotic"
|
||||
|
||||
/datum/controller/subsystem/vote/proc/result()
|
||||
. = announce_result()
|
||||
var/restart = 0
|
||||
@@ -146,7 +149,6 @@ SUBSYSTEM_DEF(vote)
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
<<<<<<< HEAD
|
||||
if("dynamic")
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
||||
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
@@ -177,8 +179,6 @@ SUBSYSTEM_DEF(vote)
|
||||
GLOB.dynamic_curve_width = CLAMP(2-abs(mean*5),0.5,4)
|
||||
to_chat(world,"<span class='boldannounce'>Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].</span>")
|
||||
log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]")
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
if("map")
|
||||
var/datum/map_config/VM = config.maplist[.]
|
||||
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
||||
@@ -241,20 +241,27 @@ SUBSYSTEM_DEF(vote)
|
||||
if("gamemode")
|
||||
choices.Add(config.votable_modes)
|
||||
if("map")
|
||||
choices.Add(config.maplist)
|
||||
for(var/i in choices)//this is necessary because otherwise we'll end up with a bunch of /datum/map_config's as the default vote value instead of 0 as intended
|
||||
choices[i] = 0
|
||||
var/players = GLOB.clients.len
|
||||
var/list/lastmaps = SSpersistence.saved_maps?.len ? list("[SSmapping.config.map_name]") | SSpersistence.saved_maps : list("[SSmapping.config.map_name]")
|
||||
for(var/M in config.maplist) //This is a typeless loop due to the finnicky nature of keyed lists in this kind of context
|
||||
var/datum/map_config/targetmap = config.maplist[M]
|
||||
if(!istype(targetmap))
|
||||
continue
|
||||
if(!targetmap.voteweight)
|
||||
continue
|
||||
if((targetmap.config_min_users && players < targetmap.config_min_users) || (targetmap.config_max_users && players > targetmap.config_max_users))
|
||||
continue
|
||||
if(targetmap.max_round_search_span && count_occurences_of_value(lastmaps, M, targetmap.max_round_search_span) >= targetmap.max_rounds_played)
|
||||
continue
|
||||
choices |= M
|
||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||
choices.Add("secret", "extended")
|
||||
<<<<<<< HEAD
|
||||
if("dynamic")
|
||||
var/saved_threats = SSpersistence.saved_threat_levels
|
||||
if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150)
|
||||
choices.Add("extended",PEACE,CHAOS)
|
||||
else
|
||||
choices.Add(PEACE,CHAOS)
|
||||
=======
|
||||
>>>>>>> parent of b404e18b15... Merge branch 'master' into FERMICHEMCurTweaks
|
||||
if("custom")
|
||||
question = stripped_input(usr,"What is the vote for?")
|
||||
if(!question)
|
||||
@@ -411,4 +418,7 @@ SUBSYSTEM_DEF(vote)
|
||||
else if(owner.ckey)
|
||||
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
||||
if(P)
|
||||
P.player_actions -= src
|
||||
P.player_actions -= src
|
||||
|
||||
#undef PEACE
|
||||
#undef CHAOS
|
||||
|
||||
@@ -74,10 +74,10 @@ SUBSYSTEM_DEF(weather)
|
||||
next_hit_by_zlevel["[z]"] = null
|
||||
|
||||
/datum/controller/subsystem/weather/proc/get_weather(z, area/active_area)
|
||||
var/datum/weather/A
|
||||
for(var/V in processing)
|
||||
var/datum/weather/W = V
|
||||
if((z in W.impacted_z_levels) && W.area_type == active_area.type)
|
||||
A = W
|
||||
break
|
||||
return A
|
||||
var/datum/weather/A
|
||||
for(var/V in processing)
|
||||
var/datum/weather/W = V
|
||||
if((z in W.impacted_z_levels) && W.area_type == active_area.type)
|
||||
A = W
|
||||
break
|
||||
return A
|
||||
|
||||
Reference in New Issue
Block a user