diff --git a/.gitignore b/.gitignore
index ce50b70af5..f67727febb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
#Ignore everything in datafolder and subdirectories
/data/**/*
+/tmp/**/*
#Ignore byond config folder.
/cfg/**/*
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 136a52acf7..7744b24d0f 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -97,6 +97,11 @@
//Citadel istypes
#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
#define isipcperson(A) (is_species(A, /datum/species/ipc))
+#define ismammal(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/mammal) )
+#define isavian(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/avian) )
+#define isaquatic(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/aquatic) )
+#define isinsect(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/insect) )
+#define isxenoperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/xeno) )
#define CITADEL_MENTOR_OOC_COLOUR "#224724"
diff --git a/code/__DEFINES/research.dm b/code/__DEFINES/research.dm
index 16776ed8e2..95b89ae04e 100644
--- a/code/__DEFINES/research.dm
+++ b/code/__DEFINES/research.dm
@@ -71,3 +71,5 @@
#define TECHWEB_POINT_TYPE_LIST_ASSOCIATIVE_NAMES list(\
TECHWEB_POINT_TYPE_GENERIC = "General Research"\
)
+
+#define TECHWEB_BOMB_POINTCAP 50000 //Adjust as needed; Stops toxins from nullifying RND progression mechanics. Current Value Cap Radius: 100
diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm
index a905fd5186..ccd5b92c79 100644
--- a/code/__DEFINES/rust_g.dm
+++ b/code/__DEFINES/rust_g.dm
@@ -3,5 +3,8 @@
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
+#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
+#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
+
#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index b60894edea..f54a0542f4 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -51,6 +51,7 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
+#define INIT_ORDER_TITLE 20
#define INIT_ORDER_GARBAGE 19
#define INIT_ORDER_DBCORE 18
#define INIT_ORDER_BLACKBOX 17
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 84d4a40135..c3b7a6bfed 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -531,10 +531,11 @@
return
sync_ranks_with_db()
var/list/sql_admins = list()
- for(var/datum/admins/A in GLOB.protected_admins)
- var/sql_ckey = sanitizeSQL(A.owner.ckey)
+ for(var/i in GLOB.protected_admins)
+ var/datum/admins/A = GLOB.protected_admins[i]
+ var/sql_ckey = sanitizeSQL(A.target)
var/sql_rank = sanitizeSQL(A.rank.name)
- sql_admins = list(list("ckey" = "'[sql_ckey]'", "rank" = "'[sql_rank]'"))
+ sql_admins += list(list("ckey" = "'[sql_ckey]'", "rank" = "'[sql_rank]'"))
SSdbcore.MassInsert(format_table_name("admin"), sql_admins, duplicate_key = TRUE)
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] p INNER JOIN [format_table_name("admin")] a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
query_admin_rank_update.Execute()
@@ -582,4 +583,4 @@
qdel(query_update_everything_ranks)
return
qdel(query_update_everything_ranks)
- qdel(query_check_everything_ranks)
+ qdel(query_check_everything_ranks)
\ No newline at end of file
diff --git a/code/__HELPERS/typelists.dm b/code/__HELPERS/typelists.dm
new file mode 100644
index 0000000000..f271b9204d
--- /dev/null
+++ b/code/__HELPERS/typelists.dm
@@ -0,0 +1,43 @@
+GLOBAL_LIST_EMPTY(typelists)
+
+#ifndef TESTING
+
+/datum/proc/typelist(key, list/values = list())
+ var/list/mytypelist = GLOB.typelists[type] || (GLOB.typelists[type] = list())
+ return mytypelist[key] || (mytypelist[key] = values.Copy())
+
+#else
+// mostly the same code as above, just more verbose, slower and has tallying for saved lists
+/datum/proc/typelist(key, list/values)
+ if (!values)
+ values = list()
+ GLOB.typelistkeys |= key
+ if (GLOB.typelists[type])
+ if (GLOB.typelists[type][key])
+ GLOB.typelists[type]["[key]-saved"]++
+ return GLOB.typelists[type][key]
+ else
+ GLOB.typelists[type][key] = values.Copy()
+ else
+ GLOB.typelists[type] = list()
+ GLOB.typelists[type][key] = values.Copy()
+ return GLOB.typelists[type][key]
+
+GLOBAL_LIST_EMPTY(typelistkeys)
+
+/proc/tallytypelistsavings()
+ var/savings = list()
+ var/saveditems = list()
+ for (var/key in GLOB.typelistkeys)
+ savings[key] = 0
+ saveditems[key] = 0
+
+ for (var/type in GLOB.typelists)
+ for (var/saving in savings)
+ if (GLOB.typelists[type]["[saving]-saved"])
+ savings[saving] += GLOB.typelists[type]["[saving]-saved"]
+ saveditems[saving] += (GLOB.typelists[type]["[saving]-saved"] * length(GLOB.typelists[type][saving]))
+
+ for (var/saving in savings)
+ to_chat(world, "Savings for [saving]: [savings[saving]] lists, [saveditems[saving]] items")
+#endif
\ No newline at end of file
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 021ea298a8..0760b81927 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -164,4 +164,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"TRANSPARENT" = TRANSPARENT,
"AMOUNT_VISIBLE" = AMOUNT_VISIBLE,
),
+ "car_traits" = list(
+ "CAN_KIDNAP" = CAN_KIDNAP,
+ ),
))
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 0cc0c622d7..125da84a30 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -164,12 +164,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// Please don't stuff random bullshit here,
// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize()
-/datum/controller/master/Initialize(delay, init_sss)
+/datum/controller/master/Initialize(delay, init_sss, tgs_prime)
set waitfor = 0
if(delay)
sleep(delay)
+ if(tgs_prime)
+ world.TgsInitializationComplete()
+
if(init_sss)
init_subtypes(/datum/controller/subsystem, subsystems)
@@ -202,7 +205,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
world.fps = CONFIG_GET(number/fps)
var/initialized_tod = REALTIMEOFDAY
- world.TgsInitializationComplete()
if(sleep_offline_after_initializations)
world.sleep_offline = TRUE
sleep(1)
@@ -612,4 +614,4 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if (client_count < CONFIG_GET(number/mc_tick_rate/disable_high_pop_mc_mode_amount))
processing = CONFIG_GET(number/mc_tick_rate/base_mc_tick_rate)
else if (client_count > CONFIG_GET(number/mc_tick_rate/high_pop_mc_mode_amount))
- processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
+ processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
\ No newline at end of file
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 75d214722a..5e960e0f96 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -15,6 +15,7 @@ SUBSYSTEM_DEF(job)
var/overflow_role = "Assistant"
/datum/controller/subsystem/job/Initialize(timeofday)
+ SSmapping.HACK_LoadMapConfig()
if(!occupations.len)
SetupOccupations()
if(CONFIG_GET(flag/load_jobs_from_txt))
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 3a25d889e0..9b70cb9117 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -34,17 +34,17 @@ SUBSYSTEM_DEF(mapping)
var/datum/space_level/transit
var/datum/space_level/empty_space
-/datum/controller/subsystem/mapping/PreInit()
+//dlete dis once #39770 is resolved
+/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
if(!config)
#ifdef FORCE_MAP
config = load_map_config(FORCE_MAP)
#else
config = load_map_config(error_if_missing = FALSE)
#endif
- return ..()
-
/datum/controller/subsystem/mapping/Initialize(timeofday)
+ HACK_LoadMapConfig()
if(initialized)
return
if(config.defaulted)
@@ -493,4 +493,4 @@ GLOBAL_LIST_EMPTY(the_station_areas)
clearing |= used_turfs //used turfs is an associative list, BUT, reserve_turfs() can still handle it. If the code above works properly, this won't even be needed as the turfs would be freed already.
unused_turfs.Cut()
used_turfs.Cut()
- reserve_turfs(clearing)
+ reserve_turfs(clearing)
\ No newline at end of file
diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm
index 94dff9b742..b19cf47693 100644
--- a/code/controllers/subsystem/title.dm
+++ b/code/controllers/subsystem/title.dm
@@ -1,13 +1,14 @@
SUBSYSTEM_DEF(title)
name = "Title Screen"
- flags = SS_NO_FIRE|SS_NO_INIT
+ flags = SS_NO_FIRE
+ init_order = INIT_ORDER_TITLE
var/file_path
var/icon/icon
var/icon/previous_icon
var/turf/closed/indestructible/splashscreen/splash_turf
-/datum/controller/subsystem/title/PreInit()
+/datum/controller/subsystem/title/Initialize()
if(file_path && icon)
return
@@ -21,6 +22,7 @@ SUBSYSTEM_DEF(title)
var/list/title_screens = list()
var/use_rare_screens = prob(1)
+ SSmapping.HACK_LoadMapConfig()
for(var/S in provisional_title_screens)
var/list/L = splittext(S,"+")
if((L.len == 1 && L[1] != "blank.png")|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name)))))
@@ -39,6 +41,8 @@ SUBSYSTEM_DEF(title)
if(splash_turf)
splash_turf.icon = icon
+ return ..()
+
/datum/controller/subsystem/title/vv_edit_var(var_name, var_value)
. = ..()
if(.)
@@ -62,4 +66,4 @@ SUBSYSTEM_DEF(title)
icon = SStitle.icon
splash_turf = SStitle.splash_turf
file_path = SStitle.file_path
- previous_icon = SStitle.previous_icon
+ previous_icon = SStitle.previous_icon
\ No newline at end of file
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 46de2c5c92..a719223ea7 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -1,44 +1,40 @@
/datum/getrev
- var/originmastercommit
- var/commit
- var/list/testmerge = list()
+ var/commit // git rev-parse HEAD
var/date
+ var/originmastercommit // git rev-parse origin/master
+ var/list/testmerge = list()
/datum/getrev/New()
testmerge = world.TgsTestMerges()
- log_world("Running /tg/ revision:")
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
else
- var/list/logs = world.file2list(".git/logs/HEAD")
- if(logs.len)
- logs = splittext(logs[logs.len - 1], " ")
- date = unix2date(text2num(logs[5]))
- commit = logs[2]
- log_world("[commit]: [date]")
- else
- log_world("Unable to read git logs, revision information not available")
- originmastercommit = commit = "Unknown"
- date = unix2date(world.timeofday)
- return
- logs = world.file2list(".git/logs/refs/remotes/origin/master")
- if(logs.len)
- originmastercommit = splittext(logs[logs.len - 1], " ")[2]
+ commit = rustg_git_revparse("HEAD")
+ if(commit)
+ date = rustg_git_commit_date(commit)
+ originmastercommit = rustg_git_revparse("origin/master")
- if(testmerge.len)
- log_world(commit)
- for(var/line in testmerge)
- if(line)
- var/datum/tgs_revision_information/test_merge/tm = line
- var/tmcommit = tm.commit
- log_world("Test merge active of PR #[tm.number] commit [tmcommit]")
- SSblackbox.record_feedback("nested tally", "testmerged_prs", 1, list("[tm.number]", "[tmcommit]"))
- if(originmastercommit)
- log_world("Based off origin/master commit [originmastercommit]")
- else if(originmastercommit)
- log_world(originmastercommit)
+ // goes to DD log and config_error.txt
+ log_world(get_log_message())
+
+/datum/getrev/proc/get_log_message()
+ var/list/msg = list()
+ msg += "Running /tg/ revision: [date]"
+ if(originmastercommit)
+ msg += "origin/master: [originmastercommit]"
+
+ for(var/line in testmerge)
+ var/datum/tgs_revision_information/test_merge/tm = line
+ msg += "Test merge active of PR #[tm.number] commit [tm.commit]"
+
+ if(commit && commit != originmastercommit)
+ msg += "HEAD: [commit]"
+ else if(!originmastercommit)
+ msg += "No commit information"
+
+ return msg.Join("\n")
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
if(!testmerge.len)
@@ -57,28 +53,34 @@
set name = "Show Server Revision"
set desc = "Check the current server code revision"
+ var/list/msg = list("")
+ // Round ID
if(GLOB.round_id)
- to_chat(src, "Round ID: [GLOB.round_id]")
- if(GLOB.revdata.originmastercommit)
- to_chat(src, "Server revision compiled on: [GLOB.revdata.date]")
- var/prefix = ""
- if(GLOB.revdata.testmerge.len)
- to_chat(src, GLOB.revdata.GetTestMergeInfo())
- prefix = "Based off origin/master commit: "
- var/pc = GLOB.revdata.originmastercommit
- to_chat(src, "[prefix][copytext(pc, 1, min(length(pc), 11))]")
- else
- to_chat(src, "Master revision unknown")
- to_chat(src, "Revision: [GLOB.revdata.commit]")
+ msg += "Round ID: [GLOB.round_id]"
+
+ // Revision information
+ var/datum/getrev/revdata = GLOB.revdata
+ msg += "Server revision compiled on: [revdata.date]"
+ var/pc = revdata.originmastercommit
+ if(pc)
+ msg += "Master commit: [pc]"
+ if(revdata.testmerge.len)
+ msg += revdata.GetTestMergeInfo()
+ if(revdata.commit && revdata.commit != revdata.originmastercommit)
+ msg += "Local commit: [revdata.commit]"
+ else if(!pc)
+ msg += "No commit information"
if(world.TgsAvailable())
- to_chat(src, "Server tools version: [world.TgsVersion()]")
- to_chat(src, "Current Informational Settings:")
- to_chat(src, "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]")
- to_chat(src, "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]")
- to_chat(src, "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]")
- to_chat(src, "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]")
- to_chat(src, "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_list/continuous))] of [config.modes.len] roundtypes")
- to_chat(src, "Allow Midround Antagonists: [length(CONFIG_GET(keyed_list/midround_antag))] of [config.modes.len] roundtypes")
+ msg += "Server tools version: [world.TgsVersion()]"
+
+ // Game mode odds
+ msg += "
Current Informational Settings:"
+ msg += "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]"
+ msg += "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]"
+ msg += "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]"
+ msg += "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]"
+ msg += "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_list/continuous))] of [config.modes.len] roundtypes"
+ msg += "Allow Midround Antagonists: [length(CONFIG_GET(keyed_list/midround_antag))] of [config.modes.len] roundtypes"
if(CONFIG_GET(flag/show_game_type_odds))
var/list/probabilities = CONFIG_GET(keyed_list/probability)
if(SSticker.IsRoundInProgress())
@@ -99,17 +101,18 @@
probs[ctag] = 1
prob_sum += probabilities[ctag]
if(current_odds_differ)
- to_chat(src, "Game Mode Odds for current round:")
+ msg += "Game Mode Odds for current round:"
for(var/ctag in probs)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / prob_sum * 100, 0.1)
- to_chat(src, "[ctag] [percentage]%")
+ msg += "[ctag] [percentage]%"
- to_chat(src, "All Game Mode Odds:")
+ msg += "All Game Mode Odds:"
var/sum = 0
for(var/ctag in probabilities)
sum += probabilities[ctag]
for(var/ctag in probabilities)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
- to_chat(src, "[ctag] [percentage]%")
+ msg += "[ctag] [percentage]%"
+ to_chat(src, msg.Join("
"))
\ No newline at end of file
diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm
index 8e6ce98fc7..39f6555db0 100644
--- a/code/datums/shuttles.dm
+++ b/code/datums/shuttles.dm
@@ -28,26 +28,30 @@
if(!cached_map)
return
+ discover_port_offset()
+
+ if(!cache)
+ cached_map = null
+
+/datum/map_template/shuttle/proc/discover_port_offset()
var/key
var/list/models = cached_map.grid_models
for(key in models)
if(findtext(models[key], "[/obj/docking_port/mobile]")) // Yay compile time checks
break // This works by assuming there will ever only be one mobile dock in a template at most
-
- var/datum/grid_set/gset
+
for(var/i in cached_map.gridSets)
- gset = i
+ var/datum/grid_set/gset = i
var/ycrd = gset.ycrd
for(var/line in gset.gridLines)
- if(key != line)
- ycrd--
- continue
- port_x_offset = gset.xcrd
- port_y_offset = ycrd
- break
-
- if(!cache)
- cached_map = null
+ var/xcrd = gset.xcrd
+ for(var/j in 1 to length(line) step cached_map.key_len)
+ if(key == copytext(line, j, j + cached_map.key_len))
+ port_x_offset = xcrd
+ port_y_offset = ycrd
+ return
+ ++xcrd
+ --ycrd
/datum/map_template/shuttle/load(turf/T, centered, register=TRUE)
. = ..()
@@ -67,7 +71,7 @@
if(register)
port.register()
if(isnull(port_x_offset))
- return
+ continue
switch(port.dir) // Yeah this looks a little ugly but mappers had to do this in their head before
if(NORTH)
port.width = width
@@ -519,4 +523,4 @@
/datum/map_template/shuttle/snowdin/excavation
suffix = "excavation"
- name = "Snowdin Excavation Elevator"
+ name = "Snowdin Excavation Elevator"
\ No newline at end of file
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 4689361e71..2af31607ea 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -74,6 +74,9 @@
var/turf/T = loc
T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways.
+ if (canSmoothWith)
+ canSmoothWith = typelist("canSmoothWith", canSmoothWith)
+
ComponentInitialize()
return INITIALIZE_HINT_NORMAL
@@ -694,9 +697,10 @@ Proc for attack log creation, because really why not
/atom/movable/proc/get_filter(name)
if(filter_data && filter_data[name])
return filters[filter_data.Find(name)]
-
+
/atom/movable/proc/remove_filter(name)
if(filter_data[name])
filter_data -= name
update_filters()
return TRUE
+
\ No newline at end of file
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 84059e8029..5a54ccd5df 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -201,6 +201,7 @@
else
for(var/i=1, i<=multiplier, i++)
var/obj/item/new_item = new being_built.build_path(A)
+ new_item.materials = new_item.materials.Copy()
for(var/mat in materials_used)
new_item.materials[mat] = materials_used[mat] / multiplier
new_item.autolathe_crafted(src)
@@ -379,4 +380,4 @@
//Called when the object is constructed by an autolathe
//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
/obj/item/proc/autolathe_crafted(obj/machinery/autolathe/A)
- return
+ return
\ No newline at end of file
diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm
index 9d522f8f1c..7fb240c711 100644
--- a/code/game/machinery/doppler_array.dm
+++ b/code/game/machinery/doppler_array.dm
@@ -111,22 +111,39 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
return FALSE
if(!istype(linked_techweb))
say("Warning: No linked research system!")
- return
- var/adjusted = orig_light - 10
- if(adjusted <= 0)
+ return
+
+ var/point_gain = 0
+
+ /*****The Point Calculator*****/
+
+ if(orig_light < 10)
say("Explosion not large enough for research calculations.")
return
- var/point_gain = techweb_scale_bomb(adjusted) - techweb_scale_bomb(linked_techweb.max_bomb_value)
- if(point_gain <= 0)
- say("Explosion not large enough for research calculations.")
+ else if(orig_light < 4500)
+ point_gain = (83300 * orig_light) / (orig_light + 3000)
+ else
+ point_gain = TECHWEB_BOMB_POINTCAP
+
+ /*****The Point Capper*****/
+ if(point_gain > linked_techweb.largest_bomb_value)
+ if(point_gain <= TECHWEB_BOMB_POINTCAP || linked_techweb.largest_bomb_value < TECHWEB_BOMB_POINTCAP)
+ var/old_tech_largest_bomb_value = linked_techweb.largest_bomb_value //held so we can pull old before we do math
+ linked_techweb.largest_bomb_value = point_gain
+ point_gain -= old_tech_largest_bomb_value
+ point_gain = min(point_gain,TECHWEB_BOMB_POINTCAP)
+ else
+ linked_techweb.largest_bomb_value = TECHWEB_BOMB_POINTCAP
+ point_gain = 1000
+
+ linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, point_gain)
+ say("Gained [point_gain] points from explosion dataset.")
+
+ else //you've made smaller bombs
+ say("Data already captured. Aborting.")
return
- linked_techweb.max_bomb_value = adjusted
- linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, point_gain)
- say("Gained [point_gain] points from explosion dataset.")
+
/obj/machinery/doppler_array/research/science/Initialize()
. = ..()
- linked_techweb = SSresearch.science_tech
-
-/proc/techweb_scale_bomb(lightradius)
- return (lightradius ** 0.5) * 3000
+ linked_techweb = SSresearch.science_tech
\ No newline at end of file
diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm
index 6b78ca0319..a1ed7fb848 100644
--- a/code/game/machinery/syndicatebeacon.dm
+++ b/code/game/machinery/syndicatebeacon.dm
@@ -86,7 +86,7 @@
if(!active)
return
- if(surplus() > 1500)
+ if(surplus() >= 1500)
add_load(1500)
if(cooldown <= world.time)
cooldown = world.time + 80
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index cb8386d8b2..455f4f4ab1 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -110,8 +110,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
/obj/item/Initialize()
- if (!materials)
- materials = list()
+
+ materials = typelist("materials", materials)
+
+ if (attack_verb)
+ attack_verb = typelist("attack_verb", attack_verb)
+
. = ..()
for(var/path in actions_types)
new path(src)
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index 1a5c7a9b43..5276655dda 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -122,8 +122,8 @@
// found a powernet, so drain up to max power from it
- var/drained = min ( drain_rate, PN.avail )
- PN.load += drained
+ var/drained = min ( drain_rate, attached.newavail() )
+ attached.add_delayedload(drained)
power_drained += drained
// if tried to drain more than available on powernet
@@ -137,6 +137,8 @@
power_drained += 50
if(A.charging == 2) // If the cell was full
A.charging = 1 // It's no longer full
+ if(drained >= drain_rate)
+ break
if(power_drained > max_power * 0.98)
if (!admins_warned)
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index dc5219b9ec..93ce26e0ae 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -270,8 +270,8 @@
var/obj/structure/cable/C = T.get_cable_node()
if(C)
playsound(src, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 3, C.powernet.avail * 0.01, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN | TESLA_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
- C.powernet.load += C.powernet.avail * 0.0375 // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock.
+ tesla_zap(src, 3, C.newavail() * 0.01, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN | TESLA_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
+ C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock.
return ..()
/obj/structure/grille/get_dumping_location(datum/component/storage/source,mob/user)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index f00fd08ee5..3dcf91ae8f 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -18,7 +18,6 @@
var/glass_type = /obj/item/stack/sheet/glass
var/glass_amount = 1
var/mutable_appearance/crack_overlay
- var/list/debris = list()
can_be_unanchored = TRUE
resistance_flags = ACID_PROOF
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
@@ -27,7 +26,6 @@
var/breaksound = "shatter"
var/hitsound = 'sound/effects/Glasshit.ogg'
var/rad_insulation = RAD_VERY_LIGHT_INSULATION
- var/spawn_cleanable_shards = TRUE
/obj/structure/window/examine(mob/user)
..()
@@ -56,22 +54,8 @@
ini_dir = dir
air_update_turf(1)
- // Precreate our own debris
-
- var/shards = 1
if(fulltile)
- shards++
setDir()
- var/rods = 0
- if(reinf)
- rods++
- if(fulltile)
- rods++
-
- for(var/i in 1 to shards)
- debris += new /obj/item/shard(src)
- if(rods)
- debris += new /obj/item/stack/rods(src, rods)
//windows only block while reinforced and fulltile, so we'll use the proc
real_explosion_block = explosion_block
@@ -98,8 +82,6 @@
/obj/structure/window/narsie_act()
add_atom_colour(NARSIE_WINDOW_COLOUR, FIXED_COLOUR_PRIORITY)
- for(var/obj/item/shard/shard in debris)
- shard.add_atom_colour(NARSIE_WINDOW_COLOUR, FIXED_COLOUR_PRIORITY)
/obj/structure/window/ratvar_act()
if(!fulltile)
@@ -288,16 +270,17 @@
if(!disassembled)
playsound(src, breaksound, 70, 1)
if(!(flags_1 & NODECONSTRUCT_1))
- if(spawn_cleanable_shards)
- new /obj/effect/decal/cleanable/glass(get_turf(src))
- for(var/i in debris)
- var/obj/item/I = i
- I.forceMove(drop_location())
- transfer_fingerprints_to(I)
- debris -= I
+ for(var/obj/item/shard/debris in spawnDebris(drop_location()))
+ transfer_fingerprints_to(debris) // transfer fingerprints to shards only
qdel(src)
update_nearby_icons()
+/obj/structure/window/proc/spawnDebris(location)
+ . = list()
+ . += new /obj/item/shard(location)
+ . += new /obj/effect/decal/cleanable/glass(location)
+ if (reinf)
+ . += new /obj/item/stack/rods(location, (fulltile ? 2 : 1))
/obj/structure/window/proc/can_be_rotated(mob/user,rotation_type)
if(anchored)
@@ -425,7 +408,6 @@
explosion_block = 1
glass_type = /obj/item/stack/sheet/plasmaglass
rad_insulation = RAD_NO_INSULATION
- spawn_cleanable_shards = FALSE
/obj/structure/window/plasma/spawner/east
dir = EAST
@@ -521,7 +503,6 @@
fulltile = TRUE
flags_1 = PREVENT_CLICK_UNDER_1
smooth = SMOOTH_TRUE
-
canSmoothWith = list(/obj/structure/window/fulltile, /obj/structure/window/reinforced/fulltile, /obj/structure/window/reinforced/tinted/fulltile, /obj/structure/window/plasma/fulltile, /obj/structure/window/plasma/reinforced/fulltile)
level = 3
glass_amount = 2
@@ -616,18 +597,15 @@
var/made_glow = FALSE
/obj/structure/window/reinforced/clockwork/Initialize(mapload, direct)
- if(fulltile)
- made_glow = TRUE
. = ..()
- QDEL_LIST(debris)
- var/amount_of_gears = 2
- if(fulltile)
- new /obj/effect/temp_visual/ratvar/window(get_turf(src))
- amount_of_gears = 4
- for(var/i in 1 to amount_of_gears)
- debris += new /obj/item/clockwork/alloy_shards/medium/gear_bit()
change_construction_value(fulltile ? 2 : 1)
+/obj/structure/window/reinforced/clockwork/spawnDebris(location)
+ . = list()
+ var/gearcount = fulltile ? 4 : 2
+ for(var/i in 1 to gearcount)
+ . += new /obj/item/clockwork/alloy_shards/medium/gear_bit(location)
+
/obj/structure/window/reinforced/clockwork/setDir(direct)
if(!made_glow)
var/obj/effect/E = new /obj/effect/temp_visual/ratvar/window/single(get_turf(src))
@@ -646,7 +624,7 @@
/obj/structure/window/reinforced/clockwork/narsie_act()
take_damage(rand(25, 75), BRUTE)
- if(src)
+ if(!QDELETED(src))
var/previouscolor = color
color = "#960000"
animate(src, color = previouscolor, time = 8)
@@ -666,6 +644,17 @@
level = 3
glass_amount = 2
+/obj/structure/window/reinforced/clockwork/spawnDebris(location)
+ . = list()
+ for(var/i in 1 to 4)
+ . += new /obj/item/clockwork/alloy_shards/medium/gear_bit(location)
+
+/obj/structure/window/reinforced/clockwork/Initialize(mapload, direct)
+ made_glow = TRUE
+ new /obj/effect/temp_visual/ratvar/window(get_turf(src))
+ return ..()
+
+
/obj/structure/window/reinforced/clockwork/fulltile/unanchored
anchored = FALSE
@@ -687,7 +676,6 @@
decon_speed = 10
CanAtmosPass = ATMOS_PASS_YES
resistance_flags = FLAMMABLE
- spawn_cleanable_shards = FALSE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
breaksound = 'sound/items/poster_ripped.ogg'
hitsound = 'sound/weapons/slashmiss.ogg'
@@ -696,13 +684,13 @@
/obj/structure/window/paperframe/Initialize()
. = ..()
- QDEL_LIST(debris)
- var/papers = rand(1,4)
- debris += new /obj/item/stack/sheet/mineral/wood()
- for(var/i in 1 to papers)
- debris += new /obj/item/paper/natural()
update_icon()
+/obj/structure/window/paperframe/spawnDebris(location)
+ . = list(new /obj/item/stack/sheet/mineral/wood(location))
+ for (var/i in 1 to rand(1,4))
+ . += new /obj/item/paper/natural(location)
+
/obj/structure/window/paperframe/attack_hand(mob/user)
. = ..()
if(.)
@@ -747,4 +735,4 @@
update_icon()
return
..()
- update_icon()
+ update_icon()
\ No newline at end of file
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 777cbedd26..f658cafbeb 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -22,10 +22,8 @@
tiled_dirt = TRUE
/turf/open/floor/Initialize(mapload)
- if (!broken_states)
- broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
- if (!burnt_states)
- burnt_states = list()
+ broken_states = typelist("broken_states", broken_states)
+ burnt_states = typelist("burnt_states", burnt_states)
if(!broken && broken_states && (icon_state in broken_states))
broken = TRUE
if(!burnt && burnt_states && (icon_state in burnt_states))
diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm
index a470e3e0a1..a77417e4e4 100644
--- a/code/game/turfs/simulated/floor/mineral_floor.dm
+++ b/code/game/turfs/simulated/floor/mineral_floor.dm
@@ -20,8 +20,7 @@
if(!broken_states)
broken_states = list("[initial(icon_state)]_dam")
. = ..()
- if (!icons)
- icons = list()
+ icons = typelist("icons", icons)
/turf/open/floor/mineral/update_icon()
diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm
index 61c7950e88..0004a4485b 100644
--- a/code/game/turfs/simulated/minerals.dm
+++ b/code/game/turfs/simulated/minerals.dm
@@ -131,17 +131,17 @@
T.ChangeTurf(type)
/turf/closed/mineral/random
- var/mineralSpawnChanceList
+ var/list/mineralSpawnChanceList = list(/turf/closed/mineral/uranium = 5, /turf/closed/mineral/diamond = 1, /turf/closed/mineral/gold = 10,
+ /turf/closed/mineral/silver = 12, /turf/closed/mineral/plasma = 20, /turf/closed/mineral/iron = 40, /turf/closed/mineral/titanium = 11,
+ /turf/closed/mineral/gibtonite = 4, /turf/open/floor/plating/asteroid/airless/cave = 2, /turf/closed/mineral/bscrystal = 1)
//Currently, Adamantine won't spawn as it has no uses. -Durandan
var/mineralChance = 13
var/display_icon_state = "rock"
/turf/closed/mineral/random/Initialize()
- if (!mineralSpawnChanceList)
- mineralSpawnChanceList = list(
- /turf/closed/mineral/uranium = 5, /turf/closed/mineral/diamond = 1, /turf/closed/mineral/gold = 10,
- /turf/closed/mineral/silver = 12, /turf/closed/mineral/plasma = 20, /turf/closed/mineral/iron = 40, /turf/closed/mineral/titanium = 11,
- /turf/closed/mineral/gibtonite = 4, /turf/open/floor/plating/asteroid/airless/cave = 2, /turf/closed/mineral/bscrystal = 1)
+
+ mineralSpawnChanceList = typelist("mineralSpawnChanceList", mineralSpawnChanceList)
+
if (display_icon_state)
icon_state = display_icon_state
. = ..()
@@ -522,4 +522,4 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
- defer_change = 1
+ defer_change = 1
\ No newline at end of file
diff --git a/code/game/world.dm b/code/game/world.dm
index 26c01c63c4..e83a01e7f2 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -10,7 +10,7 @@ GLOBAL_VAR(restart_counter)
SetupExternalRSC()
- GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
+ GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
@@ -48,7 +48,7 @@ GLOBAL_VAR(restart_counter)
cit_initialize()
- Master.Initialize(10, FALSE)
+ Master.Initialize(10, FALSE, TRUE)
if(TEST_RUN_PARAMETER in params)
HandleTestRun()
@@ -133,6 +133,11 @@ GLOBAL_VAR(restart_counter)
if(GLOB.round_id)
log_game("Round ID: [GLOB.round_id]")
+ // This was printed early in startup to the world log and config_error.log,
+ // but those are both private, so let's put the commit info in the runtime
+ // log which is ultimately public.
+ log_runtime(GLOB.revdata.get_log_message())
+
/world/Topic(T, addr, master, key)
TGS_TOPIC //redirect to server tools if necessary
diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm
index 7905a8d155..be79dce06e 100644
--- a/code/modules/admin/NewBan.dm
+++ b/code/modules/admin/NewBan.dm
@@ -61,7 +61,9 @@ GLOBAL_PROTECT(Banlist)
return 1
/proc/LoadBans()
-
+ if(!CONFIG_GET(flag/ban_legacy_system))
+ return
+
GLOB.Banlist = new("data/banlist.bdb")
log_admin("Loading Banlist")
diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm
index 45a643dcac..72ec3da8f9 100644
--- a/code/modules/admin/sql_message_system.dm
+++ b/code/modules/admin/sql_message_system.dm
@@ -554,6 +554,9 @@
#define NOTESFILE "data/player_notes.sav"
//if the AUTOCONVERT_NOTES is turned on, anytime a player connects this will be run to try and add all their notes to the databas
/proc/convert_notes_sql(ckey)
+ if(!fexists(NOTESFILE))
+ return
+
var/savefile/notesfile = new(NOTESFILE)
if(!notesfile)
log_game("Error: Cannot access [NOTESFILE]")
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 0c592c65e7..aff0292b87 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -147,10 +147,9 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/proc/do_invoke_glow()
set waitfor = FALSE
- var/oldtransform = transform
animate(src, transform = matrix()*2, alpha = 0, time = 5, flags = ANIMATION_END_NOW) //fade out
sleep(5)
- animate(src, transform = oldtransform, alpha = 255, time = 0, flags = ANIMATION_END_NOW)
+ animate(src, transform = matrix(), alpha = 255, time = 0, flags = ANIMATION_END_NOW)
/obj/effect/rune/proc/fail_invoke()
//This proc contains the effects of a rune if it is not invoked correctly, through either invalid wording or not enough cultists. By default, it's just a basic fizzle.
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index ba50a8396e..463df71f71 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -3,7 +3,7 @@ For the main html chat area
*********************************/
//Precaching a bunch of shit
-GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of icons for the browser output
+GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of icons for the browser output
//On client, created on login
/datum/chatOutput
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 1633e42752..312fc315e9 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -916,6 +916,9 @@
/mob/living/carbon/human/species/dullahan
race = /datum/species/dullahan
+/mob/living/carbon/human/species/felinid
+ race = /datum/species/human/felinid
+
/mob/living/carbon/human/species/fly
race = /datum/species/fly
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 320b75b052..2dad832aa4 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -209,13 +209,22 @@
/datum/emote/living/laugh/run_emote(mob/user, params)
. = ..()
- if(. && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.dna.species.id == "human" && (!H.mind || !H.mind.miming))
+ if(. && iscarbon(user)) //Citadel Edit because this is hilarious
+ var/mob/living/carbon/C = user
+ if(!C.mind || C.mind.miming)
+ return
+ if(iscatperson(C)) //we ask for is cat first because they're a subtype that tests true for ishumanbasic because HERESY
+ playsound(C, pick('sound/voice/catpeople/nyahaha1.ogg',
+ 'sound/voice/catpeople/nyahaha2.ogg',
+ 'sound/voice/catpeople/nyaha.ogg',
+ 'sound/voice/catpeople/nyahehe.ogg'),
+ 50, 1)
+ return
+ if(ishumanbasic(C))
if(user.gender == FEMALE)
- playsound(H, 'sound/voice/human/womanlaugh.ogg', 50, 1)
+ playsound(C, 'sound/voice/human/womanlaugh.ogg', 50, 1)
else
- playsound(H, pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg'), 50, 1)
+ playsound(C, pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg'), 50, 1)
/datum/emote/living/look
key = "look"
diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm
index 8b9abbee7a..861ffb9446 100644
--- a/code/modules/ninja/suit/ninjaDrainAct.dm
+++ b/code/modules/ninja/suit/ninjaDrainAct.dm
@@ -169,8 +169,8 @@ They *could* go in their appropriate files, but this is supposed to be modular
drain = (round((rand(G.mindrain, G.maxdrain))/2))
var/drained = 0
if(PN && do_after(H,10, target = src))
- drained = min(drain, PN.avail)
- PN.load += drained
+ drained = min(drain, delayed_surplus())
+ add_delayedload(drained)
if(drained < drain)//if no power on net, drain apcs
for(var/obj/machinery/power/terminal/T in PN.nodes)
if(istype(T.master, /obj/machinery/power/apc))
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index f48826df9d..3d466d9448 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1104,7 +1104,7 @@
/obj/machinery/power/apc/add_load(amount)
if(terminal && terminal.powernet)
- terminal.powernet.load += amount
+ terminal.add_load(amount)
/obj/machinery/power/apc/avail()
if(terminal)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 7060edecbd..7b3b2ba7bd 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -199,6 +199,10 @@ By design, d1 is the smallest direction and d2 is the highest
// Power related
///////////////////////////////////////////
+// All power generation handled in add_avail()
+// Machines should use add_load(), surplus(), avail()
+// Non-machines should use add_delayedload(), delayed_surplus(), newavail()
+
/obj/structure/cable/proc/add_avail(amount)
if(powernet)
powernet.newavail += amount
@@ -209,7 +213,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/surplus()
if(powernet)
- return powernet.avail-powernet.load
+ return CLAMP(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
@@ -219,6 +223,22 @@ By design, d1 is the smallest direction and d2 is the highest
else
return 0
+/obj/structure/cable/proc/add_delayedload(amount)
+ if(powernet)
+ powernet.delayedload += amount
+
+/obj/structure/cable/proc/delayed_surplus()
+ if(powernet)
+ return CLAMP(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
+ else
+ return 0
+
+/obj/structure/cable/proc/newavail()
+ if(powernet)
+ return powernet.newavail
+ else
+ return 0
+
/////////////////////////////////////////////////
// Cable laying helpers
////////////////////////////////////////////////
@@ -828,4 +848,4 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/cut/random
item_color = null
- color = "#ffffff"
+ color = "#ffffff"
\ No newline at end of file
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index f6110cb081..58a259de3a 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -25,6 +25,10 @@
//////////////////////////////
// common helper procs for all power machines
+// All power generation handled in add_avail()
+// Machines should use add_load(), surplus(), avail()
+// Non-machines should use add_delayedload(), delayed_surplus(), newavail()
+
/obj/machinery/power/proc/add_avail(amount)
if(powernet)
powernet.newavail += amount
@@ -38,7 +42,7 @@
/obj/machinery/power/proc/surplus()
if(powernet)
- return powernet.avail - powernet.load
+ return CLAMP(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
@@ -48,6 +52,22 @@
else
return 0
+/obj/machinery/power/proc/add_delayedload(amount)
+ if(powernet)
+ powernet.delayedload += amount
+
+/obj/machinery/power/proc/delayed_surplus()
+ if(powernet)
+ return CLAMP(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
+ else
+ return 0
+
+/obj/machinery/power/proc/newavail()
+ if(powernet)
+ return powernet.newavail
+ else
+ return 0
+
/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
return
@@ -341,7 +361,7 @@
source_area.use_power(drained_energy/GLOB.CELLRATE)
else if (istype(power_source, /datum/powernet))
var/drained_power = drained_energy/GLOB.CELLRATE //convert from "joules" to "watts"
- PN.load+=drained_power
+ PN.delayedload += (min(drained_power, max(PN.newavail - PN.delayedload, 0)))
else if (istype(power_source, /obj/item/stock_parts/cell))
cell.use(drained_energy)
return drained_energy
@@ -364,4 +384,4 @@
/area/proc/get_apc()
for(var/obj/machinery/power/apc/APC in GLOB.apcs_list)
if(APC.area == src)
- return APC
+ return APC
\ No newline at end of file
diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm
index c34edc53f3..3b70383bee 100644
--- a/code/modules/power/powernet.dm
+++ b/code/modules/power/powernet.dm
@@ -13,6 +13,7 @@
var/viewavail = 0 // the available power as it appears on the power console (gradually updated)
var/viewload = 0 // the load as it appears on the power console (gradually updated)
var/netexcess = 0 // excess power on the powernet (typically avail-load)///////
+ var/delayedload = 0 // load applied to powernet between power ticks.
/datum/powernet/New()
SSmachines.powernets += src
@@ -88,7 +89,8 @@
viewload = round(0.8 * viewload + 0.2 * load)
// reset the powernet
- load = 0
+ load = delayedload
+ delayedload = 0
avail = newavail
newavail = 0
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index eebdd5c9da..9d2ad4c12a 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -160,7 +160,7 @@
update_icon()
return
if(active == TRUE)
- if(!active_power_usage || avail(active_power_usage))
+ if(!active_power_usage || surplus() >= active_power_usage)
add_load(active_power_usage)
if(!powered)
powered = TRUE
@@ -189,7 +189,7 @@
return FALSE
if(state != EMITTER_WELDED)
return FALSE
- if(avail(active_power_usage))
+ if(surplus() >= active_power_usage)
add_load(active_power_usage)
fire_beam()
@@ -495,4 +495,4 @@
#undef EMITTER_UNWRENCHED
#undef EMITTER_WRENCHED
-#undef EMITTER_WELDED
+#undef EMITTER_WELDED
\ No newline at end of file
diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm
index f11b0ad709..dbfca477d6 100644
--- a/code/modules/research/techweb/_techweb.dm
+++ b/code/modules/research/techweb/_techweb.dm
@@ -16,7 +16,7 @@
var/list/obj/machinery/computer/rdconsole/consoles_accessing = list()
var/id = "generic"
var/list/research_logs = list() //IC logs.
- var/max_bomb_value = 0
+ var/largest_bomb_value = 0
var/organization = "Third-Party" //Organization name, used for display.
var/list/last_bitcoins = list() //Current per-second production, used for display only.
var/list/tiers = list() //Assoc list, datum = number, 1 is available, 2 is all reqs are 1, so on
diff --git a/config/game_options.txt b/config/game_options.txt
index f4d76c670c..3a1febf6dd 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -411,6 +411,7 @@ ROUNDSTART_RACES lizard
#ROUNDSTART_RACES moth
ROUNDSTART_RACES plasmaman
#ROUNDSTART_RACES shadow
+ROUNDSTART_RACES felinid
## Races that are better than humans in some ways, but worse in others
#ROUNDSTART_RACES jelly
diff --git a/dependencies.sh b/dependencies.sh
index 12fce4e866..59f84f145a 100644
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -10,10 +10,10 @@ export BYOND_MAJOR=512
export BYOND_MINOR=1441
#rust_g git tag
-export RUST_G_VERSION=0.4.0
+export RUST_G_VERSION=0.4.1
#bsql git tag
export BSQL_VERSION=v1.4.0.0
#node version
-export NODE_VERSION=4
+export NODE_VERSION=8
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human.dm b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
new file mode 100644
index 0000000000..fcdaa9caad
--- /dev/null
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
@@ -0,0 +1,14 @@
+/mob/living/carbon/human/species/mammal
+ race = /datum/species/human/mammal
+
+/mob/living/carbon/human/species/avian
+ race = /datum/species/human/avian
+
+/mob/living/carbon/human/species/aquatic
+ race = /datum/species/human/aquatic
+
+/mob/living/carbon/human/species/insect
+ race = /datum/species/human/insect
+
+/mob/living/carbon/human/species/xeno
+ race = /datum/species/human/xeno
\ No newline at end of file
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index ef3c9487ba..ece58dcf3a 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -52,6 +52,7 @@
/datum/species/mammal/on_species_loss(mob/living/carbon/human/C)
C.draw_citadel_parts(TRUE)
. = ..()
+
//AVIAN//
/datum/species/avian
name = "Avian"
diff --git a/rust_g.dll b/rust_g.dll
index 44e38ef0dd..ec072b01b0 100644
Binary files a/rust_g.dll and b/rust_g.dll differ
diff --git a/sound/voice/catpeople/nyaha.ogg b/sound/voice/catpeople/nyaha.ogg
new file mode 100644
index 0000000000..d7a6de4ab7
Binary files /dev/null and b/sound/voice/catpeople/nyaha.ogg differ
diff --git a/sound/voice/catpeople/nyahaha1.ogg b/sound/voice/catpeople/nyahaha1.ogg
new file mode 100644
index 0000000000..73a79470fe
Binary files /dev/null and b/sound/voice/catpeople/nyahaha1.ogg differ
diff --git a/sound/voice/catpeople/nyahaha2.ogg b/sound/voice/catpeople/nyahaha2.ogg
new file mode 100644
index 0000000000..a78ba60e70
Binary files /dev/null and b/sound/voice/catpeople/nyahaha2.ogg differ
diff --git a/sound/voice/catpeople/nyahehe.ogg b/sound/voice/catpeople/nyahehe.ogg
new file mode 100644
index 0000000000..c187dafc92
Binary files /dev/null and b/sound/voice/catpeople/nyahehe.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index d5e6ef47a0..773d1e66c4 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -137,6 +137,7 @@
#include "code\__HELPERS\time.dm"
#include "code\__HELPERS\type2type.dm"
#include "code\__HELPERS\type2type_vr.dm"
+#include "code\__HELPERS\typelists.dm"
#include "code\__HELPERS\unsorted.dm"
#include "code\__HELPERS\view.dm"
#include "code\__HELPERS\sorts\__main.dm"
@@ -2912,6 +2913,7 @@
#include "modular_citadel\code\modules\mob\living\carbon\carbon.dm"
#include "modular_citadel\code\modules\mob\living\carbon\damage_procs.dm"
#include "modular_citadel\code\modules\mob\living\carbon\reindex_screams.dm"
+#include "modular_citadel\code\modules\mob\living\carbon\human\human.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_movement.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\life.dm"
diff --git a/tgui/build_assets.bat b/tgui/build_assets.bat
index da9d08360a..7deb2fafd7 100644
--- a/tgui/build_assets.bat
+++ b/tgui/build_assets.bat
@@ -2,5 +2,5 @@
echo node.js and all dependencies must be installed for this script to work.
echo If this script fails try installing dependencies again.
REM Build minified assets
-cmd /c gulp --min
+node node_modules/gulp/bin/gulp.js --min
pause
diff --git a/tgui/install_dependencies.bat b/tgui/install_dependencies.bat
index d0e517b054..4d5b922fe0 100644
--- a/tgui/install_dependencies.bat
+++ b/tgui/install_dependencies.bat
@@ -3,14 +3,6 @@ echo node.js 5.3.0 or newer must be installed for this script to work.
echo If this script fails, try closing editors and running it again first.
echo Any warnings about optional dependencies can be safely ignored.
pause
-REM Install npm-cache
-cmd /c npm install npm-cache -g
-REM Install Gulp
-cmd /c npm install gulp-cli -g
-REM Install tgui dependencies
-cmd /c npm-cache install npm
-REM Flatten dependency tree
-cmd /c npm dedupe
-REM Clean dependency tree
-cmd /c npm prune
+REM Install dependencies
+npm ci
pause
diff --git a/tools/travis/build_tools.sh b/tools/travis/build_tools.sh
index 87aaa124c0..eaccd64c8c 100755
--- a/tools/travis/build_tools.sh
+++ b/tools/travis/build_tools.sh
@@ -6,7 +6,7 @@ set -e
if [ "$BUILD_TOOLS" = true ];
then
md5sum -c - <<< "49bc6b1b9ed56c83cceb6674bd97cb34 *html/changelogs/example.yml";
- cd tgui && source ~/.nvm/nvm.sh && gulp && cd ..;
+ (cd tgui && source ~/.nvm/nvm.sh && npm ci && node node_modules/gulp/bin/gulp.js --min)
phpenv global 5.6
php -l tools/WebhookProcessor/github_webhook_processor.php;
php -l tools/TGUICompiler.php;
diff --git a/tools/travis/install_build_tools.sh b/tools/travis/install_build_tools.sh
index 1d00067279..9dd73f854c 100755
--- a/tools/travis/install_build_tools.sh
+++ b/tools/travis/install_build_tools.sh
@@ -5,7 +5,6 @@ source dependencies.sh
if [ "$BUILD_TOOLS" = true ]; then
rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $NODE_VERSION
- npm install -g gulp-cli
pip3 install --user PyYaml -q
pip3 install --user beautifulsoup4 -q
fi;