diff --git a/code/_compatibility/509/JSON Reader.dm b/code/_compatibility/509/JSON Reader.dm
deleted file mode 100644
index 18f739c5ef..0000000000
--- a/code/_compatibility/509/JSON Reader.dm
+++ /dev/null
@@ -1,209 +0,0 @@
-#if DM_VERSION < 510
-
-json_token
- var
- value
- New(v)
- src.value = v
- text
- number
- word
- symbol
- eof
-
-json_reader
- var
- list
- string = list("'", "\"")
- symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
- sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
- tokens
- json
- i = 1
-
-
- proc
- // scanner
- ScanJson(json)
- src.json = json
- . = new/list()
- src.i = 1
- while(src.i <= length(json))
- var/char = get_char()
- if(is_whitespace(char))
- i++
- continue
- if(string.Find(char))
- . += read_string(char)
- else if(symbols.Find(char))
- . += new/json_token/symbol(char)
- else if(is_digit(char))
- . += read_number()
- else
- . += read_word()
- i++
- . += new/json_token/eof()
-
- read_word()
- var/val = ""
- while(i <= length(json))
- var/char = get_char()
- if(is_whitespace(char) || symbols.Find(char))
- i-- // let scanner handle this character
- return new/json_token/word(val)
- val += char
- i++
-
- read_string(delim)
- var
- escape = FALSE
- val = ""
- while(++i <= length(json))
- var/char = get_char()
- if(escape)
- switch(char)
- if("\\", "'", "\"", "/", "u")
- val += char
- else
- // TODO: support octal, hex, unicode sequences
- ASSERT(sequences.Find(char))
- val += ascii2text(sequences[char])
- else
- if(char == delim)
- return new/json_token/text(val)
- else if(char == "\\")
- escape = TRUE
- else
- val += char
- CRASH("Unterminated string.")
-
- read_number()
- var/val = ""
- var/char = get_char()
- while(is_digit(char) || char == "." || lowertext(char) == "e")
- val += char
- i++
- char = get_char()
- i-- // allow scanner to read the first non-number character
- return new/json_token/number(text2num(val))
-
- check_char()
- ASSERT(args.Find(get_char()))
-
- get_char()
- return copytext(json, i, i+1)
-
- is_whitespace(char)
- return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
-
- is_digit(char)
- var/c = text2ascii(char)
- return 48 <= c && c <= 57 || char == "+" || char == "-"
-
-
- // parser
- ReadObject(list/tokens)
- src.tokens = tokens
- . = new/list()
- i = 1
- read_token("{", /json_token/symbol)
- while(i <= tokens.len)
- var/json_token/K = get_token()
- check_type(/json_token/word, /json_token/text)
- next_token()
- read_token(":", /json_token/symbol)
-
- .[K.value] = read_value()
-
- var/json_token/S = get_token()
- check_type(/json_token/symbol)
- switch(S.value)
- if(",")
- next_token()
- continue
- if("}")
- next_token()
- return
- else
- die()
-
- get_token()
- return tokens[i]
-
- next_token()
- return tokens[++i]
-
- read_token(val, type)
- var/json_token/T = get_token()
- if(!(T.value == val && istype(T, type)))
- CRASH("Expected '[val]', found '[T.value]'.")
- next_token()
- return T
-
- check_type(...)
- var/json_token/T = get_token()
- for(var/type in args)
- if(istype(T, type))
- return
- CRASH("Bad token type: [T.type].")
-
- check_value(...)
- var/json_token/T = get_token()
- ASSERT(args.Find(T.value))
-
- read_key()
- var/char = get_char()
- if(char == "\"" || char == "'")
- return read_string(char)
-
- read_value()
- var/json_token/T = get_token()
- switch(T.type)
- if(/json_token/text, /json_token/number)
- next_token()
- return T.value
- if(/json_token/word)
- next_token()
- switch(T.value)
- if("true")
- return TRUE
- if("false")
- return FALSE
- if("null")
- return null
- if(/json_token/symbol)
- switch(T.value)
- if("\[")
- return read_array()
- if("{")
- return ReadObject(tokens.Copy(i))
- die()
-
- read_array()
- read_token("\[", /json_token/symbol)
- . = new/list()
- var/list/L = .
- while(i <= tokens.len)
- // Avoid using Add() or += in case a list is returned.
- L.len++
- L[L.len] = read_value()
- var/json_token/T = get_token()
- check_type(/json_token/symbol)
- switch(T.value)
- if(",")
- next_token()
- continue
- if("]")
- next_token()
- return
- else
- die()
- next_token()
- CRASH("Unterminated array.")
-
-
- die(json_token/T)
- if(!T) T = get_token()
- CRASH("Unexpected token: [T.value].")
-
-#endif
\ No newline at end of file
diff --git a/code/_compatibility/509/JSON Writer.dm b/code/_compatibility/509/JSON Writer.dm
deleted file mode 100644
index 80e4976687..0000000000
--- a/code/_compatibility/509/JSON Writer.dm
+++ /dev/null
@@ -1,62 +0,0 @@
-#if DM_VERSION < 510
-
-json_writer
- var
- use_cache = 0
-
- proc
- WriteObject(list/L)
- if(use_cache && L["__json_cache"])
- return L["__json_cache"]
-
- . = "{"
- var/i = 1
- for(var/k in L)
- var/val = L[k]
- . += {"\"[k]\":[write(val)]"}
- if(i++ < L.len)
- . += ","
- . += "}"
-
- write(val)
- if(isnum(val))
- return num2text(val)
- else if(isnull(val))
- return "null"
- else if(istype(val, /list))
- if(is_associative(val))
- return WriteObject(val)
- else
- return write_array(val)
- else
- . += write_string("[val]")
-
- write_array(list/L)
- . = "\["
- for(var/i = 1 to L.len)
- . += write(L[i])
- if(i < L.len)
- . += ","
- . += "]"
-
- write_string(txt)
- var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n")
- for(var/targ in json_escape)
- var/start = 1
- while(start <= length(txt))
- var/i = findtext(txt, targ, start)
- if(!i)
- break
- var/lrep = length(json_escape[targ])
- txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ))
- start = i + lrep
-
- return {""[txt]""}
-
- is_associative(list/L)
- for(var/key in L)
- // if the key is a list that means it's actually an array of lists (stupid Byond...)
- if(!isnum(key) && !isnull(L[key]) && !istype(key, /list))
- return TRUE
-
-#endif
\ No newline at end of file
diff --git a/code/_compatibility/509/_JSON.dm b/code/_compatibility/509/_JSON.dm
deleted file mode 100644
index 46f488ac56..0000000000
--- a/code/_compatibility/509/_JSON.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-#if DM_VERSION < 510
-/*
-n_Json v11.3.21
-*/
-
-proc
- json_decode(json)
- var/static/json_reader/_jsonr = new()
- return _jsonr.ReadObject(_jsonr.ScanJson(json))
-
- json_encode(list/L)
- var/static/json_writer/_jsonw = new()
- return _jsonw.write(L)
-#endif
\ No newline at end of file
diff --git a/code/_compatibility/509/text.dm b/code/_compatibility/509/text.dm
deleted file mode 100644
index c22790ccb8..0000000000
--- a/code/_compatibility/509/text.dm
+++ /dev/null
@@ -1,6 +0,0 @@
-#if DM_VERSION < 510
-
-/proc/replacetext(text, find, replacement)
- return jointext(splittext(text, find), replacement)
-
-#endif
\ No newline at end of file
diff --git a/code/_compatibility/509/type2type.dm b/code/_compatibility/509/type2type.dm
deleted file mode 100644
index 62d7a5e5c7..0000000000
--- a/code/_compatibility/509/type2type.dm
+++ /dev/null
@@ -1,102 +0,0 @@
-#if DM_VERSION < 510
-// Concatenates a list of strings into a single string. A seperator may optionally be provided.
-/proc/jointext(list/ls, sep)
- if (ls.len <= 1) // Early-out code for empty or singleton lists.
- return ls.len ? ls[1] : ""
-
- var/l = ls.len // Made local for sanic speed.
- var/i = 0 // Incremented every time a list index is accessed.
-
- if (sep <> null)
- // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc...
- #define S1 sep, ls[++i]
- #define S4 S1, S1, S1, S1
- #define S16 S4, S4, S4, S4
- #define S64 S16, S16, S16, S16
-
- . = "[ls[++i]]" // Make sure the initial element is converted to text.
-
- // Having the small concatenations come before the large ones boosted speed by an average of at least 5%.
- if (l-1 & 0x01) // 'i' will always be 1 here.
- . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2.
- if (l-i & 0x02)
- . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
- if (l-i & 0x04)
- . = text("[][][][][][][][][]", ., S4) // And so on....
- if (l-i & 0x08)
- . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4)
- if (l-i & 0x10)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16)
- if (l-i & 0x20)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
- if (l-i & 0x40)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
- while (l > i) // Chomp through the rest of the list, 128 elements at a time.
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
-
- #undef S64
- #undef S16
- #undef S4
- #undef S1
- else
- // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc...
- #define S1 ls[++i]
- #define S4 S1, S1, S1, S1
- #define S16 S4, S4, S4, S4
- #define S64 S16, S16, S16, S16
-
- . = "[ls[++i]]" // Make sure the initial element is converted to text.
-
- if (l-1 & 0x01) // 'i' will always be 1 here.
- . += S1 // Append 1 element if the remaining elements are not a multiple of 2.
- if (l-i & 0x02)
- . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
- if (l-i & 0x04)
- . = text("[][][][][]", ., S4) // And so on...
- if (l-i & 0x08)
- . = text("[][][][][][][][][]", ., S4, S4)
- if (l-i & 0x10)
- . = text("[][][][][][][][][][][][][][][][][]", ., S16)
- if (l-i & 0x20)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
- if (l-i & 0x40)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
- while (l > i) // Chomp through the rest of the list, 128 elements at a time.
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
-
- #undef S64
- #undef S16
- #undef S4
- #undef S1
-
-// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator)
-/proc/splittext(text, delimiter="\n")
- var/delim_len = length(delimiter)
- if (delim_len < 1)
- return list(text)
-
- . = list()
- var/last_found = 1
- var/found
-
- do
- found = findtext(text, delimiter, last_found, 0)
- . += copytext(text, last_found, found)
- last_found = found + delim_len
- while (found)
-#endif
\ No newline at end of file
diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm
index cb5834ffb1..700bbbfc57 100644
--- a/code/_helpers/type2type.dm
+++ b/code/_helpers/type2type.dm
@@ -2,11 +2,8 @@
* Holds procs designed to change one type of value, into another.
* Contains:
* hex2num & num2hex
- * text2list & list2text
* file2list
* angle2dir
- * angle2text
- * worldtime2text
*/
// Returns an integer given a hexadecimal number string as input.
@@ -133,10 +130,6 @@
if (NORTHWEST) return 315
if (SOUTHWEST) return 225
-// Returns the angle in english
-/proc/angle2text(var/degree)
- return dir2text(angle2dir(degree))
-
// Converts a blend_mode constant to one acceptable to icon.Blend()
/proc/blendMode2iconMode(blend_mode)
switch (blend_mode)
@@ -294,107 +287,6 @@
return strtype
return copytext(strtype, delim_pos)
-// Concatenates a list of strings into a single string. A seperator may optionally be provided.
-/proc/list2text(list/ls, sep)
- if (ls.len <= 1) // Early-out code for empty or singleton lists.
- return ls.len ? ls[1] : ""
-
- var/l = ls.len // Made local for sanic speed.
- var/i = 0 // Incremented every time a list index is accessed.
-
- if (sep != null)
- // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc...
- #define S1 sep, ls[++i]
- #define S4 S1, S1, S1, S1
- #define S16 S4, S4, S4, S4
- #define S64 S16, S16, S16, S16
-
- . = "[ls[++i]]" // Make sure the initial element is converted to text.
-
- // Having the small concatenations come before the large ones boosted speed by an average of at least 5%.
- if (l-1 & 0x01) // 'i' will always be 1 here.
- . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2.
- if (l-i & 0x02)
- . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
- if (l-i & 0x04)
- . = text("[][][][][][][][][]", ., S4) // And so on....
- if (l-i & 0x08)
- . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4)
- if (l-i & 0x10)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16)
- if (l-i & 0x20)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
- if (l-i & 0x40)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
- while (l > i) // Chomp through the rest of the list, 128 elements at a time.
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
-
- #undef S64
- #undef S16
- #undef S4
- #undef S1
- else
- // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc...
- #define S1 ls[++i]
- #define S4 S1, S1, S1, S1
- #define S16 S4, S4, S4, S4
- #define S64 S16, S16, S16, S16
-
- . = "[ls[++i]]" // Make sure the initial element is converted to text.
-
- if (l-1 & 0x01) // 'i' will always be 1 here.
- . += S1 // Append 1 element if the remaining elements are not a multiple of 2.
- if (l-i & 0x02)
- . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
- if (l-i & 0x04)
- . = text("[][][][][]", ., S4) // And so on...
- if (l-i & 0x08)
- . = text("[][][][][][][][][]", ., S4, S4)
- if (l-i & 0x10)
- . = text("[][][][][][][][][][][][][][][][][]", ., S16)
- if (l-i & 0x20)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
- if (l-i & 0x40)
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
- while (l > i) // Chomp through the rest of the list, 128 elements at a time.
- . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
- [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
-
- #undef S64
- #undef S16
- #undef S4
- #undef S1
-
-// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator)
-/proc/text2list(text, delimiter="\n")
- var/delim_len = length(delimiter)
- if (delim_len < 1)
- return list(text)
-
- . = list()
- var/last_found = 1
- var/found
-
- do
- found = findtext(text, delimiter, last_found, 0)
- . += copytext(text, last_found, found)
- last_found = found + delim_len
- while (found)
-
/proc/type2parent(child)
var/string_type = "[child]"
var/last_slash = findlasttext(string_type, "/")
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 277a668442..9d9273d4bf 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -196,9 +196,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
return 1
return 0
-/proc/sign(x)
- return x!=0?x/abs(x):0
-
/proc/getline(atom/M,atom/N)//Ultra-Fast Bresenham Line-Drawing Algorithm
var/px=M.x //starting x
var/py=M.y
@@ -207,8 +204,8 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/dy=N.y-py
var/dxabs=abs(dx)//Absolute value of x distance
var/dyabs=abs(dy)
- var/sdx=sign(dx) //Sign of x distance (+ or -)
- var/sdy=sign(dy)
+ var/sdx=SIGN(dx) //Sign of x distance (+ or -)
+ var/sdy=SIGN(dy)
var/x=dxabs>>1 //Counters for steps taken, setting to distance/2
var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast.
var/j //Generic integer for counting
@@ -426,34 +423,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
else . = pick(ais)
return .
-/proc/get_sorted_mobs()
- var/list/old_list = getmobs()
- var/list/AI_list = list()
- var/list/Dead_list = list()
- var/list/keyclient_list = list()
- var/list/key_list = list()
- var/list/logged_list = list()
- for(var/named in old_list)
- var/mob/M = old_list[named]
- if(issilicon(M))
- AI_list |= M
- else if(isobserver(M) || M.stat == 2)
- Dead_list |= M
- else if(M.key && M.client)
- keyclient_list |= M
- else if(M.key)
- key_list |= M
- else
- logged_list |= M
- old_list.Remove(named)
- var/list/new_list = list()
- new_list += AI_list
- new_list += keyclient_list
- new_list += key_list
- new_list += logged_list
- new_list += Dead_list
- return new_list
-
//Returns a list of all mobs with their name
/proc/getmobs()
return observe_list_format(sortmobs())
@@ -528,14 +497,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
return "[round((powerused * 0.000001),0.001)] MW"
return "[round((powerused * 0.000000001),0.0001)] GW"
-/proc/get_mob_by_ckey(key)
- if(!key)
- return
- var/list/mobs = sortmobs()
- for(var/mob/M in mobs)
- if(M.ckey == key)
- return M
-
//Forces a variable to be posative
/proc/modulus(var/M)
if(M >= 0)
@@ -648,34 +609,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
cant_pass = 1
return cant_pass
-/proc/get_step_towards2(var/atom/ref , var/atom/trg)
- var/base_dir = get_dir(ref, get_step_towards(ref,trg))
- var/turf/temp = get_step_towards(ref,trg)
-
- if(is_blocked_turf(temp))
- var/dir_alt1 = turn(base_dir, 90)
- var/dir_alt2 = turn(base_dir, -90)
- var/turf/turf_last1 = temp
- var/turf/turf_last2 = temp
- var/free_tile = null
- var/breakpoint = 0
-
- while(!free_tile && breakpoint < 10)
- if(!is_blocked_turf(turf_last1))
- free_tile = turf_last1
- break
- if(!is_blocked_turf(turf_last2))
- free_tile = turf_last2
- break
- turf_last1 = get_step(turf_last1,dir_alt1)
- turf_last2 = get_step(turf_last2,dir_alt2)
- breakpoint++
-
- if(!free_tile) return get_step(ref, base_dir)
- else return get_step_towards(ref,free_tile)
-
- else return get_step(ref, base_dir)
-
//Takes: Anything that could possibly have variables and a varname to check.
//Returns: 1 if found, 0 if not.
/proc/hasvar(var/datum/A, var/varname)
@@ -693,20 +626,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/return_sorted_areas()
return sortTim(return_areas(), /proc/cmp_text_asc)
-//Takes: Area type as text string or as typepath OR an instance of the area.
-//Returns: A list of all areas of that type in the world.
-/proc/get_areas(var/areatype)
- if(!areatype) return null
- if(istext(areatype)) areatype = text2path(areatype)
- if(isarea(areatype))
- var/area/areatemp = areatype
- areatype = areatemp.type
-
- var/list/areas = new/list()
- for(var/area/N in world)
- if(istype(N, areatype)) areas += N
- return areas
-
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all turfs in areas of that type of that type in the world.
/proc/get_area_turfs(var/areatype)
@@ -1021,10 +940,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/dy = abs(B.y - A.y)
return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12)
-//chances are 1:value. anyprob(1) will always return true
-/proc/anyprob(value)
- return (rand(1,value)==value)
-
/proc/view_or_range(distance = world.view , center = usr , type)
switch(type)
if("view")
@@ -1033,14 +948,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
. = range(distance,center)
return
-/proc/oview_or_orange(distance = world.view , center = usr , type)
- switch(type)
- if("view")
- . = oview(distance,center)
- if("range")
- . = orange(distance,center)
- return
-
/proc/get_mob_with_client_list()
var/list/mobs = list()
for(var/mob/M in mob_list)
@@ -1162,16 +1069,6 @@ var/global/list/common_tools = list(
istype(W, /obj/item/weapon/shovel) \
)
-/proc/is_surgery_tool(obj/item/W as obj)
- return ( \
- istype(W, /obj/item/weapon/surgical/scalpel) || \
- istype(W, /obj/item/weapon/surgical/hemostat) || \
- istype(W, /obj/item/weapon/surgical/retractor) || \
- istype(W, /obj/item/weapon/surgical/cautery) || \
- istype(W, /obj/item/weapon/surgical/bonegel) || \
- istype(W, /obj/item/weapon/surgical/bonesetter)
- )
-
// check if mob is lying down on something we can operate him on.
// The RNG with table/rollerbeds comes into play in do_surgery() so that fail_step() can be used instead.
/proc/can_operate(mob/living/carbon/M)
@@ -1184,29 +1081,13 @@ var/global/list/common_tools = list(
var/obj/surface = null
for(var/obj/O in loc) // Looks for the best surface.
if(O.surgery_odds)
- if(!surface || surface.surgery_odds < O)
+ if(!surface || surface.surgery_odds < O.surgery_odds)
surface = O
if(surface)
return surface
/proc/reverse_direction(var/dir)
- switch(dir)
- if(NORTH)
- return SOUTH
- if(NORTHEAST)
- return SOUTHWEST
- if(EAST)
- return WEST
- if(SOUTHEAST)
- return NORTHWEST
- if(SOUTH)
- return NORTH
- if(SOUTHWEST)
- return NORTHEAST
- if(WEST)
- return EAST
- if(NORTHWEST)
- return SOUTHEAST
+ return global.reverse_dir[dir]
/*
Checks if that loc and dir has a item on the wall
@@ -1323,16 +1204,12 @@ var/mob/dview/dview_mob = new
living_mob_list -= src
/mob/dview/Destroy(var/force)
- crash_with("Attempt to delete the dview_mob: [log_info_line(src)]")
+ stack_trace("Attempt to delete the dview_mob: [log_info_line(src)]")
if (!force)
return QDEL_HINT_LETMELIVE
global.dview_mob = new
return ..()
-// call to generate a stack trace and print to runtime logs
-/proc/crash_with(msg)
- CRASH(msg)
-
/proc/screen_loc2turf(scr_loc, turf/origin)
var/tX = splittext(scr_loc, ",")
var/tY = splittext(tX[2], ":")
@@ -1478,9 +1355,6 @@ var/mob/dview/dview_mob = new
if(337.5)
return "North-Northwest"
-/proc/pass()
- return
-
/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
if (value == FALSE) //nothing should be calling us with a number, so this is safe
value = input(usr, "Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index c92d42d82a..6b7c0b4137 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -20,7 +20,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
Initialize(exclude_these)
/datum/controller/global_vars/Destroy(force)
- crash_with("There was an attempt to qdel the global vars holder!")
+ stack_trace("There was an attempt to qdel the global vars holder!")
if(!force)
return QDEL_HINT_LETMELIVE
diff --git a/code/controllers/subsystems/processing/processing.dm b/code/controllers/subsystems/processing/processing.dm
index a16902c0c5..16b4da021b 100644
--- a/code/controllers/subsystems/processing/processing.dm
+++ b/code/controllers/subsystems/processing/processing.dm
@@ -112,9 +112,9 @@ SUBSYSTEM_DEF(processing)
var/tick_time = world.time - start_tick
var/tick_use_limit = world.tick_usage - start_tick_usage - 100 // Current tick use - starting tick use - 100% (a full tick excess)
if(tick_time > 0)
- crash_with("[log_info_line(subsystem.debug_last_thing)] slept during processing. Spent [tick_time] tick\s.")
+ stack_trace("[log_info_line(subsystem.debug_last_thing)] slept during processing. Spent [tick_time] tick\s.")
if(tick_use_limit > 0)
- crash_with("[log_info_line(subsystem.debug_last_thing)] took longer than a tick to process. Exceeded with [tick_use_limit]%")
+ stack_trace("[log_info_line(subsystem.debug_last_thing)] took longer than a tick to process. Exceeded with [tick_use_limit]%")
/datum/proc/process()
set waitfor = 0
diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm
index 9c41a0a4ba..dadcd9ab95 100644
--- a/code/controllers/subsystems/timer.dm
+++ b/code/controllers/subsystems/timer.dm
@@ -159,7 +159,7 @@ SUBSYSTEM_DEF(timer)
if (timer.timeToRun < head_offset)
bucket_resolution = null //force bucket recreation
- crash_with("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if (timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
@@ -170,7 +170,7 @@ SUBSYSTEM_DEF(timer)
if (timer.timeToRun < head_offset + TICKS2DS(practical_offset-1))
bucket_resolution = null //force bucket recreation
- crash_with("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if (timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
@@ -458,10 +458,10 @@ SUBSYSTEM_DEF(timer)
CRASH("addtimer called without a callback")
if (wait < 0)
- crash_with("addtimer called with a negative wait. Converting to [world.tick_lag]")
+ stack_trace("addtimer called with a negative wait. Converting to [world.tick_lag]")
if (callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object))
- crash_with("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait")
+ stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait")
wait = max(CEILING(wait, world.tick_lag), world.tick_lag)
@@ -492,7 +492,7 @@ SUBSYSTEM_DEF(timer)
. = hash_timer.id
return
else if(flags & TIMER_OVERRIDE)
- crash_with("TIMER_OVERRIDE used without TIMER_UNIQUE")
+ stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE")
var/datum/timedevent/timer = new(callback, wait, flags, hash)
return timer.id
diff --git a/code/datums/managed_browsers/_managed_browser.dm b/code/datums/managed_browsers/_managed_browser.dm
index c915c7e86a..6c702ddbdd 100644
--- a/code/datums/managed_browsers/_managed_browser.dm
+++ b/code/datums/managed_browsers/_managed_browser.dm
@@ -16,10 +16,10 @@ GLOBAL_VAR(managed_browser_id_ticker)
/datum/managed_browser/New(client/new_client)
if(!new_client)
- crash_with("Managed browser object was not given a client.")
+ stack_trace("Managed browser object was not given a client.")
return
if(!base_browser_id)
- crash_with("Managed browser object does not have a base browser id defined in its type.")
+ stack_trace("Managed browser object does not have a base browser id defined in its type.")
return
my_client = new_client
diff --git a/code/datums/mixed.dm b/code/datums/mixed.dm
index 191868e489..0b429156da 100644
--- a/code/datums/mixed.dm
+++ b/code/datums/mixed.dm
@@ -28,7 +28,7 @@
/datum/data/record/Destroy(var/force)
if(data_core.locked.Find(src))
if(!force)
- crash_with("Someone tried to qdel a record that was in data_core.locked [log_info_line(src)]")
+ stack_trace("Someone tried to qdel a record that was in data_core.locked [log_info_line(src)]")
return QDEL_HINT_LETMELIVE
data_core.locked -= src
data_core.medical -= src
diff --git a/code/datums/repositories/decls.dm b/code/datums/repositories/decls.dm
index e6040a90dd..fead498c63 100644
--- a/code/datums/repositories/decls.dm
+++ b/code/datums/repositories/decls.dm
@@ -67,5 +67,5 @@ var/repository/decls/decls_repository // Initialiozed in /datum/global_init/New(
/decl/Destroy()
SHOULD_CALL_PARENT(FALSE)
- crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]")
+ stack_trace("Prevented attempt to delete a decl instance: [log_info_line(src)]")
return QDEL_HINT_LETMELIVE // Prevents decl destruction
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index f0851201d9..acf31b5079 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -83,9 +83,9 @@
// Must return an Initialize hint. Defined in code/__defines/subsystems.dm
/atom/proc/Initialize(mapload, ...)
if(QDELETED(src))
- crash_with("GC: -- [type] had initialize() called after qdel() --")
+ stack_trace("GC: -- [type] had initialize() called after qdel() --")
if(initialized)
- crash_with("Warning: [src]([type]) initialized multiple times!")
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
initialized = TRUE
return INITIALIZE_HINT_NORMAL
diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm
index 7adc3ba9d3..1dca766535 100644
--- a/code/game/machinery/embedded_controller/docking_program.dm
+++ b/code/game/machinery/embedded_controller/docking_program.dm
@@ -77,7 +77,7 @@
..()
if(id_tag)
if(SSshuttles.docking_registry[id_tag])
- crash_with("Docking controller tag [id_tag] had multiple associated programs.")
+ stack_trace("Docking controller tag [id_tag] had multiple associated programs.")
SSshuttles.docking_registry[id_tag] = src
/datum/embedded_program/docking/Destroy()
diff --git a/code/game/objects/effects/map_effects/portal.dm b/code/game/objects/effects/map_effects/portal.dm
index 9f40c87f1b..375bbcd336 100644
--- a/code/game/objects/effects/map_effects/portal.dm
+++ b/code/game/objects/effects/map_effects/portal.dm
@@ -201,7 +201,7 @@ when portals are shortly lived, or when portals are made to be obvious with spec
break
if(!counterpart)
- crash_with("Portal master [type] ([x],[y],[z]) could not find another portal master with a matching portal_id ([portal_id]).")
+ stack_trace("Portal master [type] ([x],[y],[z]) could not find another portal master with a matching portal_id ([portal_id]).")
/obj/effect/map_effect/portal/master/proc/make_visuals()
var/list/observed_turfs = list()
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 82f8b58efe..10e78e83ee 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -172,7 +172,7 @@
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
return !density
- crash_with("Non movable passed to turf CanPass : [mover]")
+ stack_trace("Non movable passed to turf CanPass : [mover]")
return FALSE
//There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000
diff --git a/code/global.dm b/code/global.dm
index 750d0272b8..0d029e3afa 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -1,6 +1,6 @@
//#define TESTING
-#if DM_VERSION < 506
-#warn This compiler is out of date. You may experience issues with projectile animations.
+#if DM_VERSION < 512
+#error This compiler is out of date Please update to at least BYOND 512.
#endif
// Items that ask to be called every cycle.
diff --git a/code/modules/food/kitchen/cooking_machines/_appliance.dm b/code/modules/food/kitchen/cooking_machines/_appliance.dm
index 1b090068f6..9a838efeb8 100644
--- a/code/modules/food/kitchen/cooking_machines/_appliance.dm
+++ b/code/modules/food/kitchen/cooking_machines/_appliance.dm
@@ -506,7 +506,7 @@
if (!S)
continue
- words |= text2list(S.name," ")
+ words |= splittext(S.name," ")
cooktypes |= S.cooked
if (S.reagents && S.reagents.total_volume > 0)
diff --git a/code/modules/holomap/generate_holomap.dm b/code/modules/holomap/generate_holomap.dm
index d24f1f47f3..99396bd542 100644
--- a/code/modules/holomap/generate_holomap.dm
+++ b/code/modules/holomap/generate_holomap.dm
@@ -56,9 +56,9 @@
// Sanity checks - Better to generate a helpful error message now than have DrawBox() runtime
var/icon/canvas = icon(HOLOMAP_ICON, "blank")
if(world.maxx > canvas.Width())
- crash_with("Minimap for z=[zLevel] : world.maxx ([world.maxx]) must be <= [canvas.Width()]")
+ stack_trace("Minimap for z=[zLevel] : world.maxx ([world.maxx]) must be <= [canvas.Width()]")
if(world.maxy > canvas.Height())
- crash_with("Minimap for z=[zLevel] : world.maxy ([world.maxy]) must be <= [canvas.Height()]")
+ stack_trace("Minimap for z=[zLevel] : world.maxy ([world.maxy]) must be <= [canvas.Height()]")
for(var/x = 1 to world.maxx)
for(var/y = 1 to world.maxy)
@@ -82,9 +82,9 @@
// Sanity checks - Better to generate a helpful error message now than have DrawBox() runtime
var/icon/canvas = icon(HOLOMAP_ICON, "blank")
if(world.maxx > canvas.Width())
- crash_with("Minimap for z=[zLevel] : world.maxx ([world.maxx]) must be <= [canvas.Width()]")
+ stack_trace("Minimap for z=[zLevel] : world.maxx ([world.maxx]) must be <= [canvas.Width()]")
if(world.maxy > canvas.Height())
- crash_with("Minimap for z=[zLevel] : world.maxy ([world.maxy]) must be <= [canvas.Height()]")
+ stack_trace("Minimap for z=[zLevel] : world.maxy ([world.maxy]) must be <= [canvas.Height()]")
for(var/x = 1 to world.maxx)
for(var/y = 1 to world.maxy)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 2c6c9e0e70..a94aa0334c 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -107,7 +107,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
if(QDESTROYING(src))
return
- crash_with("CANARY: Old human update_icons was called.")
+ stack_trace("CANARY: Old human update_icons was called.")
update_hud() //TODO: remove the need for this
@@ -839,7 +839,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
apply_layer(SUIT_LAYER)
/mob/living/carbon/human/update_inv_pockets()
- crash_with("Someone called update_inv_pockets even though it's dumb")
+ stack_trace("Someone called update_inv_pockets even though it's dumb")
/mob/living/carbon/human/update_inv_wear_mask()
if(QDESTROYING(src))
diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
index 64283b7f92..a15e2bf518 100644
--- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
+++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
@@ -228,21 +228,21 @@
if(!delivery && compactor && length(contents))//garbage counter for trashpup
dat += "Current load: [length(contents)] / [max_item_count] objects.
"
- dat += "([list2text(contents,", ")])
"
+ dat += "([contents.Join(", ")])
"
if(delivery && length(contents))
dat += "Current load: [length(contents)] / [max_item_count] objects.
"
dat += "Cargo compartment slot: Cargo 1.
"
if(length(deliveryslot_1))
- dat += "([list2text(deliveryslot_1,", ")])
"
+ dat += "([deliveryslot_1.Join(", ")])
"
dat += "Cargo compartment slot: Cargo 2.
"
if(length(deliveryslot_2))
- dat += "([list2text(deliveryslot_2,", ")])
"
+ dat += "([deliveryslot_2.Join(", ")])
"
dat += "Cargo compartment slot: Cargo 3.
"
if(length(deliveryslot_3))
- dat += "([list2text(deliveryslot_3,", ")])
"
+ dat += "([deliveryslot_3.Join(", ")])
"
dat += "Cargo compartment slot: Fuel.
"
- dat += "([list2text(contents - (deliveryslot_1 + deliveryslot_2 + deliveryslot_3),", ")])
"
+ dat += "([jointext(contents - (deliveryslot_1 + deliveryslot_2 + deliveryslot_3),", ")])
"
if(analyzer && !synced)
dat += "Sync Files
"
diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm
index 7b1fbd6f7e..6d97835cc2 100644
--- a/code/modules/mob/mob_planes.dm
+++ b/code/modules/mob/mob_planes.dm
@@ -63,7 +63,7 @@
ASSERT(which)
var/obj/screen/plane_master/PM = plane_masters[which]
if(!PM)
- crash_with("Tried to alter [which] in plane_holder on [my_mob]!")
+ stack_trace("Tried to alter [which] in plane_holder on [my_mob]!")
if(my_mob.alpha <= EFFECTIVE_INVIS)
state = FALSE
@@ -83,7 +83,7 @@
ASSERT(which)
var/obj/screen/plane_master/PM = plane_masters[which]
if(!PM)
- crash_with("Tried to alter [which] in plane_holder on [my_mob]!")
+ stack_trace("Tried to alter [which] in plane_holder on [my_mob]!")
PM.set_desired_alpha(new_alpha)
if(PM.sub_planes)
var/list/subplanes = PM.sub_planes
@@ -94,7 +94,7 @@
ASSERT(which)
var/obj/screen/plane_master/PM = plane_masters[which]
if(!PM)
- crash_with("Tried to set_ao [which] in plane_holder on [my_mob]!")
+ stack_trace("Tried to set_ao [which] in plane_holder on [my_mob]!")
PM.set_ambient_occlusion(enabled)
if(PM.sub_planes)
var/list/subplanes = PM.sub_planes
@@ -105,7 +105,7 @@
ASSERT(which)
var/obj/screen/plane_master/PM = plane_masters[which]
if(!PM)
- crash_with("Tried to alter [which] in plane_holder on [my_mob]!")
+ stack_trace("Tried to alter [which] in plane_holder on [my_mob]!")
PM.alter_plane_values(arglist(values))
if(PM.sub_planes)
var/list/subplanes = PM.sub_planes
diff --git a/code/modules/power/antimatter/engine.dm b/code/modules/power/antimatter/engine.dm
index aa1c2245d6..13f230bbb6 100644
--- a/code/modules/power/antimatter/engine.dm
+++ b/code/modules/power/antimatter/engine.dm
@@ -98,7 +98,7 @@
H_fuel = 0
antiH_fuel = 0
else
- var/residual_matter = modulus(H_fuel - antiH_fuel)
+ var/residual_matter = abs(H_fuel - antiH_fuel)
var/mass = antiH_fuel + H_fuel - residual_matter
energy = convert2energy(mass)
if( H_fuel > antiH_fuel )
@@ -149,7 +149,7 @@
else //else if they're not equal determine which isn't equal
//and set it equal to either H or antiH so we don't lose anything
- var/residual_matter = modulus(H_fuel - antiH_fuel)
+ var/residual_matter = abs(H_fuel - antiH_fuel)
mass = antiH_fuel + H_fuel - residual_matter
energy = convert2energy(mass)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 172c7d7383..c691e6247d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -323,7 +323,7 @@
var/turf/starting = get_turf(src)
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
if(isnull(xo) || isnull(yo))
- crash_with("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
+ stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
qdel(src)
return
var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
@@ -400,7 +400,7 @@
xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc) + spread)
else
- crash_with("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
+ stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
qdel(src)
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
diff --git a/code/modules/reagents/holder/holder.dm b/code/modules/reagents/holder/holder.dm
index c2a66bb813..7e9936333f 100644
--- a/code/modules/reagents/holder/holder.dm
+++ b/code/modules/reagents/holder/holder.dm
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
/datum/reagents
@@ -508,3 +509,1026 @@
for(var/datum/reagent/reagent as anything in cached_reagents)
reagent.on_update(A)
update_total()
+||||||| parent of a17194a1a4... Merge pull request #11065 from MarinaGryphon/codequality/unused-unnecessary
+#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
+
+/datum/reagents
+ var/list/datum/reagent/reagent_list = list()
+ var/total_volume = 0
+ var/maximum_volume = 100
+ var/atom/my_atom = null
+
+/datum/reagents/New(var/max = 100, atom/A = null)
+ ..()
+ maximum_volume = max
+ my_atom = A
+
+ //I dislike having these here but map-objects are initialised before world/New() is called. >_>
+ if(!SSchemistry.chemical_reagents)
+ //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
+ var/paths = subtypesof(/datum/reagent)
+ SSchemistry.chemical_reagents = list()
+ for(var/path in paths)
+ var/datum/reagent/D = new path()
+ if(!D.name)
+ continue
+ SSchemistry.chemical_reagents[D.id] = D
+
+/datum/reagents/Destroy()
+ for(var/datum/reagent/R in reagent_list)
+ qdel(R)
+ reagent_list = null
+ if(my_atom && my_atom.reagents == src)
+ my_atom.reagents = null
+ return ..()
+
+/* Internal procs */
+
+/datum/reagents/proc/get_free_space() // Returns free space.
+ return maximum_volume - total_volume
+
+/datum/reagents/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume.
+ var/the_reagent = null
+ var/the_volume = 0
+
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_reagent = A
+
+ return the_reagent
+
+/datum/reagents/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume.
+ var/the_name = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_name = A.name
+
+ return the_name
+
+/datum/reagents/proc/get_master_reagent_id() // Returns the id of the reagent with the biggest volume.
+ var/the_id = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_id = A.id
+
+ return the_id
+
+/datum/reagents/proc/update_total() // Updates volume.
+ total_volume = 0
+ for(var/datum/reagent/R in reagent_list)
+ if(R.volume < MINIMUM_CHEMICAL_VOLUME)
+ del_reagent(R.id)
+ else
+ total_volume += R.volume
+ return
+
+/datum/reagents/proc/handle_reactions()
+ if(QDELETED(my_atom))
+ return FALSE
+ if(my_atom.flags & NOREACT)
+ return FALSE
+ var/reaction_occurred
+ var/list/eligible_reactions = list()
+ var/list/effect_reactions = list()
+ do
+ reaction_occurred = FALSE
+ for(var/i in reagent_list)
+ var/datum/reagent/R = i
+ if(SSchemistry.instant_reactions_by_reagent[R.id])
+ eligible_reactions |= SSchemistry.instant_reactions_by_reagent[R.id]
+
+ for(var/i in eligible_reactions)
+ var/decl/chemical_reaction/C = i
+ if(C.can_happen(src) && C.process(src))
+ effect_reactions |= C
+ reaction_occurred = TRUE
+ eligible_reactions.len = 0
+ while(reaction_occurred)
+ for(var/i in effect_reactions)
+ var/decl/chemical_reaction/C = i
+ C.post_reaction(src)
+ update_total()
+
+/* Holder-to-chemical */
+
+/datum/reagents/proc/add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
+ if(!isnum(amount) || amount <= 0)
+ return 0
+
+ update_total()
+ amount = min(amount, get_free_space())
+
+
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.id == "blood")
+ if(LAZYLEN(data) && !isnull(data["species"]) && !isnull(current.data["species"]) && data["species"] != current.data["species"]) // Species bloodtypes are already incompatible, this just stops it from mixing into the one already in a container.
+ continue
+
+ current.volume += amount
+ if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful
+ current.mix_data(data, amount)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ var/datum/reagent/D = SSchemistry.chemical_reagents[id]
+ if(D)
+ var/datum/reagent/R = new D.type()
+ reagent_list += R
+ R.holder = src
+ R.volume = amount
+ R.initialize_data(data)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ else
+ crash_with("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])")
+ return 0
+
+/datum/reagents/proc/isolate_reagent(reagent)
+ for(var/A in reagent_list)
+ var/datum/reagent/R = A
+ if(R.id != reagent)
+ del_reagent(R.id)
+ update_total()
+
+/datum/reagents/proc/remove_reagent(var/id, var/amount, var/safety = 0)
+ if(!isnum(amount))
+ return 0
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ current.volume -= amount // It can go negative, but it doesn't matter
+ update_total() // Because this proc will delete it then
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ return 0
+
+/datum/reagents/proc/del_reagent(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if (current.id == id)
+ reagent_list -= current
+ qdel(current)
+ update_total()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 0
+
+/datum/reagents/proc/has_reagent(var/id, var/amount = 0)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.volume >= amount)
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_any_reagent(var/list/check_reagents)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_all_reagents(var/list/check_reagents)
+ //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list
+ var/missing = check_reagents.len
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ missing--
+ return !missing
+
+/datum/reagents/proc/clear_reagents()
+ for(var/datum/reagent/current in reagent_list)
+ del_reagent(current.id)
+ return
+
+/datum/reagents/proc/get_reagent_amount(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.volume
+ return 0
+
+/datum/reagents/proc/get_data(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.get_data()
+ return 0
+
+/datum/reagents/proc/get_reagents()
+ . = list()
+ for(var/datum/reagent/current in reagent_list)
+ . += "[current.id] ([current.volume])"
+ return english_list(., "EMPTY", "", ", ", ", ")
+
+/* Holder-to-holder and similar procs */
+
+/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed.
+ amount = min(amount, total_volume)
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_remove = current.volume * part
+ remove_reagent(current.id, amount_to_remove, 1)
+
+ update_total()
+ handle_reactions()
+ return amount
+
+/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]).
+ if(!target || !istype(target))
+ return
+
+ amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier))
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_transfer = current.volume * part
+ target.add_reagent(current.id, amount_to_transfer * multiplier, current.get_data(), safety = 1) // We don't react until everything is in place
+ if(!copy)
+ remove_reagent(current.id, amount_to_transfer, 1)
+
+ if(!copy)
+ handle_reactions()
+ target.handle_reactions()
+ return amount
+
+/* Holder-to-atom and similar procs */
+
+//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
+//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob().
+//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
+//call the appropriate trans_to_*() proc.
+/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ touch(target) //First, handle mere touch effects
+
+ if(ismob(target))
+ return splash_mob(target, amount, copy)
+ if(isturf(target))
+ return trans_to_turf(target, amount, multiplier, copy)
+ if(isobj(target) && target.is_open_container())
+ return trans_to_obj(target, amount, multiplier, copy)
+ return 0
+
+//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well.
+/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60)
+ var/spill = 0
+ if(!isturf(target) && target.loc)
+ spill = amount*(rand(min_spill, max_spill)/100)
+ amount -= spill
+ if(spill)
+ splash(target.loc, spill, multiplier, copy, min_spill, max_spill)
+
+ if(!trans_to(target, amount, multiplier, copy))
+ touch(target, amount)
+
+/datum/reagents/proc/trans_type_to(var/target, var/rtype, var/amount = 1)
+ if (!target)
+ return
+
+ var/datum/reagent/transfering_reagent = get_reagent(rtype)
+
+ if (istype(target, /atom))
+ var/atom/A = target
+ if (!A.reagents || !A.simulated)
+ return
+
+ amount = min(amount, transfering_reagent.volume)
+
+ if(!amount)
+ return
+
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(rtype)
+ F.add_reagent(rtype, amount, tmpdata)
+ remove_reagent(rtype, amount)
+
+
+ if (istype(target, /atom))
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+ else if (istype(target, /datum/reagents))
+ return F.trans_to_holder(target, amount)
+
+/datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1)
+ if (!target || !target.reagents)
+ return
+
+ amount = min(amount, get_reagent_amount(id))
+
+ if(!amount)
+ return
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(id)
+ F.add_reagent(id, amount, tmpdata)
+ remove_reagent(id, amount)
+
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+
+// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
+// This does not handle transferring reagents to things.
+// For example, splashing someone with water will get them wet and extinguish them if they are on fire,
+// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
+/datum/reagents/proc/touch(var/atom/target, var/amount)
+ if(ismob(target))
+ touch_mob(target, amount)
+ if(isturf(target))
+ touch_turf(target, amount)
+ if(isobj(target))
+ touch_obj(target, amount)
+ return
+
+/datum/reagents/proc/touch_mob(var/mob/target)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_mob(target, current.volume)
+
+ update_total()
+
+/datum/reagents/proc/touch_turf(var/turf/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_turf(target, amount)
+
+ update_total()
+
+/datum/reagents/proc/touch_obj(var/obj/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_obj(target, amount)
+
+ update_total()
+
+// Attempts to place a reagent on the mob's skin.
+// Reagents are not guaranteed to transfer to the target.
+// Do not call this directly, call trans_to() instead.
+/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0)
+ var/perm = 1
+ if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs?
+ var/mob/living/L = target
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.check_shields(0, null, null, null, "the spray") == 1) //If they block the spray, it does nothing.
+ amount = 0
+ perm = L.reagent_permeability()
+ return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy)
+
+/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder...
+ if(!target || !istype(target))
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ if(type == CHEM_BLOOD)
+ var/datum/reagents/R = C.reagents
+ return trans_to_holder(R, amount, multiplier, copy)
+ if(type == CHEM_INGEST)
+ var/datum/reagents/R = C.ingested
+ return C.ingest(src, R, amount, multiplier, copy)
+ if(type == CHEM_TOUCH)
+ var/datum/reagents/R = C.touching
+ return trans_to_holder(R, amount, multiplier, copy)
+ else
+ var/datum/reagents/R = new /datum/reagents(amount)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_mob(target)
+
+/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it.
+ if(!target)
+ return
+
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_turf(target, amount)
+ return
+
+/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch.
+ if(!target)
+ return
+
+ if(!target.reagents)
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_obj(target, amount)
+ return
+
+ return trans_to_holder(target.reagents, amount, multiplier, copy)
+
+/* Atom reagent creation - use it all the time */
+
+/atom/proc/create_reagents(var/max_vol, var/reagents_type = /datum/reagents)
+ if(!ispath(reagents_type))
+ reagents_type = /datum/reagents
+ reagents = new reagents_type(max_vol, src)
+
+// Aurora Cooking Port
+/datum/reagents/proc/get_reagent(var/id) // Returns reference to reagent matching passed ID
+ for(var/datum/reagent/A in reagent_list)
+ if (A.id == id)
+ return A
+
+ return null
+
+//Spreads the contents of this reagent holder all over the vicinity of the target turf.
+/datum/reagents/proc/splash_area(var/turf/epicentre, var/range = 3, var/portion = 1.0, var/multiplier = 1, var/copy = 0)
+ var/list/things = dview(range, epicentre, INVISIBILITY_LIGHTING)
+ var/list/turfs = list()
+ for (var/turf/T in things)
+ turfs += T
+ if (!turfs.len)
+ return//Nowhere to splash to, somehow
+ //Create a temporary holder to hold all the amount that will be spread
+ var/datum/reagents/R = new /datum/reagents(total_volume * portion * multiplier)
+ trans_to_holder(R, total_volume * portion, multiplier, copy)
+ //The exact amount that will be given to each turf
+ var/turfportion = R.total_volume / turfs.len
+ for (var/turf/T in turfs)
+ var/datum/reagents/TR = new /datum/reagents(turfportion)
+ R.trans_to_holder(TR, turfportion, 1, 0)
+ TR.splash_turf(T)
+ qdel(R)
+
+
+//Spreads the contents of this reagent holder all over the target turf, dividing among things in it.
+//50% is divided between mobs, 20% between objects, and whatever is left on the turf itself
+/datum/reagents/proc/splash_turf(var/turf/T, var/amount = null, var/multiplier = 1, var/copy = 0)
+ if (isnull(amount))
+ amount = total_volume
+ else
+ amount = min(amount, total_volume)
+ if (amount <= 0)
+ return
+ var/list/mobs = list()
+ for (var/mob/M in T)
+ mobs += M
+ var/list/objs = list()
+ for (var/obj/O in T)
+ objs += O
+ if (objs.len)
+ var/objportion = (amount * 0.2) / objs.len
+ for (var/o in objs)
+ var/obj/O = o
+ trans_to(O, objportion, multiplier, copy)
+ amount = min(amount, total_volume)
+ if (mobs.len)
+ var/mobportion = (amount * 0.5) / mobs.len
+ for (var/m in mobs)
+ var/mob/M = m
+ trans_to(M, mobportion, multiplier, copy)
+ trans_to(T, total_volume, multiplier, copy)
+ if (total_volume <= 0)
+ qdel(src)
+
+/**
+ * Calls [/datum/reagent/proc/on_update] on every reagent in this holder
+ *
+ * Arguments:
+ * * atom/A - passed to on_update
+ */
+/datum/reagents/proc/conditional_update(atom/A)
+ var/list/cached_reagents = reagent_list
+ for(var/datum/reagent/reagent as anything in cached_reagents)
+ reagent.on_update(A)
+ update_total()
+=======
+#define PROCESS_REACTION_ITER 5 //when processing a reaction, iterate this many times
+
+/datum/reagents
+ var/list/datum/reagent/reagent_list = list()
+ var/total_volume = 0
+ var/maximum_volume = 100
+ var/atom/my_atom = null
+
+/datum/reagents/New(var/max = 100, atom/A = null)
+ ..()
+ maximum_volume = max
+ my_atom = A
+
+ //I dislike having these here but map-objects are initialised before world/New() is called. >_>
+ if(!SSchemistry.chemical_reagents)
+ //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
+ var/paths = subtypesof(/datum/reagent)
+ SSchemistry.chemical_reagents = list()
+ for(var/path in paths)
+ var/datum/reagent/D = new path()
+ if(!D.name)
+ continue
+ SSchemistry.chemical_reagents[D.id] = D
+
+/datum/reagents/Destroy()
+ for(var/datum/reagent/R in reagent_list)
+ qdel(R)
+ reagent_list = null
+ if(my_atom && my_atom.reagents == src)
+ my_atom.reagents = null
+ return ..()
+
+/* Internal procs */
+
+/datum/reagents/proc/get_free_space() // Returns free space.
+ return maximum_volume - total_volume
+
+/datum/reagents/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume.
+ var/the_reagent = null
+ var/the_volume = 0
+
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_reagent = A
+
+ return the_reagent
+
+/datum/reagents/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume.
+ var/the_name = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_name = A.name
+
+ return the_name
+
+/datum/reagents/proc/get_master_reagent_id() // Returns the id of the reagent with the biggest volume.
+ var/the_id = null
+ var/the_volume = 0
+ for(var/datum/reagent/A in reagent_list)
+ if(A.volume > the_volume)
+ the_volume = A.volume
+ the_id = A.id
+
+ return the_id
+
+/datum/reagents/proc/update_total() // Updates volume.
+ total_volume = 0
+ for(var/datum/reagent/R in reagent_list)
+ if(R.volume < MINIMUM_CHEMICAL_VOLUME)
+ del_reagent(R.id)
+ else
+ total_volume += R.volume
+ return
+
+/datum/reagents/proc/handle_reactions()
+ if(QDELETED(my_atom))
+ return FALSE
+ if(my_atom.flags & NOREACT)
+ return FALSE
+ var/reaction_occurred
+ var/list/eligible_reactions = list()
+ var/list/effect_reactions = list()
+ do
+ reaction_occurred = FALSE
+ for(var/i in reagent_list)
+ var/datum/reagent/R = i
+ if(SSchemistry.instant_reactions_by_reagent[R.id])
+ eligible_reactions |= SSchemistry.instant_reactions_by_reagent[R.id]
+
+ for(var/i in eligible_reactions)
+ var/decl/chemical_reaction/C = i
+ if(C.can_happen(src) && C.process(src))
+ effect_reactions |= C
+ reaction_occurred = TRUE
+ eligible_reactions.len = 0
+ while(reaction_occurred)
+ for(var/i in effect_reactions)
+ var/decl/chemical_reaction/C = i
+ C.post_reaction(src)
+ update_total()
+
+/* Holder-to-chemical */
+
+/datum/reagents/proc/add_reagent(var/id, var/amount, var/data = null, var/safety = 0)
+ if(!isnum(amount) || amount <= 0)
+ return 0
+
+ update_total()
+ amount = min(amount, get_free_space())
+
+
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.id == "blood")
+ if(LAZYLEN(data) && !isnull(data["species"]) && !isnull(current.data["species"]) && data["species"] != current.data["species"]) // Species bloodtypes are already incompatible, this just stops it from mixing into the one already in a container.
+ continue
+
+ current.volume += amount
+ if(!isnull(data)) // For all we know, it could be zero or empty string and meaningful
+ current.mix_data(data, amount)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ var/datum/reagent/D = SSchemistry.chemical_reagents[id]
+ if(D)
+ var/datum/reagent/R = new D.type()
+ reagent_list += R
+ R.holder = src
+ R.volume = amount
+ R.initialize_data(data)
+ update_total()
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ else
+ stack_trace("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])")
+ return 0
+
+/datum/reagents/proc/isolate_reagent(reagent)
+ for(var/A in reagent_list)
+ var/datum/reagent/R = A
+ if(R.id != reagent)
+ del_reagent(R.id)
+ update_total()
+
+/datum/reagents/proc/remove_reagent(var/id, var/amount, var/safety = 0)
+ if(!isnum(amount))
+ return 0
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ current.volume -= amount // It can go negative, but it doesn't matter
+ update_total() // Because this proc will delete it then
+ if(!safety)
+ handle_reactions()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 1
+ return 0
+
+/datum/reagents/proc/del_reagent(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if (current.id == id)
+ reagent_list -= current
+ qdel(current)
+ update_total()
+ if(my_atom)
+ my_atom.on_reagent_change()
+ return 0
+
+/datum/reagents/proc/has_reagent(var/id, var/amount = 0)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ if(current.volume >= amount)
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_any_reagent(var/list/check_reagents)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ return 1
+ else
+ return 0
+ return 0
+
+/datum/reagents/proc/has_all_reagents(var/list/check_reagents)
+ //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list
+ var/missing = check_reagents.len
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id in check_reagents)
+ if(current.volume >= check_reagents[current.id])
+ missing--
+ return !missing
+
+/datum/reagents/proc/clear_reagents()
+ for(var/datum/reagent/current in reagent_list)
+ del_reagent(current.id)
+ return
+
+/datum/reagents/proc/get_reagent_amount(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.volume
+ return 0
+
+/datum/reagents/proc/get_data(var/id)
+ for(var/datum/reagent/current in reagent_list)
+ if(current.id == id)
+ return current.get_data()
+ return 0
+
+/datum/reagents/proc/get_reagents()
+ . = list()
+ for(var/datum/reagent/current in reagent_list)
+ . += "[current.id] ([current.volume])"
+ return english_list(., "EMPTY", "", ", ", ", ")
+
+/* Holder-to-holder and similar procs */
+
+/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed.
+ amount = min(amount, total_volume)
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_remove = current.volume * part
+ remove_reagent(current.id, amount_to_remove, 1)
+
+ update_total()
+ handle_reactions()
+ return amount
+
+/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]).
+ if(!target || !istype(target))
+ return
+
+ amount = max(0, min(amount, total_volume, target.get_free_space() / multiplier))
+
+ if(!amount)
+ return
+
+ var/part = amount / total_volume
+
+ for(var/datum/reagent/current in reagent_list)
+ var/amount_to_transfer = current.volume * part
+ target.add_reagent(current.id, amount_to_transfer * multiplier, current.get_data(), safety = 1) // We don't react until everything is in place
+ if(!copy)
+ remove_reagent(current.id, amount_to_transfer, 1)
+
+ if(!copy)
+ handle_reactions()
+ target.handle_reactions()
+ return amount
+
+/* Holder-to-atom and similar procs */
+
+//The general proc for applying reagents to things. This proc assumes the reagents are being applied externally,
+//not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob().
+//If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person),
+//call the appropriate trans_to_*() proc.
+/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0)
+ touch(target) //First, handle mere touch effects
+
+ if(ismob(target))
+ return splash_mob(target, amount, copy)
+ if(isturf(target))
+ return trans_to_turf(target, amount, multiplier, copy)
+ if(isobj(target) && target.is_open_container())
+ return trans_to_obj(target, amount, multiplier, copy)
+ return 0
+
+//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well.
+/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60)
+ var/spill = 0
+ if(!isturf(target) && target.loc)
+ spill = amount*(rand(min_spill, max_spill)/100)
+ amount -= spill
+ if(spill)
+ splash(target.loc, spill, multiplier, copy, min_spill, max_spill)
+
+ if(!trans_to(target, amount, multiplier, copy))
+ touch(target, amount)
+
+/datum/reagents/proc/trans_type_to(var/target, var/rtype, var/amount = 1)
+ if (!target)
+ return
+
+ var/datum/reagent/transfering_reagent = get_reagent(rtype)
+
+ if (istype(target, /atom))
+ var/atom/A = target
+ if (!A.reagents || !A.simulated)
+ return
+
+ amount = min(amount, transfering_reagent.volume)
+
+ if(!amount)
+ return
+
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(rtype)
+ F.add_reagent(rtype, amount, tmpdata)
+ remove_reagent(rtype, amount)
+
+
+ if (istype(target, /atom))
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+ else if (istype(target, /datum/reagents))
+ return F.trans_to_holder(target, amount)
+
+/datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1)
+ if (!target || !target.reagents)
+ return
+
+ amount = min(amount, get_reagent_amount(id))
+
+ if(!amount)
+ return
+
+ var/datum/reagents/F = new /datum/reagents(amount)
+ var/tmpdata = get_data(id)
+ F.add_reagent(id, amount, tmpdata)
+ remove_reagent(id, amount)
+
+ return F.trans_to(target, amount) // Let this proc check the atom's type
+
+// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent.
+// This does not handle transferring reagents to things.
+// For example, splashing someone with water will get them wet and extinguish them if they are on fire,
+// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin.
+/datum/reagents/proc/touch(var/atom/target, var/amount)
+ if(ismob(target))
+ touch_mob(target, amount)
+ if(isturf(target))
+ touch_turf(target, amount)
+ if(isobj(target))
+ touch_obj(target, amount)
+ return
+
+/datum/reagents/proc/touch_mob(var/mob/target)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_mob(target, current.volume)
+
+ update_total()
+
+/datum/reagents/proc/touch_turf(var/turf/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_turf(target, amount)
+
+ update_total()
+
+/datum/reagents/proc/touch_obj(var/obj/target, var/amount)
+ if(!target || !istype(target))
+ return
+
+ for(var/datum/reagent/current in reagent_list)
+ current.touch_obj(target, amount)
+
+ update_total()
+
+// Attempts to place a reagent on the mob's skin.
+// Reagents are not guaranteed to transfer to the target.
+// Do not call this directly, call trans_to() instead.
+/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0)
+ var/perm = 1
+ if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs?
+ var/mob/living/L = target
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.check_shields(0, null, null, null, "the spray") == 1) //If they block the spray, it does nothing.
+ amount = 0
+ perm = L.reagent_permeability()
+ return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy)
+
+/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder...
+ if(!target || !istype(target))
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ if(type == CHEM_BLOOD)
+ var/datum/reagents/R = C.reagents
+ return trans_to_holder(R, amount, multiplier, copy)
+ if(type == CHEM_INGEST)
+ var/datum/reagents/R = C.ingested
+ return C.ingest(src, R, amount, multiplier, copy)
+ if(type == CHEM_TOUCH)
+ var/datum/reagents/R = C.touching
+ return trans_to_holder(R, amount, multiplier, copy)
+ else
+ var/datum/reagents/R = new /datum/reagents(amount)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_mob(target)
+
+/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it.
+ if(!target)
+ return
+
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_turf(target, amount)
+ return
+
+/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch.
+ if(!target)
+ return
+
+ if(!target.reagents)
+ var/datum/reagents/R = new /datum/reagents(amount * multiplier)
+ . = trans_to_holder(R, amount, multiplier, copy)
+ R.touch_obj(target, amount)
+ return
+
+ return trans_to_holder(target.reagents, amount, multiplier, copy)
+
+/* Atom reagent creation - use it all the time */
+
+/atom/proc/create_reagents(var/max_vol, var/reagents_type = /datum/reagents)
+ if(!ispath(reagents_type))
+ reagents_type = /datum/reagents
+ reagents = new reagents_type(max_vol, src)
+
+// Aurora Cooking Port
+/datum/reagents/proc/get_reagent(var/id) // Returns reference to reagent matching passed ID
+ for(var/datum/reagent/A in reagent_list)
+ if (A.id == id)
+ return A
+
+ return null
+
+//Spreads the contents of this reagent holder all over the vicinity of the target turf.
+/datum/reagents/proc/splash_area(var/turf/epicentre, var/range = 3, var/portion = 1.0, var/multiplier = 1, var/copy = 0)
+ var/list/things = dview(range, epicentre, INVISIBILITY_LIGHTING)
+ var/list/turfs = list()
+ for (var/turf/T in things)
+ turfs += T
+ if (!turfs.len)
+ return//Nowhere to splash to, somehow
+ //Create a temporary holder to hold all the amount that will be spread
+ var/datum/reagents/R = new /datum/reagents(total_volume * portion * multiplier)
+ trans_to_holder(R, total_volume * portion, multiplier, copy)
+ //The exact amount that will be given to each turf
+ var/turfportion = R.total_volume / turfs.len
+ for (var/turf/T in turfs)
+ var/datum/reagents/TR = new /datum/reagents(turfportion)
+ R.trans_to_holder(TR, turfportion, 1, 0)
+ TR.splash_turf(T)
+ qdel(R)
+
+
+//Spreads the contents of this reagent holder all over the target turf, dividing among things in it.
+//50% is divided between mobs, 20% between objects, and whatever is left on the turf itself
+/datum/reagents/proc/splash_turf(var/turf/T, var/amount = null, var/multiplier = 1, var/copy = 0)
+ if (isnull(amount))
+ amount = total_volume
+ else
+ amount = min(amount, total_volume)
+ if (amount <= 0)
+ return
+ var/list/mobs = list()
+ for (var/mob/M in T)
+ mobs += M
+ var/list/objs = list()
+ for (var/obj/O in T)
+ objs += O
+ if (objs.len)
+ var/objportion = (amount * 0.2) / objs.len
+ for (var/o in objs)
+ var/obj/O = o
+ trans_to(O, objportion, multiplier, copy)
+ amount = min(amount, total_volume)
+ if (mobs.len)
+ var/mobportion = (amount * 0.5) / mobs.len
+ for (var/m in mobs)
+ var/mob/M = m
+ trans_to(M, mobportion, multiplier, copy)
+ trans_to(T, total_volume, multiplier, copy)
+ if (total_volume <= 0)
+ qdel(src)
+
+/**
+ * Calls [/datum/reagent/proc/on_update] on every reagent in this holder
+ *
+ * Arguments:
+ * * atom/A - passed to on_update
+ */
+/datum/reagents/proc/conditional_update(atom/A)
+ var/list/cached_reagents = reagent_list
+ for(var/datum/reagent/reagent as anything in cached_reagents)
+ reagent.on_update(A)
+ update_total()
+>>>>>>> a17194a1a4... Merge pull request #11065 from MarinaGryphon/codequality/unused-unnecessary
diff --git a/code/modules/reagents/machinery/dispenser/dispenser2_energy.dm b/code/modules/reagents/machinery/dispenser/dispenser2_energy.dm
index b0dec9f65b..9c776d3266 100644
--- a/code/modules/reagents/machinery/dispenser/dispenser2_energy.dm
+++ b/code/modules/reagents/machinery/dispenser/dispenser2_energy.dm
@@ -15,7 +15,7 @@
for(var/id in dispense_reagents)
var/datum/reagent/R = SSchemistry.chemical_reagents[id]
if(!R)
- crash_with("[src] at [x],[y],[z] failed to find reagent '[id]'!")
+ stack_trace("[src] at [x],[y],[z] failed to find reagent '[id]'!")
dispense_reagents -= id
continue
var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[R.name]
diff --git a/code/modules/shieldgen/energy_shield.dm b/code/modules/shieldgen/energy_shield.dm
index 6c11eb62e2..c13c43496a 100644
--- a/code/modules/shieldgen/energy_shield.dm
+++ b/code/modules/shieldgen/energy_shield.dm
@@ -165,7 +165,7 @@
return
if(!damtype)
- crash_with("CANARY: shield.take_damage() callled without damtype.")
+ stack_trace("CANARY: shield.take_damage() callled without damtype.")
if(!damage)
return
diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm
index 4bbad2b3ec..92724d0f86 100644
--- a/code/modules/vore/eating/belly_obj_vr.dm
+++ b/code/modules/vore/eating/belly_obj_vr.dm
@@ -510,7 +510,7 @@
var/messages = null
if(raw_messages)
- messages = list2text(raw_messages, delim)
+ messages = raw_messages.Join(delim)
return messages
// The next function sets the messages on the belly, from human-readable var
@@ -519,7 +519,7 @@
/obj/belly/proc/set_messages(raw_text, type, delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em" || type == "ema" || type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain")
- var/list/raw_list = text2list(html_encode(raw_text),delim)
+ var/list/raw_list = splittext(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
log_debug("[owner] tried to set [lowertext(name)] with 11+ messages")
diff --git a/code/modules/vore/persist/persist_vr.dm b/code/modules/vore/persist/persist_vr.dm
index 3bae4a8524..d5833e4b3b 100644
--- a/code/modules/vore/persist/persist_vr.dm
+++ b/code/modules/vore/persist/persist_vr.dm
@@ -40,7 +40,7 @@
*/
/proc/prep_for_persist(var/mob/persister)
if(!istype(persister))
- crash_with("Persist (P4P): Given non-mob [persister].")
+ stack_trace("Persist (P4P): Given non-mob [persister].")
return
// Find out of this mob is a proper mob!
@@ -74,7 +74,7 @@
/proc/persist_interround_data(var/mob/occupant, var/datum/spawnpoint/new_spawn_point_type)
if(!istype(occupant))
- crash_with("Persist (PID): Given non-mob [occupant].")
+ stack_trace("Persist (PID): Given non-mob [occupant].")
return
var/datum/preferences/prefs = prep_for_persist(occupant)
@@ -225,7 +225,7 @@
*/
/proc/persist_nif_data(var/mob/living/carbon/human/H,var/datum/preferences/prefs)
if(!istype(H))
- crash_with("Persist (NIF): Given a nonhuman: [H]")
+ stack_trace("Persist (NIF): Given a nonhuman: [H]")
return
if(!prefs)
diff --git a/code/unit_tests/unit_test.dm b/code/unit_tests/unit_test.dm
index e775f6f763..7d7dee1617 100644
--- a/code/unit_tests/unit_test.dm
+++ b/code/unit_tests/unit_test.dm
@@ -30,7 +30,7 @@ var/total_unit_tests = 0
log_unit_test("Initializing Unit Testing")
if(!ticker)
- crash_with("No Ticker")
+ stack_trace("No Ticker")
world.Del()
var/said_msg = 0
diff --git a/maps/~map_system/maps.dm b/maps/~map_system/maps.dm
index bfac0d7e1b..4a6b06fc77 100644
--- a/maps/~map_system/maps.dm
+++ b/maps/~map_system/maps.dm
@@ -339,7 +339,7 @@ var/list/all_maps = list()
custom_skybox = new custom_skybox()
/datum/map_z_level/Destroy(var/force)
- crash_with("Attempt to delete a map_z_level instance [log_info_line(src)]")
+ stack_trace("Attempt to delete a map_z_level instance [log_info_line(src)]")
if(!force)
return QDEL_HINT_LETMELIVE // No.
if (using_map.zlevels["[z]"] == src)
diff --git a/vorestation.dme b/vorestation.dme
index add186cb53..999354da4c 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -112,11 +112,6 @@
#include "code\__defines\dcs\flags.dm"
#include "code\__defines\dcs\helpers.dm"
#include "code\__defines\dcs\signals.dm"
-#include "code\_compatibility\509\_JSON.dm"
-#include "code\_compatibility\509\JSON Reader.dm"
-#include "code\_compatibility\509\JSON Writer.dm"
-#include "code\_compatibility\509\text.dm"
-#include "code\_compatibility\509\type2type.dm"
#include "code\_global_vars\bitfields.dm"
#include "code\_global_vars\misc.dm"
#include "code\_global_vars\mobs.dm"