diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000000..8874507d61f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,62 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+
+
+#### Description of issue
+
+
+
+#### Difference between expected and actual behavior
+
+
+
+#### Steps to reproduce
+
+
+
+#### Specific information for locating
+
+
+
+
+#### Length of time in which bug has been known to occur
+
+
+
+
+#### Client version, Server revision & Game ID
+
+
+
+
+#### Issue bingo
+
+
+- [ ] Issue could be reproduced at least once
+- [ ] Issue could be reproduced by different players
+- [ ] Issue could be reproduced in multiple rounds
+- [ ] Issue happened in a recent (less than 7 days ago) round
+- [ ] [Couldn't find an existing issue about this](https://github.com/HearthOfHestia/Nebula/issues)
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000000..7c4bdc9e7de
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,41 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: "[FEATURE]"
+labels: enhancement
+assignees: ''
+
+---
+
+
+#### Is your feature request related to a problem? Please describe.
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+#### Describe the solution you'd like
+A clear and concise description of what you want to happen.
+
+#### Describe alternatives you've considered
+A clear and concise description of any alternative solutions or features you've considered.
+
+#### Additional context
+Add any other context or screenshots about the feature request here.
+
+#### Feature bingo
+
+
+- [ ] Feature does not already exist
+- [ ] Feature has not been rejected in the past 30 days
+- [ ] Feature has no maintainer vetos
+- [ ] Feature does not break the [Github Acceptable Use Policies on restricted content](https://docs.github.com/en/github/site-policy/github-acceptable-use-policies#2-content-restrictions)
+- [ ] [Couldn't find an existing feature request about this](https://github.com/HearthOfHestia/Nebula/labels/enhancement).
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 00b0aaf434a..c720132d1b5 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,31 +1,26 @@
+
-
-
-
+
## Description of changes
-
## Why and what will this PR improve
-
## Authorship
-
## Changelog
-
+
:cl:
prefix:
/:cl:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index bf52f761a5e..cfab69d15d9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,8 +15,8 @@ on:
env:
BYOND_MAJOR: "514"
- BYOND_MINOR: "1566"
- SPACEMAN_DMM_VERSION: suite-1.7
+ BYOND_MINOR: "1572"
+ SPACEMAN_DMM_VERSION: suite-1.7.1
jobs:
DreamChecker:
@@ -80,7 +80,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- map_path: [example, tradeship, nexus, exodus, ministation, away_sites_testing, modpack_testing]
+ map_path: [example, tradeship, nexus, exodus, ministation, away_sites_testing, modpack_testing, torch]
steps:
- uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Setup Cache
diff --git a/code/__defines/directions.dm b/code/__defines/directions.dm
index bb6252cb3e6..b4524560447 100644
--- a/code/__defines/directions.dm
+++ b/code/__defines/directions.dm
@@ -16,6 +16,8 @@
#define CORNER_EASTWEST CORNER_COUNTERCLOCKWISE
#define CORNER_NORTHSOUTH CORNER_CLOCKWISE
+#define FIRST_DIR(X) ((X) & -(X))
+
/*
turn() is weird:
turn(icon, angle) turns icon by angle degrees clockwise
diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm
index 106bafe44ce..0f3cd9bd04b 100644
--- a/code/__defines/flags.dm
+++ b/code/__defines/flags.dm
@@ -46,7 +46,7 @@ The latter will result in a linter warning and will not work correctly.
#define ATOM_FLAG_ADJACENT_EXCEPTION BITFLAG(9) // Skips adjacent checks for atoms that should always be reachable in window tiles
#define ATOM_FLAG_NO_DISSOLVE BITFLAG(10) // Bypasses solvent reactions in the container.
#define ATOM_FLAG_NO_PHASE_CHANGE BITFLAG(11) // Bypasses heating and cooling product reactions in the container.
-#define ATOM_FLAG_ALLOW_DIAGONAL_FACING BITFLAG(12) // Atom can face non-cardinal directions.
+#define ATOM_FLAG_BLOCK_DIAGONAL_FACING BITFLAG(12) // Atom cannot face non-cardinal directions.
#define ATOM_IS_OPEN_CONTAINER(A) (A.atom_flags & ATOM_FLAG_OPEN_CONTAINER)
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 1d7dab5188e..e753c7766f8 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -261,11 +261,25 @@
#define Z_ALL_TURFS(Z) block(locate(1, 1, Z), locate(world.maxx, world.maxy, Z))
-#if DM_BUILD < 1540
-#define AS_ANYTHING as()
-#else
#define AS_ANYTHING as anything
-#endif
+
+// Cooking appliances.
+#define APPLIANCE_MIX BITFLAG(0)
+#define APPLIANCE_FRYER BITFLAG(1)
+#define APPLIANCE_OVEN BITFLAG(2)
+#define APPLIANCE_SKILLET BITFLAG(3)
+#define APPLIANCE_SAUCEPAN BITFLAG(4)
+#define APPLIANCE_POT BITFLAG(5)
+#define APPLIANCE_MICROWAVE BITFLAG(6)
+// Cooking misc.
+// can_insert return values
+#define CANNOT_INSERT 0
+#define CAN_INSERT 1
+#define INSERT_GRABBED 2
+// check_contents return values
+#define CONTAINER_EMPTY 0
+#define CONTAINER_SINGLE 1
+#define CONTAINER_MANY 2
//NOTE: INTENT_HOTKEY_* defines are not actual intents!
//they are here to support hotkeys
@@ -286,3 +300,6 @@
#define WRITTEN_SKIP 0
#define WRITTEN_PHYSICAL 1
#define WRITTEN_DIGITAL 2
+
+// arbitrary low pressure bound for wind weather effects
+#define MIN_WIND_PRESSURE 10
diff --git a/code/__defines/temperature.dm b/code/__defines/temperature.dm
index 098cdf3ee3e..a1280715022 100644
--- a/code/__defines/temperature.dm
+++ b/code/__defines/temperature.dm
@@ -3,11 +3,13 @@
#define ATOM_TEMPERATURE_EQUILIBRIUM_CONSTANT 0.25
#define ADJUST_ATOM_TEMPERATURE(_atom, _temp) \
- _atom.temperature = _temp; \
- if(_atom.reagents) { \
- HANDLE_REACTIONS(_atom.reagents); \
- } \
- QUEUE_TEMPERATURE_ATOMS(_atom);
+ if(!QDELETED(_atom)) { \
+ _atom.temperature = _temp; \
+ if(!QDELETED(_atom.reagents)) { \
+ HANDLE_REACTIONS(_atom.reagents); \
+ } \
+ QUEUE_TEMPERATURE_ATOMS(_atom);\
+ }
#define QUEUE_TEMPERATURE_ATOMS(_atoms) \
if(islist(_atoms)) { \
diff --git a/code/_global_vars/lists/flavor.dm b/code/_global_vars/lists/flavor.dm
index 2553ba15545..28bf458706f 100644
--- a/code/_global_vars/lists/flavor.dm
+++ b/code/_global_vars/lists/flavor.dm
@@ -34,10 +34,10 @@ var/global/list/station_prefixes = list("", "Imperium", "Heretical", "Cuban",
var/global/list/station_names = list("", "Stanford", "Dwarf", "Alien",
"Aegis", "Death-World", "Rogue", "Safety", "Paranoia",
- "Explosive", "North", "West", "East", "South", "Slant-ways",
- "Widdershins", "Rimward", "Expensive", "Procreatory", "Imperial",
- "Unidentified", "Immoral", "Carp", "Orc", "Pete", "Control",
- "Nettle", "Class", "Crab", "Fist", "Corrogated", "Skeleton",
+ "Explosive", "North", "West", "East", "South", "Slant-ways",
+ "Widdershins", "Rimward", "Expensive", "Procreatory", "Imperial",
+ "Unidentified", "Immoral", "Carp", "Orc", "Pete", "Control",
+ "Nettle", "Class", "Crab", "Fist", "Corrogated", "Skeleton",
"Gentleman", "Capitalist", "Communist", "Bear", "Beard", "Space",
"Star", "Moon", "System", "Mining", "Research", "Supply", "Military",
"Orbital", "Battle", "Science", "Asteroid", "Home", "Production",
diff --git a/code/_global_vars/lists/names.dm b/code/_global_vars/lists/names.dm
index 5eb78e06c32..d9f4bec71f7 100644
--- a/code/_global_vars/lists/names.dm
+++ b/code/_global_vars/lists/names.dm
@@ -1,3 +1,5 @@
+// All variables here use double quotes to able load information on every startup.
+
var/global/list/ai_names = file2list("config/names/ai.txt")
var/global/list/wizard_first = file2list("config/names/wizardfirst.txt")
var/global/list/wizard_second = file2list("config/names/wizardsecond.txt")
@@ -11,5 +13,3 @@ var/global/list/clown_names = file2list("config/names/clown.txt")
var/global/list/verbs = file2list("config/names/verbs.txt")
var/global/list/adjectives = file2list("config/names/adjectives.txt")
-//loaded on startup because of "
-//would include in rsc if ' was used
diff --git a/code/_helpers/medical_scans.dm b/code/_helpers/medical_scans.dm
index 86c7d463727..05bd3cd191e 100644
--- a/code/_helpers/medical_scans.dm
+++ b/code/_helpers/medical_scans.dm
@@ -265,7 +265,6 @@
if(E["is_stump"])
row += "
Missing | "
else
- row += ""
var/rowdata = list()
if(E["brute_dam"] + E["burn_dam"] == 0)
rowdata += "None"
@@ -279,7 +278,7 @@
rowdata += "[capitalize(get_wound_severity(E["brute_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] physical trauma"
if(E["burn_dam"])
rowdata += "[capitalize(get_wound_severity(E["burn_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] burns"
- row += " | [jointext(rowdata, " ")] | "
+ row += "[jointext(rowdata, " ")] | "
if(skill_level >= SKILL_ADEPT)
var/list/status = list()
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index dac307ef4ad..3b1a5b1cbd2 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -14,9 +14,9 @@
*/
// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts.
-/proc/sanitizeSQL(var/t as text)
- var/sqltext = dbcon.Quote(t);
- return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that
+/proc/sanitize_sql(t)
+ var/sqltext = dbcon.Quote("[t]") // http://www.byond.com/forum/post/2218538
+ return copytext(sqltext, 2, -1)
/*
* Text sanitization
@@ -24,7 +24,7 @@
//Used for preprocessing entered text
//Added in an additional check to alert players if input is too long
-/proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1)
+/proc/sanitize(input, max_length = MAX_MESSAGE_LEN, encode = TRUE, trim = TRUE, extra = TRUE, ascii_only = FALSE)
if(!input)
return
@@ -33,47 +33,68 @@
if(input_length > max_length)
to_chat(usr, SPAN_WARNING("Your message is too long by [input_length - max_length] character\s."))
return
- input = copytext_char(input, 1, max_length + 1)
+ input = copytext_char(input, 1, max_length)
if(extra)
input = replace_characters(input, list("\n"=" ","\t"=" "))
+ if(ascii_only)
+ // Some procs work differently depending on unicode/ascii string
+ // You should always consider this with any text processing work
+ // More: http://www.byond.com/docs/ref/info.html#/{notes}/Unicode
+ // http://www.byond.com/forum/post/2520672
+ input = strip_non_ascii(input)
+ else
+ // Strip Unicode control/space-like chars here exept for line endings (\n,\r) and normal space (0x20)
+ // codes from https://www.compart.com/en/unicode/category/
+ // https://en.wikipedia.org/wiki/Whitespace_character#Unicode
+ var/static/regex/unicode_control_chars = regex(@"[\u0001-\u0009\u000B\u000C\u000E-\u001F\u007F\u0080-\u009F\u00A0\u1680\u180E\u2000-\u200D\u2028\u2029\u202F\u205F\u2060\u3000\uFEFF]", "g")
+ input = unicode_control_chars.Replace(input, "")
+
if(encode)
- // The below \ escapes have a space inserted to attempt to enable unit testing of span class usage. Please do not remove the space.
- //In addition to processing html, html_encode removes byond formatting codes like "\ red", "\ i" and other.
- //It is important to avoid double-encode text, it can "break" quotes and some other characters.
- //Also, keep in mind that escaped characters don't work in the interface (window titles, lower left corner of the main window, etc.)
+ // In addition to processing html, html_encode removes byond formatting codes like "\red", "\i" and other.
+ // It is important to avoid double-encode text, it can "break" quotes and some other characters.
+ // Also, keep in mind that escaped characters don't work in the interface (window titles, lower left corner of the main window, etc.)
input = html_encode(input)
else
- //If not need encode text, simply remove < and >
- //note: we can also remove here byond formatting codes: 0xFF + next byte
+ // If not need encode text, simply remove < and >
+ // note: we can also remove here byond formatting codes: 0xFF + next byte
input = replace_characters(input, list("<"=" ", ">"=" "))
if(trim)
- //Maybe, we need trim text twice? Here and before copytext?
input = trim(input)
return input
-//Run sanitize(), but remove <, >, " first to prevent displaying them as > < &34; in some places, after html_encode().
+//Run sanitize(), but remove <, >, " first to prevent displaying them as > < &34; in some places after html_encode().
//Best used for sanitize object names, window titles.
//If you have a problem with sanitize() in chat, when quotes and >, < are displayed as html entites -
-//this is a problem of double-encode(when & becomes &), use sanitize() with encode=0, but not the sanitizeSafe()!
-/proc/sanitizeSafe(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1)
- return sanitize(replace_characters(input, list(">"=" ","<"=" ", "\""="'")), max_length, encode, trim, extra)
+//this is a problem of double-encode(when & becomes &), use sanitize() with encode=0, but not the sanitize_safe()!
+/proc/sanitize_safe(input, max_length = MAX_MESSAGE_LEN, encode = TRUE, trim = TRUE, extra = TRUE, ascii_only = FALSE)
+ return sanitize(replace_characters(input, list(">"=" ","<"=" ", "\""="'")), max_length, encode, trim, extra, ascii_only)
+
+/proc/paranoid_sanitize(t)
+ var/regex/alphanum_only = regex("\[^a-zA-Z0-9# ,.?!:;()]", "g")
+ return alphanum_only.Replace(t, "#")
//Filters out undesirable characters from names
-/proc/sanitizeName(var/input, var/max_length = MAX_NAME_LEN, var/allow_numbers = 0, var/force_first_letter_uppercase = TRUE)
- if(!input || length(input) > max_length)
+/proc/sanitize_name(input, max_length = MAX_NAME_LEN, allow_numbers = 0, force_first_letter_uppercase = TRUE)
+ if(!input || length_char(input) > max_length)
return //Rejects the input if it is null or if it is longer then the max length allowed
var/number_of_alphanumeric = 0
var/last_char_group = 0
var/output = ""
- for(var/i=1, i<=length(input), i++)
- var/ascii_char = text2ascii(input,i)
- switch(ascii_char)
+ var/char = ""
+ var/bytes_length = length(input)
+ var/ascii_char
+ for(var/i = 1, i <= bytes_length, i += length(char))
+ char = input[i]
+
+ ascii_char = text2ascii(char)
+
+ switch(ascii_char) //todo: unicode names?
// A .. Z
if(65 to 90) //Uppercase Letters
output += ascii2text(ascii_char)
@@ -121,10 +142,7 @@
if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '"
if(last_char_group == 1)
- output = copytext(output,1,length(output)) //removes the last character (in this case a space)
-
- for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names
- if(cmptext(output,bad_name)) return //(not case sensitive)
+ output = copytext(output, 1, -1) //removes the last character (in this case a space)
return output
@@ -213,11 +231,16 @@
* Text modification
*/
-/proc/replace_characters(var/t,var/list/repl_chars)
+/proc/replace_characters(t, list/repl_chars)
for(var/char in repl_chars)
t = replacetext(t, char, repl_chars[char])
return t
+/proc/random_string(length, list/characters)
+ . = ""
+ for (var/i in 1 to length)
+ . += pick(characters)
+
//Adds 'u' number of zeros ahead of the text 't'
/proc/add_zero(t, u)
return pad_left(t, u, "0")
@@ -233,13 +256,13 @@
// Adds the required amount of 'character' in front of 'text' to extend the lengh to 'desired_length', if it is shorter
// No consideration are made for a multi-character 'character' input
/proc/pad_left(text, desired_length, character)
- var/padding = generate_padding(length(text), desired_length, character)
+ var/padding = generate_padding(length_char(text), desired_length, character)
return length(padding) ? "[padding][text]" : text
// Adds the required amount of 'character' after 'text' to extend the lengh to 'desired_length', if it is shorter
// No consideration are made for a multi-character 'character' input
/proc/pad_right(text, desired_length, character)
- var/padding = generate_padding(length(text), desired_length, character)
+ var/padding = generate_padding(length_char(text), desired_length, character)
return length(padding) ? "[text][padding]" : text
/proc/generate_padding(current_length, desired_length, character)
@@ -250,32 +273,59 @@
characters += character
return JOINTEXT(characters)
-
-//Returns a string with reserved characters and spaces before the first letter removed
+// Returns a string with reserved characters and spaces before the first letter removed
+// not work for unicode spaces - you should cleanup them first with sanitize()
/proc/trim_left(text)
for (var/i = 1 to length(text))
if (text2ascii(text, i) > 32)
return copytext(text, i)
return ""
-//Returns a string with reserved characters and spaces after the last letter removed
+// Returns a string with reserved characters and spaces after the last letter removed
+// not work for unicode spaces - you should cleanup them first with sanitize()
/proc/trim_right(text)
for (var/i = length(text), i > 0, i--)
if (text2ascii(text, i) > 32)
return copytext(text, 1, i + 1)
+
return ""
-//Returns a string with reserved characters and spaces before the first word and after the last word removed.
+// Returns a string with reserved characters and spaces before the first word and after the last word removed.
+// not work for unicode spaces - you should cleanup them first with sanitize()
/proc/trim(text)
return trim_left(trim_right(text))
//Returns a string with the first element of the string capitalized.
-/proc/capitalize(var/t as text)
- return uppertext(copytext_char(t, 1, 2)) + copytext_char(t, 2)
+/proc/capitalize(text)
+ if(text)
+ text = uppertext(text[1]) + copytext(text, 1 + length(text[1]))
+ return text
+
+//Returns a string with the first element of the every word of the string capitalized.
+/proc/capitalize_words(text)
+ var/list/S = splittext(text, " ")
+ var/list/M = list()
+ for (var/w in S)
+ M += capitalize(w)
+ return jointext(M, " ")
+
+/proc/strip_non_ascii(text)
+ var/static/regex/non_ascii_regex = regex(@"[^\x00-\x7F]+", "g")
+ return non_ascii_regex.Replace(text, "")
+
+/proc/strip_html_simple(t, limit = MAX_MESSAGE_LEN)
+ var/list/strip_chars = list("<",">")
+ t = copytext(t,1,limit)
+ for(var/char in strip_chars)
+ var/index = findtext(t, char)
+ while(index)
+ t = copytext(t, 1, index) + copytext(t, index+1)
+ index = findtext(t, char)
+ return t
//This proc strips html properly, remove < > and all text between
//for complete text sanitizing should be used sanitize()
-/proc/strip_html_properly(var/input)
+/proc/strip_html_properly(input)
if(!input)
return
var/opentag = 1 //These store the position of < and > respectively.
@@ -301,7 +351,7 @@
//This proc fills in all spaces with the "replace" var (* by default) with whatever
//is in the other string at the same spot (assuming it is not a replace char).
//This is used for fingerprints
-/proc/stringmerge(var/text,var/compare,replace = "*")
+/proc/stringmerge_ascii(text, compare,replace = "*")
var/newtext = text
if(length(text) != length(compare))
return 0
@@ -321,7 +371,7 @@
//This proc returns the number of chars of the string that is the character
//This is used for detective work to determine fingerprint completion.
-/proc/stringpercent(var/text,character = "*")
+/proc/stringpercent_ascii(text,character = "*")
if(!text || !character)
return 0
var/count = 0
@@ -331,10 +381,13 @@
count++
return count
-/proc/reverse_text(var/text = "")
+/proc/reverse_text(text = "")
var/new_text = ""
- for(var/i = length(text); i > 0; i--)
- new_text += copytext(text, i, i+1)
+ var/bytes_length = length(text)
+ var/letter = ""
+ for(var/i = 1, i <= bytes_length, i += length(letter))
+ letter = text[i]
+ new_text = letter + new_text
return new_text
//Used in preferences' SetFlavorText and human's set_flavor verb
@@ -423,6 +476,7 @@
t = replacetext(t, "\[row\]", "")
t = replacetext(t, "\[cell\]", "")
t = replacetext(t, "\[editorbr\]", "")
+ t = replacetext(t, "\[iseologo\]", "")
return t
//pencode translation to html for tags exclusive to digital files (currently email, nanoword, report editor fields,
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 1a9c5f8eb8a..8f38ebb0a3e 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -303,7 +303,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
newname = input(src,"You are \a [role]. Would you like to change your name to something else?", "Name change",oldname) as text
if((world.time-time_passed) > 5 MINUTES)
return //took too long
- newname = sanitizeName(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters.
+ newname = sanitize_name(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters.
for(var/mob/living/M in global.player_list)
if(M == src)
continue
diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm
index fc9120c4dfd..8d024420c4e 100644
--- a/code/_onclick/hud/movable_screen_objects.dm
+++ b/code/_onclick/hud/movable_screen_objects.dm
@@ -8,4 +8,4 @@
var/list/screen_loc_params = splittext(PM["screen-loc"], ",")
var/list/x_data = splittext(screen_loc_params[1], ":")
var/list/y_data = splittext(screen_loc_params[2], ":")
- screen_loc = "LEFT+[x_data[1]]:[text2num(x_data[2])-16],BOTTOM+[y_data[1]]:[text2num(y_data[2])-16]"
+ screen_loc = "LEFT+[x_data[1]]:[text2num(x_data[2])-(1.5 * world.icon_size)],BOTTOM+[y_data[1]]:[text2num(y_data[2])-(1.5 * world.icon_size)]"
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 69493131744..e61cf91fddd 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -32,6 +32,8 @@ var/global/list/radial_menus = list()
closeToolTip(usr)
/obj/screen/radial/slice/Click(location, control, params)
+ if(QDELETED(src) || QDELETED(parent))
+ return
if(parent && usr.client == parent.current_user)
if(next_page)
parent.next_page()
@@ -51,6 +53,8 @@ var/global/list/radial_menus = list()
icon_state = "radial_center"
/obj/screen/radial/center/Click(location, control, params)
+ if(QDELETED(src) || QDELETED(parent))
+ return
if(usr.client == parent.current_user)
parent.finished = TRUE
@@ -274,6 +278,7 @@ var/global/list/radial_menus = list()
/datum/radial_menu/proc/hide()
if(current_user)
current_user.images -= menu_holder
+ clear_vis_contents(menu_holder)
/datum/radial_menu/proc/wait(atom/user, atom/anchor, require_near = FALSE, list/check_locs)
while (current_user && !finished && !selected_choice)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index c653a3d34c7..504ed39436e 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -237,7 +237,7 @@ var/global/obj/screen/robot_inventory
else
//Modules display is hidden
//R.client.screen -= robot_inventory //"store" icon
- for(var/atom/A in R.module.equipment)
+ for(var/atom/A in R.module?.equipment)
if( (A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3) )
//Module is not currently active
R.client.screen -= A
diff --git a/code/_onclick/hud/skybox.dm b/code/_onclick/hud/skybox.dm
index fb5546c5a29..9bd447bf94b 100644
--- a/code/_onclick/hud/skybox.dm
+++ b/code/_onclick/hud/skybox.dm
@@ -1,5 +1,4 @@
-#define SKYBOX_MAX_BOUND 736
-
+var/global/const/SKYBOX_DIMENSION = 736 // Largest measurement for icon sides, used for offsets/scaling
/obj/skybox
name = "skybox"
mouse_opacity = 0
@@ -7,13 +6,14 @@
simulated = FALSE
plane = SKYBOX_PLANE
blend_mode = BLEND_MULTIPLY
- var/base_x_dim = 7
- var/base_y_dim = 7
- var/base_offset_x = -224 // -(world.view x dimension * world.icon_size)
- var/base_offset_y = -224 // -(world.view y dimension * world.icon_size)
+ screen_loc = "CENTER,CENTER"
+ transform_animate_time = 0
+ var/static/max_view_dim
+ var/static/const/parallax_bleed_percent = 0.2 // 20% parallax offset when going from x=1 to x=max
/obj/skybox/Initialize()
- screen_loc = "CENTER:[base_offset_x],CENTER:[base_offset_y]"
+ if(!max_view_dim)
+ max_view_dim = CEILING(SKYBOX_DIMENSION / world.icon_size)
. = ..()
/client
@@ -21,36 +21,46 @@
/client/proc/set_skybox_offsets(var/x_dim, var/y_dim)
if(!skybox)
- update_skybox()
- if(skybox)
- skybox.base_x_dim = x_dim
- skybox.base_y_dim = y_dim
- skybox.base_offset_x = -((world.icon_size * skybox.base_x_dim)/2)
- skybox.base_offset_y = -((world.icon_size * skybox.base_y_dim)/2)
-
- // Check if the skybox needs to be scaled to fit large displays.
- var/new_max_tile_bound = max(skybox.base_x_dim, skybox.base_y_dim)
- var/old_max_tile_bound = SKYBOX_MAX_BOUND/world.icon_size
- if(new_max_tile_bound > old_max_tile_bound)
- var/matrix/M = matrix()
- M.Scale(1 + (new_max_tile_bound/old_max_tile_bound))
- skybox.transform = M
- else
- skybox.transform = null
- update_skybox()
+ update_skybox(TRUE)
+ return
+ var/scale_value = 1
+ if(isnum(view))
+ var/target_icon_size = (view * 2 + 1) * world.icon_size
+ scale_value = skybox.parallax_bleed_percent + max((target_icon_size / SKYBOX_DIMENSION), 1)
+ skybox.screen_loc = "CENTER:-[view * world.icon_size],CENTER:-[view * world.icon_size]"
+ else
+ var/target_icon_size = max(x_dim, y_dim) * world.icon_size
+ scale_value = skybox.parallax_bleed_percent + max((target_icon_size / SKYBOX_DIMENSION), 1)
+ skybox.screen_loc = "CENTER:-[round(SKYBOX_DIMENSION * scale_value / 2)],CENTER:-[round(SKYBOX_DIMENSION * scale_value / 2)]"
+ skybox.set_scale(scale_value)
+ update_skybox()
/client/proc/update_skybox(rebuild)
+
+ var/turf/T = get_turf(eye)
+ if(!T)
+ return
+
if(!skybox)
skybox = new()
screen += skybox
- rebuild = 1
- var/turf/T = get_turf(eye)
- if(T)
- if(rebuild)
- skybox.overlays.Cut()
- skybox.overlays += SSskybox.get_skybox(T.z)
- screen |= skybox
- skybox.screen_loc = "CENTER:[skybox.base_offset_x - T.x],CENTER:[skybox.base_offset_y - T.y]"
+ rebuild = TRUE
+
+ if(rebuild)
+ skybox.overlays.Cut()
+ var/image/I = SSskybox.get_skybox(T.z)
+ I.appearance_flags |= PIXEL_SCALE
+ skybox.overlays += I
+ screen |= skybox
+ set_skybox_offsets(last_view_x_dim, last_view_y_dim)
+ return
+
+ if(skybox.parallax_bleed_percent > 0)
+ var/matrix/M = skybox.update_transform() || matrix()
+ var/x_translate = -((T.x/world.maxx)-0.5) * skybox.parallax_bleed_percent * SKYBOX_DIMENSION
+ var/y_translate = -((T.y/world.maxy)-0.5) * skybox.parallax_bleed_percent * SKYBOX_DIMENSION
+ M.Translate(x_translate, y_translate)
+ skybox.transform = M
/mob/Move()
var/old_z = get_z(src)
@@ -63,5 +73,3 @@
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
-
-#undef SKYBOX_MAX_BOUND
\ No newline at end of file
diff --git a/code/controllers/subsystems/fluids.dm b/code/controllers/subsystems/fluids.dm
index 71457a3d1d7..449b67ba476 100644
--- a/code/controllers/subsystems/fluids.dm
+++ b/code/controllers/subsystems/fluids.dm
@@ -64,6 +64,7 @@ SUBSYSTEM_DEF(fluids)
if(!fluid_sources_copied_yet)
fluid_sources_copied_yet = TRUE
processing_sources = water_sources.Copy()
+ water_sources.Cut()
while(processing_sources.len)
@@ -73,10 +74,10 @@ SUBSYSTEM_DEF(fluids)
flooded_a_neighbor = FALSE
UPDATE_FLUID_BLOCKED_DIRS(current_turf)
for(spread_dir in global.cardinal)
- if(current_turf.fluid_blocked_dirs & spread_dir)
+ if(current_turf.fluid_blocked_dirs & spread_dir)
continue
neighbor = get_step(current_turf, spread_dir)
- if(!istype(neighbor) || neighbor.flooded)
+ if(!istype(neighbor) || QDELETED(neighbor) || neighbor.flooded)
continue
UPDATE_FLUID_BLOCKED_DIRS(neighbor)
if((neighbor.fluid_blocked_dirs & global.reverse_dir[spread_dir]) || !neighbor.CanFluidPass(spread_dir) || checked_targets[neighbor])
@@ -159,7 +160,7 @@ SUBSYSTEM_DEF(fluids)
if(current_turf.fluid_blocked_dirs & spread_dir)
continue
neighbor = get_step(current_turf, spread_dir)
- if(!neighbor)
+ if(QDELETED(neighbor))
continue
UPDATE_FLUID_BLOCKED_DIRS(neighbor)
coming_from = global.reverse_dir[spread_dir]
@@ -192,11 +193,12 @@ SUBSYSTEM_DEF(fluids)
current_fluid.last_flow_dir = 0
if (MC_TICK_CHECK)
- break
+ break
if(!holders_copied_yet)
holders_copied_yet = TRUE
processing_holders = holders_to_update.Copy()
+ holders_to_update.Cut()
while(processing_holders.len)
reagent_holder = processing_holders[processing_holders.len]
diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index f70c8ecfba8..37c98698f50 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -397,7 +397,7 @@ SUBSYSTEM_DEF(garbage)
return
if(!skip_alert)
- if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
+ if(UNLINT(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No")) == "No")
running_find_references = null
return
@@ -410,15 +410,29 @@ SUBSYSTEM_DEF(garbage)
testing("Beginning search for references to a [type].")
last_find_references = world.time
- DoSearchVar(global) //globals
- for(var/datum/thing in world) //atoms (don't believe its lies)
- DoSearchVar(thing, "World -> [thing]")
-
- for (var/datum/thing) //datums
- DoSearchVar(thing, "World -> [thing]")
-
- for (var/client/thing) //clients
- DoSearchVar(thing, "World -> [thing]")
+ //Yes we do actually need to do this. The searcher refuses to read weird lists
+ //And global.vars is a really weird list
+ var/list/normal_globals = list()
+ for(var/global_var in global.vars)
+ normal_globals[global_var] = global.vars[global_var]
+ DoSearchVar(normal_globals, "(global) -> ") //globals
+ testing("Finished searching globals")
+
+ for(var/atom/atom_thing) //atoms
+ DoSearchVar(atom_thing, "World -> [atom_thing]")
+ testing("Finished searching atoms")
+
+ for (var/datum/datum_thing) //datums
+ DoSearchVar(datum_thing, "World -> [datum_thing]")
+ testing("Finished searching datums")
+
+#ifndef FIND_REF_SKIP_CLIENTS
+ // DO NOT RUN THIS ON A LIVE SERVER
+ // IT WILL CRASH!!!
+ for (var/client/client_thing) //clients
+ DoSearchVar(client_thing, "World -> [client_thing]")
+ testing("Finished searching clients")
+#endif
testing("Completed search for references to a [type].")
if(usr && usr.client)
@@ -452,12 +466,16 @@ SUBSYSTEM_DEF(garbage)
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
-/datum/proc/DoSearchVar(X, Xname, recursive_limit = 64)
+/datum/proc/DoSearchVar(X, Xname, recursive_limit = 128)
if(usr && usr.client && !usr.client.running_find_references)
return
if (!recursive_limit)
return
+ #ifndef FIND_REF_NO_CHECK_TICK
+ CHECK_TICK
+ #endif
+
if(istype(X, /datum))
var/datum/D = X
if(D.last_find_references == last_find_references)
@@ -467,6 +485,9 @@ SUBSYSTEM_DEF(garbage)
var/list/L = D.vars
for(var/varname in L)
+ #ifndef FIND_REF_NO_CHECK_TICK
+ CHECK_TICK
+ #endif
if (varname == "vars")
continue
var/variable = L[varname]
@@ -475,22 +496,25 @@ SUBSYSTEM_DEF(garbage)
testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]")
else if(islist(variable))
- DoSearchVar(variable, "[Xname] -> list", recursive_limit-1)
+ DoSearchVar(variable, "[Xname] -> [varname] (list)", recursive_limit-1)
else if(islist(X))
var/normal = IS_NORMAL_LIST(X)
for(var/I in X)
+ #ifndef FIND_REF_NO_CHECK_TICK
+ CHECK_TICK
+ #endif
if (I == src)
testing("Found [src.type] \ref[src] in list [Xname].")
- else if (I && !isnum(I) && normal && X[I] == src)
- testing("Found [src.type] \ref[src] in list [Xname]\[[I]\]")
+ else if (I && !isnum(I) && normal)
+ if(X[I] == src)
+ testing("Found [src.type] \ref[src] in list [Xname]\[[I]\]")
+ else if(islist(X[I]))
+ DoSearchVar(X[I], "[Xname]\[[I]\]", recursive_limit-1)
else if (islist(I))
- DoSearchVar(I, "[Xname] -> list", recursive_limit-1)
-
-#ifndef FIND_REF_NO_CHECK_TICK
- CHECK_TICK
-#endif
+ var/list/Xlist = X
+ DoSearchVar(I, "[Xname]\[[Xlist.Find(I)]\] -> list", recursive_limit-1)
#endif
diff --git a/code/controllers/subsystems/statistics.dm b/code/controllers/subsystems/statistics.dm
index 263e9f8d7ac..c6931d5ba1e 100644
--- a/code/controllers/subsystems/statistics.dm
+++ b/code/controllers/subsystems/statistics.dm
@@ -146,14 +146,14 @@ SUBSYSTEM_DEF(statistics)
var/datum/death/death = new
var/area/placeofdeath = get_area(dead)
death.place_of_death = placeofdeath ? placeofdeath.name : "Unknown area"
- death.place_of_death = sanitizeSQL(death.place_of_death)
- death.name = sanitizeSQL(dead.real_name)
- death.key = sanitizeSQL(dead.key)
- death.special_role = sanitizeSQL(dead.mind.get_special_role_name())
- death.job = sanitizeSQL(dead.mind.assigned_role)
+ death.place_of_death = sanitize_sql(death.place_of_death)
+ death.name = sanitize_sql(dead.real_name)
+ death.key = sanitize_sql(dead.key)
+ death.special_role = sanitize_sql(dead.mind.get_special_role_name())
+ death.job = sanitize_sql(dead.mind.assigned_role)
if(dead.last_attacker_)
- death.last_attacker_name = sanitizeSQL(dead.last_attacker_.name)
- death.last_attacker_key = sanitizeSQL(dead.last_attacker_.client.key)
+ death.last_attacker_name = sanitize_sql(dead.last_attacker_.name)
+ death.last_attacker_key = sanitize_sql(dead.last_attacker_.client.key)
death.gender = dead.gender
death.time_of_death = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
death.coords = "[dead.x], [dead.y], [dead.z]"
diff --git a/code/controllers/subsystems/throwing.dm b/code/controllers/subsystems/throwing.dm
index 21adc0015f4..d4519eac6ad 100644
--- a/code/controllers/subsystems/throwing.dm
+++ b/code/controllers/subsystems/throwing.dm
@@ -26,8 +26,16 @@ SUBSYSTEM_DEF(throwing)
var/atom/movable/AM = currentrun[currentrun.len]
var/datum/thrownthing/TT = currentrun[AM]
currentrun.len--
- if (QDELETED(AM) || QDELETED(TT))
- processing -= AM
+ if (QDELETED(AM))
+ if(!QDELETED(TT))
+ qdel(TT) // handles removing from processing list
+ if (MC_TICK_CHECK)
+ return
+ continue
+ if (QDELETED(TT))
+ if(!QDELETED(AM))
+ AM.throwing = null
+ processing -= AM
if (MC_TICK_CHECK)
return
continue
@@ -168,10 +176,10 @@ SUBSYSTEM_DEF(throwing)
hit = TRUE
thrownthing.throw_impact(A, src)
break
-
+
if(QDELETED(thrownthing))
return
-
+
if(!hit)
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
thrownthing.space_drift(init_dir)
diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm
index c329651a5bc..d62ad0af676 100644
--- a/code/controllers/subsystems/timer.dm
+++ b/code/controllers/subsystems/timer.dm
@@ -259,6 +259,12 @@ SUBSYSTEM_DEF(timer)
// Add all timed events from the secondary queue as well
alltimers += second_queue
+ for (var/datum/timedevent/t as anything in alltimers)
+ t.bucket_joined = FALSE
+ t.bucket_pos = -1
+ t.prev = null
+ t.next = null
+
// If there are no timers being tracked by the subsystem,
// there is no need to do any further rebuilding
if (!length(alltimers))
@@ -302,6 +308,7 @@ SUBSYSTEM_DEF(timer)
new_bucket_count++
var/bucket_pos = BUCKET_POS(timer)
timer.bucket_pos = bucket_pos
+ timer.bucket_joined = TRUE
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
if (!bucket_head)
diff --git a/code/datums/composite_sounds/_composite_sound.dm b/code/datums/composite_sounds/_composite_sound.dm
index bdf1301bc71..419d45e01b9 100644
--- a/code/datums/composite_sounds/_composite_sound.dm
+++ b/code/datums/composite_sounds/_composite_sound.dm
@@ -67,9 +67,8 @@
timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP)
/datum/composite_sound/proc/play(soundfile)
- var/sound/S = sound(soundfile)
- for(var/atom/thing AS_ANYTHING in output_atoms)
- playsound(thing, S, volume)
+ for(var/atom/thing as anything in output_atoms)
+ playsound(thing, soundfile, volume)
/datum/composite_sound/proc/get_sound(starttime, _mid_sounds)
. = _mid_sounds || mid_sounds
diff --git a/code/datums/composite_sounds/machinery_sounds.dm b/code/datums/composite_sounds/machinery_sounds.dm
index d8a261cac34..18a290e1e06 100644
--- a/code/datums/composite_sounds/machinery_sounds.dm
+++ b/code/datums/composite_sounds/machinery_sounds.dm
@@ -1,7 +1,15 @@
+/datum/composite_sound/deep_fryer
+ start_sound = 'sound/machines/fryer/deep_fryer_immerse.ogg' //my immersions
+ start_length = 10
+ mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
+ mid_length = 2
+ end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
+ volume = 10
+
/datum/composite_sound/microwave
start_sound = 'sound/machines/microwave/microwave-start.ogg'
start_length = 10
mid_sounds = list('sound/machines/microwave/microwave-mid1.ogg'=10, 'sound/machines/microwave/microwave-mid2.ogg'=1)
mid_length = 10
end_sound = 'sound/machines/microwave/microwave-end.ogg'
- volume = 1
\ No newline at end of file
+ volume = 10
diff --git a/code/datums/extensions/assembly/assembly.dm b/code/datums/extensions/assembly/assembly.dm
index e7db4747142..9a532c435d4 100644
--- a/code/datums/extensions/assembly/assembly.dm
+++ b/code/datums/extensions/assembly/assembly.dm
@@ -52,7 +52,7 @@
else
var/atom/movable/H = holder
P.dropInto(H.loc)
- if(P.type in critical_parts)
+ if(enabled && (P.type in critical_parts))
critical_shutdown()
/datum/extension/assembly/proc/add_replace_component(var/mob/living/user, var/part_type, var/obj/item/stock_parts/P)
@@ -106,6 +106,11 @@
handle_power()
+/datum/extension/assembly/proc/is_critical_part(var/obj/item/stock_parts/P)
+ if(is_type_in_list(P, critical_parts))
+ return TRUE
+ return FALSE
+
/datum/extension/assembly/proc/has_critical_parts()
for(var/crit_type in critical_parts)
var/found_part = FALSE
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 45bb23c33a5..a8fadf4018c 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -29,7 +29,7 @@
if(sector)
var/list/neighbors_to_add = list()
- for(var/obj/effect/overmap/visitable/neighbor in sector.loc)
+ for(var/obj/effect/overmap/visitable/neighbor in /*HEARTH EDIT START*/ range(sector.loc, 2) /*HEARTH EDIT END*/)
neighbors_to_add |= neighbor
var/list/neighboring_sectors = list()
@@ -45,7 +45,7 @@
accessible_z_levels |= neighbor.map_z
return (tz in accessible_z_levels)
-
+
/decl/teleport/proc/can_teleport(var/atom/movable/target, var/atom/destination)
if(!destination || !target?.loc)
return FALSE
diff --git a/code/datums/mind/mind.dm b/code/datums/mind/mind.dm
index e7c9134cf0f..62f88197fb8 100644
--- a/code/datums/mind/mind.dm
+++ b/code/datums/mind/mind.dm
@@ -36,7 +36,6 @@
var/mob/living/original //TODO: remove.not used in any meaningful way ~Carn. First I'll need to tweak the way silicon-mobs handle minds.
var/active = 0
- var/list/known_connections //list of known (RNG) relations between people
var/gen_relations_info
var/assigned_role
@@ -47,7 +46,6 @@
var/datum/job/assigned_job
var/list/datum/objective/objectives = list()
- var/list/datum/objective/special_verbs = list()
var/has_been_rev = 0//Tracks if this mind has been a rev or not
@@ -70,9 +68,19 @@
/datum/mind/Destroy()
QDEL_NULL_LIST(memories)
+ QDEL_NULL_LIST(objectives)
+ QDEL_NULL(changeling)
SSticker.minds -= src
. = ..()
+/datum/mind/proc/handle_mob_deletion(mob/living/deleted_mob)
+ if (current == deleted_mob)
+ current.spellremove()
+ current = null
+
+ if (original == deleted_mob)
+ original = null
+
/datum/mind/proc/transfer_to(mob/living/new_character)
if(!istype(new_character))
to_world_log("## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn")
@@ -493,7 +501,6 @@
changeling = null
initial_account = null
objectives = list()
- special_verbs = list()
has_been_rev = 0
rev_cooldown = 0
brigged_since = -1
diff --git a/code/datums/movement/mob.dm b/code/datums/movement/mob.dm
index 3bd328bdcb3..d31a94d6e22 100644
--- a/code/datums/movement/mob.dm
+++ b/code/datums/movement/mob.dm
@@ -13,12 +13,15 @@
control_object.set_dir(direction)
// Death handling
-/datum/movement_handler/mob/death/DoMove()
- if(mob.stat != DEAD)
+/datum/movement_handler/mob/death/DoMove(var/direction, var/mob/mover)
+ if(mob != mover || mob.stat != DEAD)
return
+
. = MOVEMENT_HANDLED
+
if(!mob.client)
return
+
mob.ghostize()
// Incorporeal/Ghost movement
diff --git a/code/datums/observation/dir_set.dm b/code/datums/observation/dir_set.dm
index 9245e15dd1c..b4456ff0ffd 100644
--- a/code/datums/observation/dir_set.dm
+++ b/code/datums/observation/dir_set.dm
@@ -27,7 +27,7 @@
/atom/set_dir(ndir)
var/old_dir = dir
// This attempts to mimic BYOND's handling of diagonal directions and cardinal icon states.
- if(!(atom_flags & ATOM_FLAG_ALLOW_DIAGONAL_FACING) && !IsPowerOfTwo(ndir))
+ if((atom_flags & ATOM_FLAG_BLOCK_DIAGONAL_FACING) && !IsPowerOfTwo(ndir))
if(old_dir & ndir)
ndir = old_dir
else
diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm
index 3c40d700aad..3610367a7cd 100644
--- a/code/datums/observation/~cleanup.dm
+++ b/code/datums/observation/~cleanup.dm
@@ -44,7 +44,7 @@ var/global/list/event_listen_count = list()
for(var/entry in global.all_observable_events)
var/decl/observ/event = entry
if(event.unregister_global(listener))
- log_debug("[event] - [listener] was deleted while still registered to global events.")
+ log_debug("[event] ([event.type]) - [log_info_line(listener)] was deleted while still registered to global events.")
if(!(--listen_count))
return
@@ -56,7 +56,7 @@ var/global/list/event_listen_count = list()
if(proc_owners)
for(var/proc_owner in proc_owners)
if(event.unregister(event_source, proc_owner))
- log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].")
+ log_debug("[event] ([event.type]) - [log_info_line(event_source)] was deleted while still being listened to by [log_info_line(proc_owner)].")
if(!(--source_listener_count))
return
@@ -66,6 +66,6 @@ var/global/list/event_listen_count = list()
var/decl/observ/event = entry
for(var/event_source in event.event_sources)
if(event.unregister(event_source, listener))
- log_debug("[event] - [listener] was deleted while still listening to [event_source].")
+ log_debug("[event] ([event.type]) - [log_info_line(listener)] was deleted while still listening to [log_info_line(event_source)].")
if(!(--listener_count))
return
diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm
index db0b321f57d..09a78eb3948 100644
--- a/code/datums/recipe.dm
+++ b/code/datums/recipe.dm
@@ -13,6 +13,22 @@
var/result // example: = /obj/item/chems/food/donut/normal
var/time = 100 // Cooking time in deciseconds.
var/result_quantity = 1 // How many items to create. Where possible, just use fewer ingredients instead.
+ var/coating = null // Required coating on all items in the recipe. The default value of null explitly requires no coating
+ // A value of -1 is permissive and cares not for any coatings
+ // Any typepath indicates a specific coating that should be present
+ // Coatings are used for batter, breadcrumbs, beer-batter, colonel's secret coating, etc
+ var/appliance = APPLIANCE_MIX // Which appliances this recipe can be made in.
+ // List of defines is in _defines/misc.dm. But for reference they are:
+ /*
+ MIX
+ FRYER
+ OVEN
+ SKILLET
+ SAUCEPAN
+ POT
+ MICROWAVE
+ */
+ // This is a bitfield, more than one type can be used.
var/const/REAGENT_REPLACE = 0 //Reagents in the ingredients are discarded (only the reagents present in the result at compiletime are used)
var/const/REAGENT_MAX = 1 //The result will contain the maximum of each reagent present between the two pools. Compiletime result, and sum of ingredients
@@ -32,12 +48,49 @@
/decl/recipe/Initialize()
. = ..()
complexity = length(reagents) + length(fruit)
- var/value
for(var/i in items) // add the number of items total
- value = items[i]
- complexity += isnum(value) ? value : 1
+ if(!items[i])
+ items[i] = 1
+ complexity += items[i]
complexity += length(uniquelist(items)) // add how many unique items there are; will prioritise burgers over 2 bunbuns and 1 wasted meat, for example
+/decl/recipe/proc/get_appliances_string()
+ var/list/appliance_names
+ if(appliance & APPLIANCE_MIX)
+ LAZYADD(appliance_names, "a mixing bowl or plate")
+ if(appliance & APPLIANCE_FRYER)
+ LAZYADD(appliance_names, "a fryer")
+ if(appliance & APPLIANCE_OVEN)
+ LAZYADD(appliance_names, "an oven")
+ if(appliance & APPLIANCE_SKILLET)
+ LAZYADD(appliance_names, "a skillet")
+ if(appliance & APPLIANCE_SAUCEPAN)
+ LAZYADD(appliance_names, "a saucepan")
+ if(appliance & APPLIANCE_POT)
+ LAZYADD(appliance_names, "a pot")
+ if(appliance & APPLIANCE_MICROWAVE)
+ LAZYADD(appliance_names, "a microwave")
+ return english_list(appliance_names, and_text = " or ")
+
+/decl/recipe/proc/get_appliance_names()
+ var/list/appliance_names
+ if(appliance & APPLIANCE_MIX)
+ LAZYADD(appliance_names, "mixing bowl")
+ LAZYADD(appliance_names, "plate")
+ if(appliance & APPLIANCE_FRYER)
+ LAZYADD(appliance_names, "fryer")
+ if(appliance & APPLIANCE_OVEN)
+ LAZYADD(appliance_names, "oven")
+ if(appliance & APPLIANCE_SKILLET)
+ LAZYADD(appliance_names, "skillet")
+ if(appliance & APPLIANCE_SAUCEPAN)
+ LAZYADD(appliance_names, "saucepan")
+ if(appliance & APPLIANCE_POT)
+ LAZYADD(appliance_names, "pot")
+ if(appliance & APPLIANCE_MICROWAVE)
+ LAZYADD(appliance_names, "microwave")
+ return appliance_names
+
/decl/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
SHOULD_BE_PURE(TRUE)
if(length(avail_reagents?.reagent_volumes) < length(reagents))
@@ -51,37 +104,43 @@
SHOULD_BE_PURE(TRUE)
if(!length(fruit))
return TRUE
- var/container_contents = container?.get_contained_external_atoms()
+ var/list/container_contents = container?.get_contained_external_atoms()
if(length(container_contents) < length(fruit))
return FALSE
var/list/needed_fruits = fruit.Copy()
for(var/obj/item/chems/food/S in container_contents)
- var/use_tag
- if(istype(S, /obj/item/chems/food/grown))
- var/obj/item/chems/food/grown/G = S
- if(!G.seed || !G.seed.kitchen_tag)
- continue
- use_tag = G.dry ? "dried [G.seed.kitchen_tag]" : G.seed.kitchen_tag
- else if(istype(S, /obj/item/chems/food/fruit_slice))
- var/obj/item/chems/food/fruit_slice/FS = S
- if(!FS.seed || !FS.seed.kitchen_tag)
- continue
- use_tag = "[FS.seed.kitchen_tag] slice"
- use_tag = "[S.dry ? "dried " : ""][use_tag]"
+ var/list/tags = S.get_kitchen_tags()
+ if(!LAZYLEN(tags))
+ continue
+ var/use_tag = tags.Join(" ")
if(isnull(needed_fruits[use_tag]))
continue
- needed_fruits[use_tag]--
+ if(check_coating(S))
+ needed_fruits[use_tag]--
for(var/ktag in needed_fruits)
if(needed_fruits[ktag] > 0)
return FALSE
return TRUE
+//This is called on individual items within the container.
+/decl/recipe/proc/check_coating(var/obj/item/chems/food/S)
+ if(!istype(S))
+ return TRUE//Only snacks can be battered
+
+ if (coating == -1)
+ return TRUE //-1 value doesnt care
+
+ return S.batter_coating == coating
+
/decl/recipe/proc/check_items(var/obj/container)
SHOULD_BE_PURE(TRUE)
if(!length(items))
return TRUE
var/list/container_contents = container?.get_contained_external_atoms()
- if(length(container_contents) < length(items))
+ var/sum = 0
+ for(var/i in items)
+ sum += items[i]
+ if(length(container_contents) < sum)
return FALSE
var/list/needed_items = items.Copy()
for(var/itype in needed_items)
@@ -89,16 +148,18 @@
if(!istype(thing, itype))
continue
container_contents -= thing
- if(isnum(needed_items[itype]))
- --needed_items[itype]
- if(needed_items[itype] <= 0)
- needed_items -= itype
- else
+ if(!check_coating(thing))
+ continue
+ needed_items[itype]--
+ if(needed_items[itype] <= 0)
needed_items -= itype
- break
+ break
if(!length(container_contents))
break
- return !length(needed_items)
+ sum = 0
+ for(var/i in needed_items)
+ sum += needed_items[i]
+ return !sum
//general version
/decl/recipe/proc/make(var/obj/container)
@@ -123,14 +184,15 @@
to decide what to do. They may be used again to make another recipe or discarded, or merged into the results,
thats no longer the concern of this proc
*/
- var/datum/reagents/buffer = new /datum/reagents(1e12, global.temp_reagents_holder)//
+ var/datum/reagents/buffer = new /datum/reagents(INFINITY, global.temp_reagents_holder)//
var/list/container_contents = container.get_contained_external_atoms()
//Find items we need
- if (LAZYLEN(items))
- for (var/i in items)
+ for (var/i in items)
+ for(var/_ in 1 to items[i])
var/obj/item/I = locate(i) in container_contents
if (I && I.reagents)
I.reagents.trans_to_holder(buffer,I.reagents.total_volume)
+ container_contents -= I
qdel(I)
//Find fruits
@@ -214,6 +276,21 @@
//If we're here, then holder is a buffer containing the total reagents for all the results.
//So now we redistribute it among them
var/total = holder.total_volume
- for(var/atom/a AS_ANYTHING in results)
- holder.trans_to(a, total / length(results))
- return results
\ No newline at end of file
+ for (var/atom/a as anything in results)
+ holder.trans_to_obj(a, total / length(results))
+ return results
+
+/proc/select_recipe(var/obj/container, var/appliance)
+ if(!appliance)
+ CRASH("Null appliance flag passed to select_recipe!")
+ var/highest_complexity = 0
+ var/available_recipes = decls_repository.get_decls_of_subtype(/decl/recipe)
+ for (var/rtype in available_recipes)
+ var/decl/recipe/recipe = available_recipes[rtype]
+ if(!(appliance & recipe.appliance))
+ continue
+ if(!recipe.check_reagents(container.reagents) || !recipe.check_items(container) || !recipe.check_fruit(container))
+ continue
+ if(recipe.complexity >= highest_complexity)
+ highest_complexity = recipe.complexity
+ . = recipe
diff --git a/code/datums/security_state.dm b/code/datums/security_state.dm
index abd8e0da125..f1bbdb3ea1a 100644
--- a/code/datums/security_state.dm
+++ b/code/datums/security_state.dm
@@ -62,10 +62,11 @@
comm_console_security_levels = list()
// Setup the list of selectable security levels available in the comm. console
- for(var/security_level in all_security_levels)
+ for(var/decl/security_level/security_level in all_security_levels)
if(security_level == highest_standard_security_level)
break
- comm_console_security_levels += security_level
+ if(security_level.selectable)
+ comm_console_security_levels += security_level
// Now we ensure the high security level is not above the severe one (but we allow them to be equal)
var/severe_index = all_security_levels.Find(severe_security_level)
@@ -149,6 +150,8 @@
var/up_description
var/down_description
+ var/selectable = TRUE
+
var/datum/alarm_appearance/alarm_appearance
/decl/security_level/Initialize()
@@ -181,8 +184,8 @@
/decl/security_level/default
icon = 'icons/misc/security_state.dmi'
- var/static/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg'))
- var/static/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg'))
+ var/static/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('maps/torch/sounds/minor_alert.ogg'))
+ var/static/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1, new_sound = sound('maps/torch/sounds/minor_alert.ogg'))
/decl/security_level/default/switching_up_to()
if(up_description)
@@ -293,6 +296,21 @@
alarm_icon = "alarm_normal"
alarm_icon_color = PIPE_COLOR_GREEN
+/decl/security_level/default/code_yellow
+ name = "code yellow"
+ icon = 'icons/misc/security_state.dmi'
+
+ light_color_alarm = COLOR_YELLOW_GRAY
+ light_color_status_display = COLOR_YELLOW_GRAY
+ overlay_alarm = "alarm_orange"
+ overlay_status_display = "status_display_orange"
+ alarm_appearance = /datum/alarm_appearance/yellow
+
+ up_description = "Subsector FTL Procedures are now in effect; observe modified Code Orange protocols, secure all stations for superluminal transition. EVA Ban in effect."
+ down_description = "Subsector FTL Procedures are now in effect; observe modified Code Orange protocols, secure all stations for superluminal transition. EVA Ban in effect."
+
+ selectable = FALSE
+
/datum/alarm_appearance/blue
display_icon = "status_display_lines"
display_icon_color = COLOR_BLUE
@@ -327,4 +345,14 @@
alarm_icon_color = COLOR_RED
alarm_icon_twotone = "alarm_blinking_twotone2"
- alarm_icon_twotone_color = PIPE_COLOR_YELLOW
\ No newline at end of file
+ alarm_icon_twotone_color = PIPE_COLOR_YELLOW
+
+/datum/alarm_appearance/yellow
+ display_icon = "status_display_lines"
+ display_icon_color = COLOR_YELLOW_GRAY
+
+ display_emblem = "status_display_ftl"
+ display_emblem_color = COLOR_WHITE
+
+ alarm_icon = "alarm_normal"
+ alarm_icon_color = COLOR_YELLOW_GRAY
\ No newline at end of file
diff --git a/code/datums/sound_player.dm b/code/datums/sound_player.dm
index ab4f31d4a6b..47b92d9fd45 100644
--- a/code/datums/sound_player.dm
+++ b/code/datums/sound_player.dm
@@ -80,7 +80,7 @@
*/
/datum/sound_token
var/atom/source // Where the sound originates from
- var/list/listeners // Assoc: Atoms hearing this sound, and their sound datum
+ var/list/listeners // Atoms hearing this sound
var/range // How many turfs away the sound will stop playing completely
var/prefer_mute // If sound should be muted instead of stopped when mob moves out of range. In the general case this should be avoided because listeners will remain tracked.
var/sound/sound // Sound datum, holds most sound relevant data
@@ -204,7 +204,7 @@
PrivUpdateListeners()
/datum/sound_token/proc/PrivAddListener(var/atom/listener)
- if(!check_preference(listener))
+ if(QDELETED(listener) || !check_preference(listener))
return
if(isvirtualmob(listener))
@@ -259,8 +259,8 @@
for(var/listener in listeners)
PrivUpdateListener(listener)
-/datum/sound_token/proc/PrivUpdateListener(var/listener, var/update_sound = TRUE)
- if(!check_preference(listener))
+/datum/sound_token/proc/PrivUpdateListener(var/atom/listener, var/update_sound = TRUE)
+ if(QDELETED(listener) || !check_preference(listener))
PrivRemoveListener(listener)
return
@@ -271,7 +271,7 @@
sound.status |= SOUND_UPDATE
sound_to(listener, sound)
-/datum/sound_token/proc/PrivGetEnvironment(var/listener)
+/datum/sound_token/proc/PrivGetEnvironment(var/atom/listener)
var/area/A = get_area(listener)
return A && PrivIsValidEnvironment(A.sound_env) ? A.sound_env : sound.environment
diff --git a/code/datums/supplypacks/dispcarts.dm b/code/datums/supplypacks/dispcarts.dm
index dcaddd40fcb..10c091494c2 100644
--- a/code/datums/supplypacks/dispcarts.dm
+++ b/code/datums/supplypacks/dispcarts.dm
@@ -86,6 +86,3 @@ PACK(syrup_chocolate, /obj/item/chems/chem_disp_cartridge/syrup_chocolate, "Reag
PACK(syrup_caramel, /obj/item/chems/chem_disp_cartridge/syrup_caramel, "Reagent refill - Caramel Syrup", "caramel syrup reagent cartridge crate")
PACK(syrup_vanilla, /obj/item/chems/chem_disp_cartridge/syrup_vanilla, "Reagent refill - Vanilla Syrup", "vanilla syrup reagent cartridge crate")
PACK(syrup_pumpkin, /obj/item/chems/chem_disp_cartridge/syrup_pumpkin, "Reagent refill - Pumpkin Spice Syrup", "pumpkin spice syrup reagent cartridge crate")
-
-#undef SEC_PACK
-#undef PACK
diff --git a/code/datums/supplypacks/operations.dm b/code/datums/supplypacks/operations.dm
index 59e82647bbc..cb594f257ea 100644
--- a/code/datums/supplypacks/operations.dm
+++ b/code/datums/supplypacks/operations.dm
@@ -90,7 +90,7 @@
/obj/item/folder/red,
/obj/item/folder/yellow,
/obj/item/hand_labeler,
- /obj/item/tape_roll,
+ /obj/item/ducttape,
/obj/structure/filingcabinet/chestdrawer,
/obj/item/paper_bin)
name = "Office supplies"
diff --git a/code/datums/supplypacks/supply.dm b/code/datums/supplypacks/supply.dm
index 757bd1eda08..a4e8f9849b0 100644
--- a/code/datums/supplypacks/supply.dm
+++ b/code/datums/supplypacks/supply.dm
@@ -57,6 +57,12 @@
contains = list (/obj/item/storage/box/water = 2)
containername = "bottled water crate"
+/decl/hierarchy/supply_pack/supply/hand_truck
+ name = "Hand Truck"
+ contains = list(/obj/structure/hand_cart)
+ containertype = /obj/structure/largecrate
+ containername = "Hand Truck crate"
+
/decl/hierarchy/supply_pack/supply/sodas
num_contained = 2
contains = list(/obj/item/storage/box/cola,
diff --git a/code/datums/uplink/devices and tools.dm b/code/datums/uplink/devices and tools.dm
index eb05d6d9a28..788163c0a5c 100644
--- a/code/datums/uplink/devices and tools.dm
+++ b/code/datums/uplink/devices and tools.dm
@@ -15,7 +15,7 @@
name = "Duct Tape"
desc = "A roll of duct tape. changes \"HELP\" into sexy \"mmm\"."
item_cost = 2
- path = /obj/item/tape_roll
+ path = /obj/item/ducttape
/datum/uplink_item/item/tools/money
name = "Operations Funding"
diff --git a/code/datums/vote/custom.dm b/code/datums/vote/custom.dm
index b783c749dea..ba32ded269e 100644
--- a/code/datums/vote/custom.dm
+++ b/code/datums/vote/custom.dm
@@ -12,7 +12,7 @@
return ..()
/datum/vote/custom/setup_vote(mob/creator, automatic)
- question = sanitizeSafe(input(creator,"What is the vote for?") as text|null)
+ question = sanitize_safe(input(creator,"What is the vote for?") as text|null)
if(!question)
abort = 1
return
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 3d517675a7e..db45e4380a3 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -1,12 +1,11 @@
/decl/special_role
abstract_type = /decl/special_role
-
// Text shown when becoming this antagonist.
var/list/restricted_jobs = list() // Jobs that cannot be this antagonist at roundstart (depending on config)
var/list/protected_jobs = list() // As above.
var/list/blocked_job_event_categories // Job event categories that blacklist a job from being this antagonist.
// Jobs that can NEVER be this antagonist
- var/list/blacklisted_jobs = (/datum/job/submap)
+ var/list/blacklisted_jobs = (/datum/job/submap)
// Strings.
var/welcome_text = "Cry havoc and let slip the dogs of war!"
@@ -85,7 +84,7 @@
and before taking extreme actions, please try to also contact the administration! \
Think through your actions and make the roleplay immersive! Please remember all \
rules aside from those without explicit exceptions apply to antagonists."
-
+
// Map template that antag needs to load before spawning. Nulled after it's loaded.
var/datum/map_template/base_to_load
@@ -104,9 +103,9 @@
if(antaghud_indicator)
if(!global.hud_icon_reference)
global.hud_icon_reference = list()
- if(name)
+ if(name)
global.hud_icon_reference[name] = antaghud_indicator
- if(faction_name)
+ if(faction_name)
global.hud_icon_reference[faction_name] = antaghud_indicator
/decl/special_role/proc/get_antag_text(mob/recipient)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index c9c7f3a672e..8542a650d98 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -580,7 +580,11 @@ its easier to just keep the beam vertical.
var/matrix/M = matrix()
M.Scale(icon_scale_x, icon_scale_y)
M.Turn(icon_rotation)
- animate(src, transform = M, transform_animate_time)
+ if(transform_animate_time)
+ animate(src, transform = M, transform_animate_time)
+ else
+ transform = M
+ return transform
// Walks up the loc tree until it finds a loc of the given loc_type
/atom/get_recursive_loc_of_type(var/loc_type)
diff --git a/code/game/atoms_init.dm b/code/game/atoms_init.dm
index a11aba7fa38..48db58219d9 100644
--- a/code/game/atoms_init.dm
+++ b/code/game/atoms_init.dm
@@ -71,6 +71,8 @@
LAZYCLEARLIST(our_overlays)
LAZYCLEARLIST(priority_overlays)
+ LAZYCLEARLIST(climbers)
+
QDEL_NULL(light)
if(opacity)
@@ -93,7 +95,17 @@
loc.Entered(src, null)
/atom/movable/Destroy()
- . = ..()
+ // These must be done before event cleanup in the parent call
+ if(LAZYLEN(movement_handlers) && !ispath(movement_handlers[1]))
+ QDEL_NULL_LIST(movement_handlers)
+
+ if (bound_overlay)
+ QDEL_NULL(bound_overlay)
+
+ if(virtual_mob && !ispath(virtual_mob))
+ qdel(virtual_mob)
+ virtual_mob = null
+
#ifdef DISABLE_DEBUG_CRASH
// meh do nothing. we know what we're doing. pro engineers.
#else
@@ -106,12 +118,7 @@
forceMove(null)
- if(LAZYLEN(movement_handlers) && !ispath(movement_handlers[1]))
- QDEL_NULL_LIST(movement_handlers)
-
- if (bound_overlay)
- QDEL_NULL(bound_overlay)
+ vis_locs = null //clears this atom out of all vis_contents
+ vis_contents.Cut()
- if(virtual_mob && !ispath(virtual_mob))
- qdel(virtual_mob)
- virtual_mob = null
+ . = ..() // called last so that events are unregistered before the parent call
diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm
index c02bc4be338..ccfaea16d32 100644
--- a/code/game/gamemodes/objectives/_objective.dm
+++ b/code/game/gamemodes/objectives/_objective.dm
@@ -14,6 +14,8 @@ var/global/list/all_objectives = list()
/datum/objective/Destroy()
global.all_objectives -= src
+ owner = null
+ target = null
. = ..()
/datum/objective/proc/find_target()
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index ec7b2849251..5fca1d98f41 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -35,7 +35,7 @@
/obj/machinery/sleeper/standard/Initialize(mapload, d, populate_parts)
. = ..()
- add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/stabilizer())
+ add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/stabilizer())
add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/sedatives())
add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/painkillers())
add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/antitoxins())
@@ -263,7 +263,7 @@
to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them."))
else if(panel_open)
to_chat(user, SPAN_WARNING("Close the maintenance panel before attempting to place the subject in the sleeper."))
- else
+ else
go_in(target, user)
return TRUE
@@ -318,6 +318,11 @@
if(close_sound)
playsound(src, close_sound, 40)
+/obj/machinery/sleeper/get_contained_external_atoms()
+ . = ..()
+ LAZYREMOVE(., loaded_canisters)
+ LAZYREMOVE(., beaker)
+
/obj/machinery/sleeper/proc/go_out()
if(!occupant)
return
@@ -329,9 +334,6 @@
if(open_sound)
playsound(src, open_sound, 40)
- for(var/obj/O in (contents - (component_parts + loaded_canisters))) // In case an object was dropped inside or something. Excludes the beaker and component parts.
- if(O != beaker)
- O.dropInto(loc)
toggle_filter()
/obj/machinery/sleeper/proc/set_occupant(var/mob/living/carbon/occupant)
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 23f8ce81acb..2ed558621a9 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -128,7 +128,7 @@
. = ..()
/obj/machinery/alarm/Destroy()
- events_repository.unregister(/decl/observ/name_set, src, get_area(src), .proc/change_area_name)
+ events_repository.unregister(/decl/observ/name_set, get_area(src), src, .proc/change_area_name)
unregister_radio(src, frequency)
return ..()
diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm
index 93fe942d7a0..235be870e8a 100644
--- a/code/game/machinery/atmo_control.dm
+++ b/code/game/machinery/atmo_control.dm
@@ -222,32 +222,32 @@
return TOPIC_REFRESH
if(href_list["set_input_tag"])
- var/t = sanitizeSafe(input(usr, "Enter the input ID tag.", src.name, src.input_tag), MAX_NAME_LEN)
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ var/t = sanitize_safe(input(usr, "Enter the input ID tag.", src.name, src.input_tag), MAX_NAME_LEN)
+ t = sanitize_safe(t, MAX_NAME_LEN)
if (t)
src.input_tag = t
set_frequency(frequency)
return TOPIC_REFRESH
if(href_list["set_output_tag"])
- var/t = sanitizeSafe(input(usr, "Enter the output ID tag.", src.name, src.output_tag), MAX_NAME_LEN)
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ var/t = sanitize_safe(input(usr, "Enter the output ID tag.", src.name, src.output_tag), MAX_NAME_LEN)
+ t = sanitize_safe(t, MAX_NAME_LEN)
if (t)
src.output_tag = t
set_frequency(frequency)
return TOPIC_REFRESH
if(href_list["set_sensor_tag"])
- var/t = sanitizeSafe(input(usr, "Enter the sensor ID tag.", src.name, src.sensor_tag))
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ var/t = sanitize_safe(input(usr, "Enter the sensor ID tag.", src.name, src.sensor_tag))
+ t = sanitize_safe(t, MAX_NAME_LEN)
if(t)
src.sensor_tag = t
set_frequency(frequency)
return TOPIC_REFRESH
if(href_list["set_sensor_name"])
- var/t = sanitizeSafe(input(usr, "Enter the sensor name.", src.name, src.sensor_name))
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ var/t = sanitize_safe(input(usr, "Enter the sensor name.", src.name, src.sensor_name))
+ t = sanitize_safe(t, MAX_NAME_LEN)
if(t)
src.sensor_name = t
return TOPIC_REFRESH
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 23a989f7785..04ab8cc6737 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -20,6 +20,7 @@
var/list/scrubbing_gas
+
/obj/machinery/portable_atmospherics/powered/scrubber/Initialize()
. = ..()
if(!scrubbing_gas)
diff --git a/code/game/machinery/bodyscanner.dm b/code/game/machinery/bodyscanner.dm
index 603b0571e37..1bbb5e45066 100644
--- a/code/game/machinery/bodyscanner.dm
+++ b/code/game/machinery/bodyscanner.dm
@@ -45,7 +45,7 @@
usr.client.eye = src
/obj/machinery/bodyscanner/proc/drop_contents()
- for(var/obj/O in (contents - component_parts))
+ for(var/obj/O in get_contained_external_atoms())
O.dropInto(loc)
/obj/machinery/bodyscanner/proc/go_out()
diff --git a/code/game/machinery/bodyscanner_console.dm b/code/game/machinery/bodyscanner_console.dm
index 1bd8108b490..60f5b92206e 100644
--- a/code/game/machinery/bodyscanner_console.dm
+++ b/code/game/machinery/bodyscanner_console.dm
@@ -1,5 +1,5 @@
/obj/machinery/body_scanconsole
- var/obj/machinery/bodyscanner/connected
+ var/obj/machinery/bodyscanner/connected
var/stored_scan_subject
name = "Body Scanner Console"
icon = 'icons/obj/Cryogenic2.dmi'
@@ -20,7 +20,7 @@
/obj/machinery/body_scanconsole/on_update_icon()
if(stat & (BROKEN | NOPOWER))
- icon_state = "body_scannerconsole-p"
+ icon_state = "body_scannerconsole-p"
else
icon_state = initial(icon_state)
@@ -31,13 +31,14 @@
break
events_repository.register(/decl/observ/destroyed, connected, src, .proc/unlink_scanner)
-/obj/machinery/body_scanconsole/proc/unlink_scanner(var/obj/machinery/bodyscanner/scanner)
+/obj/machinery/body_scanconsole/proc/unlink_scanner(var/obj/machinery/bodyscanner/scanner)
events_repository.unregister(/decl/observ/destroyed, scanner, src, .proc/unlink_scanner)
connected = null
/obj/machinery/body_scanconsole/proc/FindDisplays()
for(var/obj/machinery/body_scan_display/D in SSmachines.machinery)
- if(D.tag in display_tags)
+ // TODO: Convert to use networking
+ if(D.id_tag in display_tags)
connected_displays += D
events_repository.register(/decl/observ/destroyed, D, src, .proc/remove_display)
return !!connected_displays.len
@@ -97,7 +98,7 @@
data["html_scan_header"] = display_medical_data_header(data["scan"], user.get_skill_value(SKILL_MEDICAL))
data["html_scan_health"] = display_medical_data_health(data["scan"], user.get_skill_value(SKILL_MEDICAL))
data["html_scan_body"] = display_medical_data_body(data["scan"], user.get_skill_value(SKILL_MEDICAL))
-
+
stored_scan_subject = connected.occupant
user.visible_message("\The [user] performs a scan of \the [connected.occupant] using \the [connected].")
playsound(connected.loc, 'sound/machines/medbayscanner.ogg', 50)
@@ -111,7 +112,7 @@
new /obj/item/paper/bodyscan(loc, "Printout error.", "Body scan report - [stored_scan_subject]", scan.Copy())
return TOPIC_REFRESH
- if(href_list["push"])
+ if(href_list["push"])
if(!connected_displays.len && !FindDisplays())
to_chat(user, "[html_icon(src)]Error: No configured displays detected.")
return TOPIC_REFRESH
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index cd40f066a19..f153ddc892a 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -156,7 +156,6 @@
var/mob/occupant = null // Person waiting to be despawned.
var/time_till_despawn = 9000 // Down to 15 minutes //30 minutes-ish is too long
var/time_entered = 0 // Used to keep track of the safe period.
- var/obj/item/radio/intercom/announce //
var/obj/machinery/computer/cryopod/control_computer
var/last_no_computer_message = 0
@@ -185,6 +184,10 @@
var/open_sound = 'sound/machines/podopen.ogg'
var/close_sound = 'sound/machines/podclose.ogg'
+/obj/machinery/cryopod/get_contained_external_atoms()
+ . = ..()
+ LAZYREMOVE(., occupant)
+
/obj/machinery/cryopod/robot
name = "robotic storage unit"
desc = "A storage unit for robots."
@@ -262,7 +265,6 @@
/obj/machinery/cryopod/Initialize()
. = ..()
- announce = new /obj/item/radio/intercom(src)
find_control_computer()
/obj/machinery/cryopod/proc/find_control_computer()
@@ -324,7 +326,7 @@
qdel(R.mmi)
for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc
- for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags
+ for(var/obj/item/O in I.get_contained_external_atoms()) // the things inside the tools, if anything; mainly for janiborg trash bags
O.forceMove(R)
qdel(I)
qdel(R.module)
@@ -335,23 +337,18 @@
// Also make sure there is a valid control computer
/obj/machinery/cryopod/proc/despawn_occupant()
//Drop all items into the pod.
- for(var/obj/item/W in occupant)
+ for(var/obj/item/W in occupant.get_equipped_items(include_carried = TRUE))
occupant.drop_from_inventory(W)
W.forceMove(src)
- if(W.contents.len) //Make sure we catch anything not handled by qdel() on the items.
- for(var/obj/item/O in W.contents)
- if(istype(O,/obj/item/storage/internal)) //Stop eating pockets, you fuck!
- continue
- O.forceMove(src)
+ //Make sure we catch anything not handled by qdel() on the items.
+ for(var/obj/item/O in W.get_contained_external_atoms())
+ if(istype(O,/obj/item/storage/internal)) //Stop eating pockets, you fuck!
+ continue
+ O.forceMove(src)
//Delete all items not on the preservation list.
- var/list/items = src.contents.Copy()
- items -= occupant // Don't delete the occupant
- items -= announce // or the autosay radio.
- items -= component_parts
-
- for(var/obj/item/W in items)
+ for(var/obj/item/W in get_contained_external_atoms())
var/preserve = null
// Snowflaaaake.
@@ -374,7 +371,7 @@
control_computer.frozen_items += W
W.forceMove(null)
else
- W.forceMove(src.loc)
+ W.forceMove(get_turf(src))
//Update any existing objectives involving this mob.
for(var/datum/objective/O in global.all_objectives)
@@ -417,7 +414,8 @@
control_computer._admin_logs += "[key_name(occupant)] ([role_alt_title]) at [stationtime2text()]"
log_and_message_admins("[key_name(occupant)] ([role_alt_title]) entered cryostorage.")
- announce.autosay("[occupant.real_name], [role_alt_title], [on_store_message]", "[on_store_name]")
+ var/obj/item/radio/announcer = get_global_announcer()
+ announcer.autosay("[occupant.real_name], [role_alt_title], [on_store_message]", "[on_store_name]")
visible_message("\The [initial(name)] hums and hisses as it moves [occupant.real_name] into storage.", range = 3)
//This should guarantee that ghosts don't spawn.
@@ -486,9 +484,7 @@
icon_state = base_icon_state
//Eject any items that aren't meant to be in the pod.
- var/list/items = contents - component_parts
- if(occupant) items -= occupant
- if(announce) items -= announce
+ var/list/items = get_contained_external_atoms()
for(var/obj/item/W in items)
W.dropInto(loc)
diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm
deleted file mode 100644
index a6fb75d8efd..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/_cooker.dm
+++ /dev/null
@@ -1,236 +0,0 @@
-// This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed.
-
-// Tracks precooked food to stop deep fried baked grilled grilled grilled monkey cereal.
-/obj/item/chems/food/var/list/cooked
-
-// Root type for cooking machines. See following files for specific implementations.
-/obj/machinery/cooker
- name = "cooker"
- desc = "You shouldn't be seeing this!"
- icon = 'icons/obj/cooking_machines.dmi'
- density = 1
- anchored = 1
- idle_power_usage = 5
- construct_state = /decl/machine_construction/default/panel_closed
- uncreated_component_parts = null
- stat_immune = 0
-
- var/on_icon // Icon state used when cooking.
- var/off_icon // Icon state used when not cooking.
- var/cooking // Whether or not the machine is currently operating.
- var/cook_type // A string value used to track what kind of food this machine makes.
- var/cook_time = 200 // How many ticks the cooking will take.
- var/can_cook_mobs // Whether or not this machine accepts grabbed mobs.
- var/food_color // Colour of resulting food item.
- var/cooked_sound // Sound played when cooking completes.
- var/can_burn_food // Can the object burn food that is left inside?
- var/burn_chance = 10 // How likely is the food to burn?
- var/obj/item/cooking_obj // Holder for the currently cooking object.
-
- // If the machine has multiple output modes, define them here.
- var/selected_option
- var/list/output_options = list()
-
-/obj/machinery/cooker/Destroy()
- if(cooking_obj)
- qdel(cooking_obj)
- cooking_obj = null
- return ..()
-
-/obj/machinery/cooker/examine(mob/user)
- . = ..()
- if(cooking_obj)
- to_chat(user, "You can see \a [cooking_obj] inside.")
- if(panel_open)
- to_chat(user, "The panel is open.")
-
-/obj/machinery/cooker/components_are_accessible(path)
- return !cooking && ..()
-
-/obj/machinery/cooker/cannot_transition_to(state_path, mob/user)
- if(cooking)
- return SPAN_NOTICE("Wait for \the [src] to finish first!")
- return ..()
-
-/obj/machinery/cooker/attackby(var/obj/item/I, var/mob/user)
- set waitfor = 0 //So that any remaining parts of calling proc don't have to wait for the long cooking time ahead.
-
- if(cooking)
- to_chat(user, "\The [src] is running!")
- return
-
- if((. = component_attackby(I, user)))
- return
-
- if(!cook_type || (stat & (NOPOWER|BROKEN)))
- to_chat(user, "\The [src] is not working.")
- return
-
- // We are trying to cook a grabbed mob.
- var/obj/item/grab/G = I
- if(istype(G))
-
- if(!can_cook_mobs)
- to_chat(user, "That's not going to fit.")
- return
-
- if(!isliving(G.affecting))
- to_chat(user, "You can't cook that.")
- return
-
- cook_mob(G.affecting, user)
- return
-
- // We're trying to cook something else. Check if it's valid.
- var/obj/item/chems/food/check = I
- if(istype(check) && islist(check.cooked) && (cook_type in check.cooked))
- to_chat(user, "\The [check] has already been [cook_type].")
- return 0
- else if(istype(check, /obj/item/chems/glass))
- to_chat(user, "That would probably break [src].")
- return 0
- else if(istype(check, /obj/item/disk/nuclear))
- to_chat(user, "Central Command would kill you if you [cook_type] that.")
- return 0
- else if(!istype(check) && !istype(check, /obj/item/holder))
- to_chat(user, "That's not edible.")
- return 0
-
- // Gotta hurt.
- if(istype(cooking_obj, /obj/item/holder))
- for(var/mob/living/M in cooking_obj.contents)
- M.apply_damage(rand(30,40), BURN, BP_CHEST)
-
- // Not sure why a food item that passed the previous checks would fail to drop, but safety first.
- if(!user.unEquip(I))
- return
-
- // We can actually start cooking now.
- user.visible_message("\The [user] puts \the [I] into \the [src].")
- cooking_obj = I
- cooking_obj.forceMove(src)
- cooking = 1
- icon_state = on_icon
-
- // Doop de doo. Jeopardy theme goes here.
- sleep(cook_time)
-
- // Sanity checks.
- if(check_cooking_obj())
- return // Cooking failed/was terminated.
-
- // RIP slow-moving held mobs.
- if(istype(cooking_obj, /obj/item/holder))
- for(var/mob/living/M in cooking_obj.contents)
- M.death()
- qdel(M)
-
- // Cook the food.
- var/cook_path
- if(selected_option && output_options.len)
- cook_path = output_options[selected_option]
- if(!cook_path)
- cook_path = /obj/item/chems/food/variable
- var/obj/item/chems/food/result = new cook_path(src) //Holy typepaths, Batman.
-
- if(cooking_obj.reagents && cooking_obj.reagents.total_volume)
- cooking_obj.reagents.trans_to(result, cooking_obj.reagents.total_volume)
-
- // Set icon and appearance.
- change_product_appearance(result)
-
- // Update strings.
- change_product_strings(result)
-
- // Set cooked data.
- var/obj/item/chems/food/food_item = cooking_obj
- if(istype(food_item) && islist(food_item.cooked))
- result.cooked = food_item.cooked.Copy()
- else
- result.cooked = list()
- result.cooked |= cook_type
-
- // Reset relevant variables.
- qdel(cooking_obj)
- src.visible_message("\The [src] pings!")
- if(cooked_sound)
- playsound(get_turf(src), cooked_sound, 50, 1)
-
- if(!can_burn_food)
- icon_state = off_icon
- cooking = 0
- result.dropInto(loc)
- cooking_obj = null
- else
- var/failed
- var/overcook_period = max(FLOOR(cook_time/5),1)
- cooking_obj = result
- while(1)
- sleep(overcook_period)
- if(!cooking || !result || result.loc != src)
- failed = 1
- else if(prob(burn_chance))
- // You dun goofed.
- qdel(cooking_obj)
- cooking_obj = new /obj/item/chems/food/badrecipe(src)
- // Produce nasty smoke.
- visible_message("\The [src] vomits a gout of rancid smoke!")
- var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
- smoke.attach(src)
- smoke.set_up(10, 0, usr.loc)
- smoke.start()
- failed = 1
-
- if(failed)
- cooking = 0
- icon_state = off_icon
- break
-
-/obj/machinery/cooker/proc/check_cooking_obj()
- if(!cooking_obj || cooking_obj.loc != src)
- cooking_obj = null
- icon_state = off_icon
- cooking = 0
- return TRUE
-
-/obj/machinery/cooker/physical_attack_hand(var/mob/user)
- if(cooking_obj)
- to_chat(user, "You grab \the [cooking_obj] from \the [src].")
- user.put_in_hands(cooking_obj)
- cooking = 0
- cooking_obj = null
- icon_state = off_icon
- return TRUE
-
- if(output_options.len)
- if(cooking)
- to_chat(user, "\The [src] is in use!")
- return TRUE
-
- var/choice = input("What specific food do you wish to make with \the [src]?") as null|anything in output_options+"Default"
- if(!choice)
- return TRUE
- if(choice == "Default")
- selected_option = null
- to_chat(user, "You decide not to make anything specific with \the [src].")
- else
- selected_option = choice
- to_chat(user, "You prepare \the [src] to make \a [selected_option].")
- return TRUE
-
-/obj/machinery/cooker/proc/cook_mob(var/mob/living/victim, var/mob/user)
- return
-
-/obj/machinery/cooker/proc/change_product_strings(var/obj/item/chems/food/product)
- if(product.type == /obj/item/chems/food/variable) // Base type, generic.
- product.SetName("[cook_type] [cooking_obj.name]")
- product.desc = "[cooking_obj.desc] It has been [cook_type]."
- else
- product.SetName("[cooking_obj.name] [product.name]")
-
-/obj/machinery/cooker/proc/change_product_appearance(var/obj/item/chems/food/product)
- if(istype(product))
- if(istype(cooking_obj, /obj/item/chems/food))
- var/obj/item/chems/food/S = cooking_obj
- food_color = S.filling_color
- product.update_food_appearance_from(cooking_obj, food_color)
diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm
deleted file mode 100644
index 7f279bd0561..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm
+++ /dev/null
@@ -1,93 +0,0 @@
-// Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn.
-/obj/item/chems/food/variable
- name = "cooked food"
- icon = 'icons/obj/food_custom.dmi'
- desc = "If you can see this description then something is wrong. Please report the bug on the tracker."
- nutriment_amt = 5
- bitesize = 2
- filling_color = COLOR_BROWN
-
-/obj/item/chems/food/variable/Initialize()
- . = ..()
- update_icon()
-
-/obj/item/chems/food/variable/update_food_appearance_from(var/obj/item/donor, var/food_color, var/copy_donor_appearance = TRUE)
- ..(donor, food_color, (type == /obj/item/chems/food/variable)) // variable is used for generic foods (deep fried X), subtypes are used for specific foods
-
-/obj/item/chems/food/variable/pizza
- name = "personal pizza"
- desc = "A personalized pan pizza meant for only one person."
- icon_state = "personal_pizza"
-
-/obj/item/chems/food/variable/bread
- name = "bread"
- desc = "Tasty bread."
- icon_state = "breadcustom"
-
-/obj/item/chems/food/variable/pie
- name = "pie"
- desc = "Tasty pie."
- icon_state = "piecustom"
-
-/obj/item/chems/food/variable/cake
- name = "cake"
- desc = "A popular band."
- icon_state = "cakecustom"
-
-/obj/item/chems/food/variable/pocket
- name = "hot pocket"
- desc = "You wanna put a bangin- oh, nevermind."
- icon_state = "donk"
- filling_color = COLOR_BROWN
-
-/obj/item/chems/food/variable/kebab
- name = "kebab"
- desc = "Food is just tastier on a stick!"
- icon_state = "kabob"
- filling_color = COLOR_DARK_RED
-
-/obj/item/chems/food/variable/waffles
- name = "waffles"
- desc = "Made with love."
- icon_state = "waffles"
- gender = PLURAL
-
-/obj/item/chems/food/variable/pancakes
- name = "pancakes"
- desc = "How does an oven make pancakes?"
- icon_state = "pancakescustom"
- gender = PLURAL
-
-/obj/item/chems/food/variable/cookie
- name = "cookie"
- desc = "Sugar snap!"
- icon_state = "cookie"
-
-/obj/item/chems/food/variable/donut
- name = "filled donut"
- desc = "Donut eat this!" // kill me
- icon_state = "donut"
-
-/obj/item/chems/food/variable/jawbreaker
- name = "flavored jawbreaker"
- desc = "It's like cracking a molar on a rainbow."
- icon_state = "jawbreaker"
- filling_color = COLOR_RED
-
-/obj/item/chems/food/variable/candybar
- name = "flavored chocolate bar"
- desc = "Made in a factory downtown."
- icon_state = "bar"
- filling_color = COLOR_DARK_BROWN
-
-/obj/item/chems/food/variable/sucker
- name = "flavored sucker"
- desc = "Suck, suck, suck."
- icon_state = "sucker"
- filling_color = COLOR_RED
-
-/obj/item/chems/food/variable/jelly
- name = "jelly"
- desc = "All your friends will be jelly."
- icon_state = "jellycustom"
- filling_color = COLOR_RED
diff --git a/code/game/machinery/kitchen/cooking_machines/cereal.dm b/code/game/machinery/kitchen/cooking_machines/cereal.dm
deleted file mode 100644
index b5a3783ff56..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/cereal.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-/obj/machinery/cooker/cereal
- name = "cereal maker"
- desc = "Now with Dann O's available!"
- icon = 'icons/obj/cooking_machines.dmi'
- icon_state = "cereal_off"
- cook_type = "cerealized"
- on_icon = "cereal_on"
- off_icon = "cereal_off"
-
-/obj/machinery/cooker/cereal/change_product_strings(var/obj/item/chems/food/product)
- . = ..()
- product.SetName("box of [cooking_obj.name] cereal")
-
-/obj/machinery/cooker/cereal/change_product_appearance(var/obj/item/chems/food/product)
- product.icon = 'icons/obj/food.dmi'
- product.icon_state = "cereal_box"
- product.filling_color = cooking_obj.color
-
- var/image/food_image = image(cooking_obj.icon, cooking_obj.icon_state)
- food_image.color = cooking_obj.color
- food_image.overlays += cooking_obj.overlays
- food_image.transform *= 0.7
-
- product.overlays += food_image
-
diff --git a/code/game/machinery/kitchen/cooking_machines/fryer.dm b/code/game/machinery/kitchen/cooking_machines/fryer.dm
deleted file mode 100644
index 0b084658b0d..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/fryer.dm
+++ /dev/null
@@ -1,50 +0,0 @@
-/obj/machinery/cooker/fryer
- name = "deep fryer"
- desc = "Deep fried everything."
- icon_state = "fryer_off"
- can_cook_mobs = 1
- cook_type = "deep fried"
- on_icon = "fryer_on"
- off_icon = "fryer_off"
- food_color = "#ffad33"
- cooked_sound = 'sound/machines/ding.ogg'
-
-/obj/machinery/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user)
-
- if(!istype(victim))
- return
-
- user.visible_message("\The [user] starts pushing \the [victim] into \the [src]!")
- icon_state = on_icon
- cooking = 1
-
- if(!do_mob(user, victim, 20))
- cooking = 0
- icon_state = off_icon
- return
-
- if(!victim || !victim.Adjacent(user))
- to_chat(user, "Your victim slipped free!")
- cooking = 0
- icon_state = off_icon
- return
-
- var/target_zone = user.zone_sel.selecting
- if(ishuman(victim) && !(target_zone in list(BP_GROIN, BP_CHEST)))
- var/mob/living/carbon/human/H = victim
- var/obj/item/organ/external/E = H.get_organ(target_zone)
- if(!E)
- to_chat(user, "They are missing that body part!")
- else
- visible_message("\The [user] shoves \the [victim][E ? "'s [E.name]" : ""] into \the [src]!")
- H.apply_damage(rand(20,30), BURN, target_zone)
-
- else
- victim.apply_damage(rand(30,40), BURN)
-
- if(victim)
- admin_attack_log(user, victim, "Has [cook_type] their victim in \a [src]", "Has been [cook_type] in \a [src] by the attacker.", "[cook_type], in \a [src], ")
-
- icon_state = off_icon
- cooking = 0
- return
diff --git a/code/game/machinery/kitchen/cooking_machines/grill.dm b/code/game/machinery/kitchen/cooking_machines/grill.dm
deleted file mode 100644
index b4f83c56adb..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/grill.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/obj/machinery/cooker/grill
- name = "griddle"
- desc = "A flat, wide, and smooth cooking surface."
- icon_state = "grill_off"
- cook_type = "grilled"
- cook_time = 100
- food_color = "#a34719"
- on_icon = "grill_on"
- off_icon = "grill_off"
- can_burn_food = 1
\ No newline at end of file
diff --git a/code/game/machinery/kitchen/cooking_machines/oven.dm b/code/game/machinery/kitchen/cooking_machines/oven.dm
deleted file mode 100644
index 5eb89e361d6..00000000000
--- a/code/game/machinery/kitchen/cooking_machines/oven.dm
+++ /dev/null
@@ -1,24 +0,0 @@
-/obj/machinery/cooker/oven
- name = "oven"
- desc = "Cookies are ready, dear."
- icon = 'icons/obj/cooking_machines.dmi'
- icon_state = "oven_off"
- on_icon = "oven_on"
- off_icon = "oven_off"
- cook_type = "baked"
- cook_time = 300
- food_color = "#a34719"
- can_burn_food = 1
-
- output_options = list(
- "Personal Pizza" = /obj/item/chems/food/variable/pizza,
- "Bread" = /obj/item/chems/food/variable/bread,
- "Pie" = /obj/item/chems/food/variable/pie,
- "Small Cake" = /obj/item/chems/food/variable/cake,
- "Hot Pocket" = /obj/item/chems/food/variable/pocket,
- "Kebab" = /obj/item/chems/food/variable/kebab,
- "Waffles" = /obj/item/chems/food/variable/waffles,
- "Pancakes" = /obj/item/chems/food/variable/pancakes,
- "Cookie" = /obj/item/chems/food/variable/cookie,
- "Donut" = /obj/item/chems/food/variable/donut,
- )
\ No newline at end of file
diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm
index a3250bc212f..41c17e1f14d 100644
--- a/code/game/machinery/kitchen/gibber.dm
+++ b/code/game/machinery/kitchen/gibber.dm
@@ -143,7 +143,7 @@
/obj/machinery/gibber/proc/go_out()
if(operating || !src.occupant)
return
- for(var/obj/O in (contents - component_parts))
+ for(var/obj/O in get_contained_external_atoms())
O.dropInto(loc)
if (src.occupant.client)
src.occupant.client.eye = src.occupant.client.mob
@@ -211,7 +211,7 @@
qdel(occupant)
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
- for (var/obj/thing in (contents - component_parts))
+ for (var/obj/thing in get_contained_external_atoms())
// There's a chance that the gibber will fail to destroy some evidence.
if(istype(thing,/obj/item/organ) && prob(80))
qdel(thing)
diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm
index 7cc2c4100c3..d1d05e87fac 100644
--- a/code/game/machinery/kitchen/microwave.dm
+++ b/code/game/machinery/kitchen/microwave.dm
@@ -202,17 +202,6 @@
/***********************************
* Microwave Menu Handling/Cooking
************************************/
-/obj/machinery/microwave/proc/select_recipe()
- var/list/all_recipes = decls_repository.get_decls_of_subtype(/decl/recipe)
- var/highest_count = 0
- for(var/rtype in all_recipes)
- var/decl/recipe/recipe = all_recipes[rtype]
- if(!istype(recipe) || !recipe.check_reagents(reagents) || !recipe.check_items(src) || !recipe.check_fruit(src))
- continue
- //okay, let's select the most complicated recipe
- if(recipe.complexity >= highest_count)
- highest_count = recipe.complexity
- . = recipe
/obj/machinery/microwave/proc/cook()
cook_break = FALSE
@@ -228,7 +217,7 @@
if (reagents.total_volume && prob(50)) // 50% chance a liquid recipe gets messy
dirty += CEILING(reagents.total_volume / 10)
- var/decl/recipe/recipe = select_recipe()
+ var/decl/recipe/recipe = select_recipe(src, APPLIANCE_MICROWAVE)
if (!recipe)
failed = TRUE
cook_time = update_cook_time()
@@ -249,21 +238,21 @@
return (ct / cooking_power)
/obj/machinery/microwave/proc/finish_cooking()
- var/decl/recipe/recipe = select_recipe()
+ var/decl/recipe/recipe = select_recipe(src, APPLIANCE_MICROWAVE)
if(!recipe)
return
- var/result = recipe.result
+ var/decl/recipe/oldrecipe = recipe
var/list/cooked_items = list()
while(recipe)
cooked_items += recipe.make_food(src)
- recipe = select_recipe()
- if (!recipe || (recipe.result != result))
+ recipe = select_recipe(src, APPLIANCE_MICROWAVE)
+ if (!recipe || recipe != oldrecipe)
break
//Any leftover reagents are divided amongst the foods
var/total = reagents.total_volume
for (var/obj/item/I in cooked_items)
- reagents.trans_to_holder(I.reagents, total/cooked_items.len)
+ reagents.trans_to_obj(I, total/cooked_items.len)
I.dropInto(loc) // since eject only ejects ingredients!
dispose(message = FALSE) //clear out anything left
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 30fb38ec304..ab0a95dfe61 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -457,7 +457,7 @@ var/global/list/allCasters = list() //Global list that will contain reference to
if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && isturf(src.loc))) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)
if(href_list["set_channel_name"])
- src.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN)
+ src.channel_name = sanitize_safe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN)
src.updateUsrDialog()
//src.update_icon()
@@ -560,7 +560,7 @@ var/global/list/allCasters = list() //Global list that will contain reference to
src.updateUsrDialog()
else if(href_list["set_wanted_name"])
- src.channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN)
+ src.channel_name = sanitize_safe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN)
src.updateUsrDialog()
else if(href_list["set_wanted_desc"])
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 45655481ebb..0bdec2de426 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -798,7 +798,7 @@ var/global/list/turret_icons
return
if(istype(I, /obj/item/pen)) //you can rename turrets like bots!
- var/t = sanitizeSafe(input(user, "Enter new turret name", name, finish_name) as text, MAX_NAME_LEN)
+ var/t = sanitize_safe(input(user, "Enter new turret name", name, finish_name) as text, MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm
index 5e872f38fa0..ba008a04f7d 100644
--- a/code/game/machinery/telecomms/machine_interactions.dm
+++ b/code/game/machinery/telecomms/machine_interactions.dm
@@ -50,11 +50,6 @@
return
return MCS_BLOCK
-/obj/machinery/telecomms/dismantle()
- for(var/obj/x in (contents - component_parts))
- x.dropInto(loc)
- . = ..()
-
// This should all be a multitool extension, but outside the scope of current rework.
/obj/machinery/telecomms/CanUseTopic(mob/user)
// You need a multitool to use this, or be silicon
@@ -135,7 +130,7 @@
dat += ""
temp = ""
-
+
var/datum/browser/written_digital/popup = new(user, "tcommmachine", "Telecommunications Machine Configuration Panel", 520, 600)
popup.set_content(JOINTEXT(dat))
popup.open()
diff --git a/code/game/machinery/vending/engineering.dm b/code/game/machinery/vending/engineering.dm
index 18d7cd188a9..d09812099b9 100644
--- a/code/game/machinery/vending/engineering.dm
+++ b/code/game/machinery/vending/engineering.dm
@@ -18,7 +18,7 @@
/obj/item/screwdriver = 5,
/obj/item/flashlight/flare/glowstick = 3,
/obj/item/flashlight/flare/glowstick/red = 3,
- /obj/item/tape_roll = 8,
+ /obj/item/ducttape = 8,
/obj/item/clothing/gloves/insulated/cheap = 2
)
contraband = list(
diff --git a/code/game/machinery/vending/medical.dm b/code/game/machinery/vending/medical.dm
index 7a8453e181a..7b278bad927 100644
--- a/code/game/machinery/vending/medical.dm
+++ b/code/game/machinery/vending/medical.dm
@@ -41,6 +41,7 @@
icon_deny = "wallmed-deny"
icon_vend = "wallmed-vend"
base_type = /obj/machinery/vending/wallmed1
+ markup = 0
density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude
products = list(
/obj/item/stack/medical/bruise_pack = 3,
@@ -60,6 +61,7 @@
icon_state = "wallmed"
icon_deny = "wallmed-deny"
icon_vend = "wallmed-vend"
+ markup = 0
density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude
base_type = /obj/machinery/vending/wallmed2
products = list(
diff --git a/code/game/machinery/vending/misc.dm b/code/game/machinery/vending/misc.dm
index c3cef8d3b58..2294deedf10 100644
--- a/code/game/machinery/vending/misc.dm
+++ b/code/game/machinery/vending/misc.dm
@@ -26,7 +26,16 @@
markup = 0
base_type = /obj/machinery/vending/dinnerware
products = list(
- /obj/item/chems/glass/beaker/bowl =2,
+ /obj/item/chems/cooking_container/plate/bowl = 4,
+ /obj/item/chems/cooking_container/plate = 4,
+ /obj/item/chems/cooking_container/fryer = 4,
+ /obj/item/chems/cooking_container/oven = 4,
+ /obj/item/chems/cooking_container/pot = 4,
+ /obj/item/chems/cooking_container/saucepan = 4,
+ /obj/item/chems/cooking_container/skillet = 4,
+ /obj/item/kitchen/utensil/fork = 4,
+ /obj/item/kitchen/utensil/spoon = 4,
+ /obj/item/chems/glass/beaker/measuringcup = 4,
/obj/item/storage/tray/metal/aluminium = 8,
/obj/item/knife/kitchen = 3,
/obj/item/kitchen/rollingpin = 2,
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index 07c1a3c3ccf..ac233842fca 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -67,7 +67,7 @@
addtimer(CALLBACK(src, /obj/machinery/washing_machine/proc/wash), 20 SECONDS)
/obj/machinery/washing_machine/proc/wash()
- for(var/atom/A in (contents - component_parts))
+ for(var/atom/A in get_contained_external_atoms())
if(detergent)
A.clean_blood()
if(isitem(A))
@@ -200,7 +200,7 @@
var/mob/M = locate(/mob/living) in src
if(M)
M.gib()
- for(var/atom/movable/O in (contents - component_parts))
+ for(var/atom/movable/O in get_contained_external_atoms())
O.dropInto(loc)
state &= ~WASHER_STATE_FULL
update_icon()
diff --git a/code/game/movietitles.dm b/code/game/movietitles.dm
index a603643b1dc..9f37d5e716c 100644
--- a/code/game/movietitles.dm
+++ b/code/game/movietitles.dm
@@ -88,7 +88,7 @@ var/global/list/end_titles
var/client/P = parent
if(parent)
P.screen -= src
- LAZYREMOVE(P.credits, src)
+ LAZYREMOVE(P?.credits, src)
parent = null
return ..()
diff --git a/code/game/objects/effects/fluids.dm b/code/game/objects/effects/fluids.dm
index 7a61d705e33..8341a5ed934 100644
--- a/code/game/objects/effects/fluids.dm
+++ b/code/game/objects/effects/fluids.dm
@@ -37,7 +37,7 @@
ADD_ACTIVE_FLUID(src)
for(var/checkdir in global.cardinal)
var/obj/effect/fluid/F = locate() in get_step(loc, checkdir)
- if(F)
+ if(!QDELETED(F))
ADD_ACTIVE_FLUID(F)
update_lighting = TRUE
update_icon()
@@ -46,7 +46,7 @@
var/turf/simulated/T = get_turf(src)
for(var/checkdir in global.cardinal)
var/obj/effect/fluid/F = locate() in get_step(T, checkdir)
- if(F)
+ if(!QDELETED(F))
ADD_ACTIVE_FLUID(F)
REMOVE_ACTIVE_FLUID(src)
SSfluids.pending_flows -= src
diff --git a/code/game/objects/item.dm b/code/game/objects/item.dm
index 289cf8a73f0..10ee1a26476 100644
--- a/code/game/objects/item.dm
+++ b/code/game/objects/item.dm
@@ -131,6 +131,8 @@
STOP_PROCESSING(SSobj, src)
QDEL_NULL(hidden_uplink)
+ QDEL_NULL(coating)
+
if(ismob(loc))
var/mob/M = loc
@@ -140,10 +142,11 @@
LAZYREMOVE(organ.implants, src)
M.drop_from_inventory(src)
+ // TODO: CONVERT TO USE OBSERVATIONS
var/obj/item/storage/storage = loc
if(istype(storage))
// some ui cleanup needs to be done
- storage.on_item_pre_deletion(src) // must be done before deletion
+ storage.on_item_pre_deletion(src) // must be done before deletion // TODO: ADD PRE_DELETION OBSERVATION
. = ..()
storage.on_item_post_deletion(src) // must be done after deletion
else
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index b01b245ded0..cb99a477dd2 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -49,7 +49,7 @@
return
if (!in_range(src, user) && src.loc != user)
return
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ t = sanitize_safe(t, MAX_NAME_LEN)
if (t)
src.SetName("body bag - ")
src.name += t
diff --git a/code/game/objects/items/books/_book.dm b/code/game/objects/items/books/_book.dm
index dd0c5921c13..4652e19a142 100644
--- a/code/game/objects/items/books/_book.dm
+++ b/code/game/objects/items/books/_book.dm
@@ -75,7 +75,7 @@
var/choice = input("What would you like to change?") in list("Title", "Contents", "Author", "Cancel")
switch(choice)
if("Title")
- var/newtitle = reject_bad_text(sanitizeSafe(input("Write a new title:")))
+ var/newtitle = reject_bad_text(sanitize_safe(input("Write a new title:")))
if(!newtitle)
to_chat(usr, "The title is invalid.")
return
diff --git a/code/game/objects/items/books/skill_book.dm b/code/game/objects/items/books/skill_book.dm
index c49dc07331b..c9b67b52726 100644
--- a/code/game/objects/items/books/skill_book.dm
+++ b/code/game/objects/items/books/skill_book.dm
@@ -734,7 +734,7 @@ MEDICAL
return FALSE
/obj/item/book/skill/custom/proc/edit_title(var/obj/item/pen, var/mob/user)
- var/newtitle = reject_bad_text(sanitizeSafe(input(user, "Write a new title:")))
+ var/newtitle = reject_bad_text(sanitize_safe(input(user, "Write a new title:")))
if(!can_write(pen,user))
return
if(!newtitle)
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 96039634a2a..e0cdb252330 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -229,6 +229,9 @@
if(.)
SSnano.update_uis(src)
+/mob/announcer // used only for autosay
+ simulated = FALSE
+
/obj/item/radio/proc/autosay(var/message, var/from, var/channel, var/sayverb = "states") //BS12 EDIT
var/datum/radio_frequency/connection = null
if(channel && channels && channels.len > 0)
@@ -240,7 +243,7 @@
channel = null
if (!istype(connection))
return
- var/mob/living/silicon/ai/A = new /mob/living/silicon/ai(src, null, null, 1)
+ var/mob/announcer/A = new()
A.fully_replace_character_name(from)
talk_into(A, message, channel, sayverb)
qdel(A)
@@ -344,7 +347,7 @@
jobname = "No id"
// --- AI ---
- else if (isAI(M))
+ else if (isAI(M) || istype(M, /mob/announcer))
jobname = ASSIGNMENT_COMPUTER
// --- Cyborg ---
@@ -818,7 +821,7 @@
/obj/item/radio/phone/medbay
frequency = MED_I_FREQ
-
+
/obj/item/radio/phone/medbay/Initialize()
. = ..()
internal_channels = global.default_medbay_channels.Copy()
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 18d0b84c917..0487e0c630e 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -454,7 +454,7 @@
if(loc == user)
var/new_name = input(user, "What would you like to label the tape?", "Tape labeling") as null|text
if(isnull(new_name)) return
- new_name = sanitizeSafe(new_name)
+ new_name = sanitize_safe(new_name)
if(new_name)
SetName("tape - '[new_name]'")
to_chat(user, "You label the tape '[new_name]'.")
diff --git a/code/game/objects/items/robot/robot_frame.dm b/code/game/objects/items/robot/robot_frame.dm
index 0ca8db0428c..34cd2723f1c 100644
--- a/code/game/objects/items/robot/robot_frame.dm
+++ b/code/game/objects/items/robot/robot_frame.dm
@@ -138,7 +138,7 @@
qdel(src)
else if(istype(W, /obj/item/pen))
- var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
+ var/t = sanitize_safe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if(t && (in_range(src, user) || loc == user))
created_name = t
else
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index c264c004195..6220bb4f6e5 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -71,7 +71,7 @@
var/heldname = "default name"
/obj/item/borg/upgrade/rename/attack_self(mob/user)
- heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN)
+ heldname = sanitize_safe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN)
/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R)
if(..()) return 0
diff --git a/code/game/objects/items/spirit_board.dm b/code/game/objects/items/spirit_board.dm
index 229435b0bcb..b55b5731e94 100644
--- a/code/game/objects/items/spirit_board.dm
+++ b/code/game/objects/items/spirit_board.dm
@@ -9,7 +9,7 @@
var/lastuser = null
/obj/item/spirit_board/examine(mob/user)
- ..()
+ . = ..()
to_chat(user, "The planchette is sitting at \"[planchette]\".")
/obj/item/spirit_board/attack_hand(mob/user)
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 4108969fc3c..e4a7e7d4612 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -70,7 +70,7 @@
use(2)
return
- if (istype(W, /obj/item/tape_roll))
+ if (istype(W, /obj/item/ducttape))
var/obj/item/stack/medical/splint/ghetto/new_splint = new(user.loc)
new_splint.dropInto(loc)
new_splint.add_fingerprint(user)
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 1a18081f94f..1617f2e0543 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -39,7 +39,7 @@
if(signed_by)
to_chat(user, SPAN_WARNING("\The [src] has already been signed."))
else
- var/signature = sanitizeSafe(input("What do you want to sign the card as?", "Union Card") as text, MAX_NAME_LEN)
+ var/signature = sanitize_safe(input("What do you want to sign the card as?", "Union Card") as text, MAX_NAME_LEN)
if(signature && !signed_by && !user.incapacitated() && Adjacent(user))
signed_by = signature
user.visible_message(SPAN_NOTICE("\The [user] signs \the [src] with a flourish."))
diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm
index 351db1c3965..3b1bd79d618 100644
--- a/code/game/objects/items/weapons/cards_ids_syndicate.dm
+++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm
@@ -110,13 +110,13 @@
to_chat(user, "Age has been set to '[age]'.")
. = 1
if("Prefix")
- var/new_prefix = sanitizeSafe(input(user,"What title prefix would you like to put on this card?","Agent Card Prefix", age) as text, MAX_NAME_LEN)
+ var/new_prefix = sanitize_safe(input(user,"What title prefix would you like to put on this card?","Agent Card Prefix", age) as text, MAX_NAME_LEN)
if(!isnull(new_prefix) && CanUseTopic(user, state))
formal_name_prefix = new_prefix
to_chat(user, "Title prefix has been set to '[formal_name_prefix]'.")
. = 1
if("Suffix")
- var/new_suffix = sanitizeSafe(input(user,"What title suffix would you like to put on this card?","Agent Card Suffix", age) as text, MAX_NAME_LEN)
+ var/new_suffix = sanitize_safe(input(user,"What title suffix would you like to put on this card?","Agent Card Suffix", age) as text, MAX_NAME_LEN)
if(!isnull(new_suffix) && CanUseTopic(user, state))
formal_name_suffix = new_suffix
to_chat(user, "Title suffix has been set to '[formal_name_suffix]'.")
@@ -172,7 +172,7 @@
to_chat(user, "Fingerprint hash changed to '[new_fingerprint_hash]'.")
. = 1
if("Name")
- var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text, allow_numbers=TRUE)
+ var/new_name = sanitize_name(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text, allow_numbers=TRUE)
if(!isnull(new_name) && CanUseTopic(user, state))
src.registered_name = new_name
to_chat(user, "Name changed to '[new_name]'.")
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/household.dm b/code/game/objects/items/weapons/circuitboards/machinery/household.dm
index 3762cb31248..1796c4007f5 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/household.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/household.dm
@@ -27,15 +27,17 @@
/obj/item/stock_parts/power/apc/buildable = 1
)
-/obj/item/stock_parts/circuitboard/cooker
- name = "circuitboard (candy machine)"
- build_path = /obj/machinery/cooker/candy
+// HEARTH OF HESTIA EDIT
+/obj/item/stock_parts/circuitboard/appliance
+ name = "circuitboard (kitchen appliance)"
+ build_path = /obj/machinery/appliance/mixer/candy
board_type = "machine"
origin_tech = "{'biotech':1,'materials':1}"
buildtype_select = TRUE
req_components = list(
- /obj/item/stock_parts/manipulator = 2,
- /obj/item/stock_parts/matter_bin = 1,
+ /obj/item/stock_parts/capacitor = 3,
+ /obj/item/stock_parts/scanning_module = 1,
+ /obj/item/stock_parts/matter_bin = 2,
/obj/item/stack/cable_coil = 10)
additional_spawn_components = list(
/obj/item/stock_parts/console_screen = 1,
@@ -43,8 +45,10 @@
/obj/item/stock_parts/power/apc/buildable = 1
)
-/obj/item/stock_parts/circuitboard/cooker/get_buildable_types()
- return subtypesof(/obj/machinery/cooker)
+/obj/item/stock_parts/circuitboard/appliance/get_buildable_types()
+ return subtypesof(/obj/machinery/appliance/cooker) + subtypesof(/obj/machinery/appliance/mixer)
+
+// END HEARTH OF HESTIA EDIT
/obj/item/stock_parts/circuitboard/honey
name = "circuitboard (honey extractor)"
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 281e00e9ecc..b3dda7746fb 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -14,6 +14,11 @@
var/list/allowed_containers = list(/obj/item/chems/glass/beaker, /obj/item/chems/glass/bottle)
var/affected_area = 3
+/obj/item/grenade/chem_grenade/Destroy()
+ QDEL_NULL(detonator)
+ QDEL_NULL_LIST(beakers)
+ . = ..()
+
/obj/item/grenade/chem_grenade/Initialize()
. = ..()
create_reagents(1000)
@@ -112,7 +117,7 @@
update_icon()
/obj/item/grenade/chem_grenade/activate(mob/user)
- if(active)
+ if(active)
return
if(detonator)
if(!isigniter(detonator.a_left))
@@ -127,12 +132,12 @@
/obj/item/grenade/chem_grenade/detonate()
set waitfor = 0
- if(!stage || stage < 2)
+ if(!stage || stage < 2)
return
var/has_reagents = 0
for(var/obj/item/chems/glass/G in beakers)
- if(G.reagents.total_volume)
+ if(G.reagents.total_volume)
has_reagents = TRUE
break
@@ -162,7 +167,7 @@
set_invisibility(INVISIBILITY_MAXIMUM)
// Visual effect to show the grenade going off.
- if(reagents.total_volume)
+ if(reagents.total_volume)
var/datum/effect/effect/system/steam_spread/steam = new
steam.set_up(10, 0, get_turf(src))
steam.attach(src)
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index bda5fb96f1d..964674d2738 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -46,7 +46,7 @@
return
if((!in_range(src, usr) && loc != user))
return
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ t = sanitize_safe(t, MAX_NAME_LEN)
if(t)
SetName("glass case - '[t]'")
desc = "A case containing \a [t] implant."
diff --git a/code/game/objects/items/weapons/material/swiss.dm b/code/game/objects/items/weapons/material/swiss.dm
index f1605a45e62..0ee0bedabbe 100644
--- a/code/game/objects/items/weapons/material/swiss.dm
+++ b/code/game/objects/items/weapons/material/swiss.dm
@@ -49,9 +49,9 @@
/obj/item/knife/folding/swiss/get_tool_quality(archetype)
. = (archetype == get_tool_archetype()) ? ..() : 0
-
+
/obj/item/knife/folding/swiss/attack_self(mob/user)
- var/choice
+ var/choice
if(user.a_intent != I_HELP && ((SWISSKNF_LBLADE in tools) || (SWISSKNF_SBLADE in tools)) && active_tool == SWISSKNF_CLOSED)
open = TRUE
if(SWISSKNF_LBLADE in tools)
@@ -64,7 +64,7 @@
else
choice = SWISSKNF_CLOSED
open = FALSE
-
+
if(!choice || !CanPhysicallyInteract(user))
return
if(choice == SWISSKNF_CLOSED)
@@ -77,7 +77,7 @@
playsound(user, 'sound/weapons/flipblade.ogg', 15, 1)
else
user.visible_message("\The [user] opens the [lowertext(choice)].")
-
+
active_tool = choice
update_force()
update_icon()
@@ -108,7 +108,7 @@
/obj/item/knife/folding/swiss/on_update_icon()
..()
if(active_tool != null)
- overlays += overlay_image(icon, active_tool)
+ add_overlay(overlay_image(icon, active_tool))
/obj/item/knife/folding/swiss/get_mob_overlay(mob/user_mob, slot, bodypart)
. = (active_tool == SWISSKNF_LBLADE || active_tool == SWISSKNF_SBLADE) ? ..() : new /image
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index cca5951971e..eeab7c82918 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -266,9 +266,9 @@
/obj/item/radio/headset,
/obj/item/megaphone,
/obj/item/taperoll,
+ /obj/item/magnetic_tape,
/obj/item/holowarrant,
/obj/item/radio,
- /obj/item/tape,
/obj/item/pen,
/obj/item/stamp,
/obj/item/stack/package_wrap,
@@ -311,6 +311,8 @@
/obj/item/flash,
/obj/item/telebaton,
/obj/item/taperecorder,
+ /obj/item/magnetic_tape,
+ /obj/item/taperoll,
/obj/item/folder,
/obj/item/paper,
/obj/item/clipboard,
@@ -320,10 +322,8 @@
/obj/item/modular_computer/pda,
/obj/item/radio/headset,
/obj/item/megaphone,
- /obj/item/taperoll,
/obj/item/holowarrant,
/obj/item/radio,
- /obj/item/tape,
/obj/item/pen,
/obj/item/stamp,
/obj/item/stack/package_wrap,
@@ -352,16 +352,14 @@
/obj/item/forensics/sample/print,
/obj/item/forensics/sample/fibers,
/obj/item/taperecorder,
- /obj/item/tape,
+ /obj/item/magnetic_tape,
/obj/item/clothing/gloves/latex,
/obj/item/clothing/gloves/forensic,
/obj/item/folder,
/obj/item/paper,
/obj/item/forensics/sample_kit,
- /obj/item/camera,
- /obj/item/taperecorder,
- /obj/item/tape
- )
+ /obj/item/camera
+ )
/obj/item/storage/belt/holster/machete
name = "machete belt"
@@ -387,9 +385,9 @@
/obj/item/radio/beacon,
/obj/item/pinpointer/radio,
/obj/item/taperecorder,
- /obj/item/tape,
+ /obj/item/magnetic_tape,
/obj/item/scanner/gas
- )
+ )
can_holster = list(/obj/item/hatchet/machete)
sound_in = 'sound/effects/holster/sheathin.ogg'
sound_out = 'sound/effects/holster/sheathout.ogg'
diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm
index 741361d5696..4a0dda00b01 100644
--- a/code/game/objects/items/weapons/storage/bible.dm
+++ b/code/game/objects/items/weapons/storage/bible.dm
@@ -108,7 +108,7 @@
set desc = "Click to rename your bible."
if(!renamed)
- var/input = sanitizeSafe(input("What do you want to rename your bible to? You can only do this once.", ,""), MAX_NAME_LEN)
+ var/input = sanitize_safe(input("What do you want to rename your bible to? You can only do this once.", ,""), MAX_NAME_LEN)
var/mob/M = usr
if(src && input && !M.stat && in_range(M,src))
diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm
index dfd5709968c..dfc32c4a9b5 100644
--- a/code/game/objects/items/weapons/tape.dm
+++ b/code/game/objects/items/weapons/tape.dm
@@ -1,18 +1,18 @@
-/obj/item/tape_roll
+/obj/item/ducttape
name = "duct tape"
desc = "A roll of sticky tape. Possibly for taping ducks... or was that ducts?"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "taperoll"
w_class = ITEM_SIZE_SMALL
-/obj/item/tape_roll/Initialize()
+/obj/item/ducttape/Initialize()
. = ..()
set_extension(src, /datum/extension/tool, list(
TOOL_BONE_GEL = TOOL_QUALITY_MEDIOCRE,
TOOL_SUTURES = TOOL_QUALITY_BAD
))
-/obj/item/tape_roll/attack(var/mob/living/carbon/human/H, var/mob/user)
+/obj/item/ducttape/attack(var/mob/living/carbon/human/H, var/mob/user)
if(istype(H))
if(user.zone_sel.selecting == BP_EYES)
@@ -83,7 +83,7 @@
return ..()
return 1
-/obj/item/tape_roll/proc/stick(var/obj/item/W, mob/user)
+/obj/item/ducttape/proc/stick(var/obj/item/W, mob/user)
if(!istype(W, /obj/item/paper) || istype(W, /obj/item/paper/sticky) || !user.unEquip(W))
return
var/obj/item/ducttape/tape = new(get_turf(src))
diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm
index d219d4506d4..4e483267f42 100644
--- a/code/game/objects/random/random.dm
+++ b/code/game/objects/random/random.dm
@@ -131,7 +131,7 @@
/obj/item/storage/belt/utility = 2,
/obj/item/storage/belt/utility/atmostech = 1,
/obj/random/tool = 5,
- /obj/item/tape_roll = 2)
+ /obj/item/ducttape = 2)
/obj/random/medical
name = "Random Medical equipment"
diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm
index 6a465b62d40..311ec958699 100644
--- a/code/game/objects/structures/bookcase.dm
+++ b/code/game/objects/structures/bookcase.dm
@@ -34,7 +34,7 @@ var/global/list/station_bookcases = list()
if(istype(O, /obj/item/book) && user.unEquip(O, src))
update_icon()
else if(istype(O, /obj/item/pen))
- var/newname = sanitizeSafe(input("What would you like to title this bookshelf?"), MAX_NAME_LEN)
+ var/newname = sanitize_safe(input("What would you like to title this bookshelf?"), MAX_NAME_LEN)
if(!newname)
return
else
diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm
index a0e6e655ab8..daaceef5817 100644
--- a/code/game/objects/structures/catwalk.dm
+++ b/code/game/objects/structures/catwalk.dm
@@ -186,9 +186,9 @@
C.plated_tile += GET_DECL(plating_type)
C.name = "plated catwalk"
C.update_icon()
- activated = 1
+ activated = TRUE
for(var/turf/T in orange(src, 1))
- for(var/obj/effect/wallframe_spawn/other in T)
+ for(var/obj/effect/catwalk_plated/other in T)
if(!other.activated) other.activate()
/obj/effect/catwalk_plated/dark
diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
index 8387fba6890..8a44ed80ff0 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -20,15 +20,17 @@
closet_appearance = /decl/closet_appearance/oxygen
/obj/structure/closet/emcloset/WillContain()
- //Guaranteed kit - two tanks and masks
- . = list(/obj/item/tank/emergency/oxygen = 2,
- /obj/item/clothing/mask/breath = 2)
+ //Guaranteed kit - two tanks, two masks, two O2 pouches, and a softsuit
+ . = list(/obj/item/tank/emergency/oxygen/engi = 2,
+ /obj/item/clothing/mask/breath = 2,
+ /obj/item/storage/med_pouch/oxyloss = 2,
+ /obj/item/clothing/suit/space/emergency,
+ /obj/item/clothing/head/helmet/space/emergency)
. += new/datum/atom_creator/simple(list(/obj/item/storage/toolbox/emergency, /obj/item/inflatable/wall = 2), 75)
- . += new/datum/atom_creator/simple(list(/obj/item/tank/emergency/oxygen/engi, /obj/item/clothing/mask/gas/half), 10)
- . += new/datum/atom_creator/simple(/obj/item/oxycandle, 15)
- . += new/datum/atom_creator/simple(/obj/item/storage/firstaid/o2, 25)
- . += new/datum/atom_creator/simple(list(/obj/item/clothing/suit/space/emergency,/obj/item/clothing/head/helmet/space/emergency), 25)
+ . += new/datum/atom_creator/simple(list(/obj/item/clothing/mask/gas/half, /obj/item/tank/oxygen), 10)
+ . += new/datum/atom_creator/simple(/obj/item/oxycandle, 75)
+ . += new/datum/atom_creator/simple(/obj/item/storage/firstaid/regular, 25)
/*
* Fire Closet
diff --git a/code/game/objects/structures/crematorium.dm b/code/game/objects/structures/crematorium.dm
index 3b41a43dcc7..1ea52f85486 100644
--- a/code/game/objects/structures/crematorium.dm
+++ b/code/game/objects/structures/crematorium.dm
@@ -92,7 +92,7 @@
/obj/structure/crematorium/attackby(P, mob/user)
if(istype(P, /obj/item/pen))
- var/new_label = sanitizeSafe(input(user, "What would you like the label to be?", capitalize(name), null) as text|null, MAX_NAME_LEN)
+ var/new_label = sanitize_safe(input(user, "What would you like the label to be?", capitalize(name), null) as text|null, MAX_NAME_LEN)
if((!Adjacent(user) || loc == user))
return
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 583b8ed67ca..8c9d6830f27 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -103,7 +103,7 @@
/obj/structure/door_assembly/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/pen))
- var/t = sanitizeSafe(input(user, "Enter the name for the door.", src.name, src.created_name), MAX_NAME_LEN)
+ var/t = sanitize_safe(input(user, "Enter the name for the door.", src.name, src.created_name), MAX_NAME_LEN)
if(!t) return
if(!in_range(src, usr) && src.loc != usr) return
created_name = t
diff --git a/code/game/objects/structures/doors/_door.dm b/code/game/objects/structures/doors/_door.dm
index 219260cb900..ffdaa951296 100644
--- a/code/game/objects/structures/doors/_door.dm
+++ b/code/game/objects/structures/doors/_door.dm
@@ -1,19 +1,20 @@
-#define MATERIAL_DOOR_SOUND_VOLUME 25
/obj/structure/door
name = "door"
icon = 'icons/obj/doors/material_doors.dmi'
icon_state = "metal"
hitsound = 'sound/weapons/genhit.ogg'
- material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_COLOR
+ material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR
maxhealth = 50
density = TRUE
anchored = TRUE
opacity = TRUE
+ var/datum/lock/lock
+
var/has_window = FALSE
var/changing_state = FALSE
var/icon_base
- var/datum/lock/lock
+ var/door_sound_volume = 25
/obj/structure/door/Initialize()
. = ..()
@@ -23,15 +24,11 @@
lock = new /datum/lock(src, lock)
if(!icon_base)
icon_base = material.door_icon_base
- changing_state = FALSE
- update_nearby_tiles(need_rebuild=TRUE)
-
- if(material.luminescence)
+ update_icon()
+ update_nearby_tiles(need_rebuild = TRUE)
+ if(material?.luminescence)
set_light(material.luminescence, 0.5, material.color)
- if(material.opacity < 0.5)
- alpha = 180
-
/obj/structure/door/Destroy()
update_nearby_tiles()
QDEL_NULL(lock)
@@ -42,25 +39,22 @@
/obj/structure/door/on_update_icon()
..()
- if(density)
- icon_state = "[icon_base]"
- else
- icon_state = "[icon_base]open"
+ icon_state = "[icon_base][!density ? "open" : ""]"
/obj/structure/door/proc/post_change_state()
update_nearby_tiles()
update_icon()
changing_state = FALSE
-/obj/structure/door/attack_hand(var/mob/user)
+/obj/structure/door/attack_hand(mob/user)
return density ? open() : close()
/obj/structure/door/proc/close()
set waitfor = 0
if(!can_close())
return FALSE
- flick("[icon_base]closing", src)
- playsound(src.loc, material.dooropen_noise, MATERIAL_DOOR_SOUND_VOLUME, 1)
+ flick("[icon_base]_closing", src)
+ playsound(src, material.dooropen_noise, door_sound_volume, 1)
changing_state = TRUE
sleep(1 SECOND)
@@ -73,8 +67,8 @@
set waitfor = 0
if(!can_open())
return FALSE
- flick("[icon_base]opening", src)
- playsound(src.loc, material.dooropen_noise, MATERIAL_DOOR_SOUND_VOLUME, 1)
+ flick("[icon_base]_opening", src)
+ playsound(src, material.dooropen_noise, door_sound_volume, 1)
changing_state = TRUE
sleep(1 SECOND)
@@ -112,7 +106,6 @@
return FALSE
/obj/structure/door/attackby(obj/item/I, mob/user)
-
add_fingerprint(user, 0, I)
if((user.a_intent == I_HURT && I.force) || istype(I, /obj/item/stack/material))
@@ -149,7 +142,7 @@
return !opacity
return !density
-/obj/structure/door/CanFluidPass(var/coming_from)
+/obj/structure/door/CanFluidPass(coming_from)
return !density
/obj/structure/door/Bumped(atom/AM)
@@ -212,4 +205,3 @@
/obj/structure/door/shuttle
material = /decl/material/solid/metal/steel
-#undef MATERIAL_DOOR_SOUND_VOLUME
\ No newline at end of file
diff --git a/code/game/objects/structures/fountain.dm b/code/game/objects/structures/fountain.dm
index 4972ba89463..91a143a920f 100644
--- a/code/game/objects/structures/fountain.dm
+++ b/code/game/objects/structures/fountain.dm
@@ -49,12 +49,11 @@
to_chat(user, "You touch the fountain. All the memories of your life seem to fade into the distant past as seconds drag like years. You feel the inexplicable sensation of your skin tightening and thinning across your entire body as your muscles degrade and your joints weaken. Time returns to its 'normal' pace. You can only just barely remember touching the fountain.")
user.became_older = TRUE
user.change_hair_color(80, 80, 80)
- var/age_holder = round(rand(15,20))
- user.set_age(age_holder)
+ user.set_age(user.get_age() + round(rand(15,20)))
else //become younger
to_chat(user, "You touch the fountain. Everything stops - then reverses. You relive in an instant the events of your life. The fountain, yesterday's lunch, your first love, your first kiss. It all feels as though it just happened moments ago. Then it feels like it never happened at all. Time reverses back into normality and continues its advance. You feel great, but why are you here?")
user.became_younger = TRUE
- user.set_age(rand(15,17))
+ user.set_age(rand(18, max(round(user.get_age() / 2), 18))) //anywhere from 18 to half your age
used = TRUE
desc = "The water flows beautifully from the spout, but the water in the pool does not ripple."
@@ -64,5 +63,8 @@
icon_state = "fountain_g"
used = TRUE
-/obj/structure/fountain/mundane/attack_hand()
+/obj/structure/fountain/mundane/attack_hand(var/mob/user)
+ return
+
+/obj/structure/fountain/mundane/time_dilation(var/mob/living/carbon/human/user)
return
\ No newline at end of file
diff --git a/code/game/objects/structures/hand_cart.dm b/code/game/objects/structures/hand_cart.dm
index f5e9ea3cfe1..c1ac8d6b39d 100644
--- a/code/game/objects/structures/hand_cart.dm
+++ b/code/game/objects/structures/hand_cart.dm
@@ -37,6 +37,12 @@
/obj/structure/hand_cart/grab_attack(var/obj/item/grab/G)
if(G.affecting && istype(G.affecting, /obj/))
+ if(G.affecting == src)
+ to_chat(G.assailant, SPAN_NOTICE("You can't make \the [src] carry itself!"))
+ return TRUE
+ if(carrying)
+ to_chat(G.assailant, SPAN_NOTICE("[src] already has \the [carrying] on it, it can't fit anything else!"))
+ return TRUE
to_chat(G.assailant, SPAN_NOTICE("You start loading \the [G.affecting] onto \the [src]."))
if(load_item(G.affecting, G.assailant))
qdel(G)
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index 53786b0fa9b..7612d769a05 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -120,7 +120,7 @@
add_fingerprint(user)
/obj/structure/inflatable/can_repair_with(obj/item/tool)
- . = istype(tool, /obj/item/tape_roll) && (health < maxhealth)
+ . = istype(tool, /obj/item/ducttape) && (health < maxhealth)
/obj/structure/inflatable/handle_repair(mob/user, obj/item/tool)
if(taped)
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index e025bcef129..32954e5304d 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -82,7 +82,7 @@
/obj/structure/morgue/attackby(P, mob/user)
if(istype(P, /obj/item/pen))
- var/new_label = sanitizeSafe(input(user, "What would you like the label to be?", capitalize(name), null) as text|null, MAX_NAME_LEN)
+ var/new_label = sanitize_safe(input(user, "What would you like the label to be?", capitalize(name), null) as text|null, MAX_NAME_LEN)
if((!Adjacent(user) || loc == user))
return
diff --git a/code/game/objects/structures/racks.dm b/code/game/objects/structures/racks.dm
index 138f4111329..76259ff6b06 100644
--- a/code/game/objects/structures/racks.dm
+++ b/code/game/objects/structures/racks.dm
@@ -12,6 +12,7 @@
parts_amount = 2
parts_type = /obj/item/stack/material/strut
density = TRUE
+ anchored = TRUE
/obj/structure/rack/Initialize()
..()
@@ -33,6 +34,14 @@
auto_align(O, click_params)
return TRUE
+/obj/structure/rack/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ if(air_group || height==0)
+ return TRUE
+ if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE))
+ return TRUE
+ var/obj/structure/rack/R = (locate() in get_turf(mover))
+ return R
+
/obj/structure/rack/holorack/dismantle()
material = null
reinf_material = null
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index b581bd99b64..972ddb3732b 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -255,7 +255,7 @@
var/response = input(user, "New Window ID:", name, id) as null | text
if (isnull(response) || user.incapacitated() || !user.Adjacent(src) || user.get_active_hand() != W)
return
- id = sanitizeSafe(response, MAX_NAME_LEN)
+ id = sanitize_safe(response, MAX_NAME_LEN)
to_chat(user, SPAN_NOTICE("The new ID of \the [src] is [id]."))
return
else if(istype(W, /obj/item/gun/energy/plasmacutter) && anchored)
@@ -568,10 +568,10 @@
/obj/machinery/button/windowtint/attackby(obj/item/W, mob/user)
if(isMultitool(W))
- var/t = sanitizeSafe(input(user, "Enter the ID for the button.", name, id_tag), MAX_NAME_LEN)
+ var/t = sanitize_safe(input(user, "Enter the ID for the button.", name, id_tag), MAX_NAME_LEN)
if(!CanPhysicallyInteract(user))
return TRUE
- t = sanitizeSafe(t, MAX_NAME_LEN)
+ t = sanitize_safe(t, MAX_NAME_LEN)
if (t)
id_tag = t
to_chat(user, SPAN_NOTICE("The new ID of the button is '[id_tag]'."))
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index a2cf8496a1e..e5b8825fc0d 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -130,7 +130,7 @@
/turf/proc/get_movement_delay(var/travel_dir)
. = get_base_movement_delay()
if(weather)
- . += weather.get_movement_delay(travel_dir)
+ . += weather.get_movement_delay(return_air(), travel_dir)
/turf/attack_hand(mob/user)
user.setClickCooldown(DEFAULT_QUICK_COOLDOWN)
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index e12bd213650..c995ab4a492 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -1,5 +1,6 @@
/turf/proc/ReplaceWithLattice(var/material)
var/base_turf = get_base_turf_by_area(src)
+ . = src
if(base_turf && type != base_turf)
. = ChangeTurf(base_turf)
if(!(locate(/obj/structure/lattice) in .))
@@ -124,14 +125,14 @@
/turf/simulated/floor/transport_properties_from(turf/simulated/floor/other)
if(!..())
return FALSE
-
+
broken = other.broken
burnt = other.burnt
if(broken || burnt)
queue_icon_update()
set_flooring(other.flooring)
return TRUE
-
+
//I would name this copy_from() but we remove the other turf from their air zone for some reason
/turf/simulated/transport_properties_from(turf/simulated/other)
if(!..())
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 5b92362faf2..d81555bd166 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -94,6 +94,7 @@ var/global/list/admin_verbs_admin = list(
/datum/admins/proc/show_aspects
)
var/global/list/admin_verbs_ban = list(
+ /client/proc/DB_ban_panel,
/client/proc/unban_panel,
/client/proc/jobbans
)
@@ -661,7 +662,7 @@ var/global/list/admin_verbs_mod = list(
var/mob/living/silicon/S = input("Select silicon.", "Rename Silicon.") as null|anything in global.silicon_mob_list
if(!S) return
- var/new_name = sanitizeSafe(input(src, "Enter new name. Leave blank or as is to cancel.", "[S.real_name] - Enter new silicon name", S.real_name))
+ var/new_name = sanitize_safe(input(src, "Enter new name. Leave blank or as is to cancel.", "[S.real_name] - Enter new silicon name", S.real_name))
if(new_name && new_name != S.real_name)
log_and_message_admins("has renamed the silicon '[S.real_name]' to '[new_name]'")
S.fully_replace_character_name(new_name)
@@ -924,7 +925,7 @@ var/global/list/admin_verbs_mod = list(
if("Upload custom")
var/file = input(usr) as icon|null
- if(!file)
+ if(!file)
return
global.using_map.update_titlescreen(file)
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/dbban/functions.dm
similarity index 99%
rename from code/modules/admin/DB ban/functions.dm
rename to code/modules/admin/dbban/functions.dm
index 5cde2396817..ee761246959 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/dbban/functions.dm
@@ -294,7 +294,7 @@
/client/proc/DB_ban_panel()
set category = "Admin"
set name = "Banning Panel"
- set desc = "Edit admin permissions"
+ set desc = "Allow edit existing bans or create new ones."
if(!holder)
return
diff --git a/code/modules/admin/ticket.dm b/code/modules/admin/ticket.dm
index 7bf115e2a6c..fa3df76106d 100644
--- a/code/modules/admin/ticket.dm
+++ b/code/modules/admin/ticket.dm
@@ -19,7 +19,7 @@ var/global/list/ticket_panels = list()
id = tickets.len
opened_time = world.time
if(establish_db_connection())
- var/sql_ckey = sanitizeSQL(owner.ckey)
+ var/sql_ckey = sanitize_sql(owner.ckey)
var/DBQuery/ticket_query = dbcon.NewQuery("INSERT INTO `erro_admin_tickets`(`ckey`, `round`, `inround_id`, `status`, `open_date`) VALUES ('[sql_ckey]', '[game_id]', [src.id], 'OPEN', NOW());")
ticket_query.Execute()
addtimer(CALLBACK(src, .proc/timeoutcheck), 5 MINUTES)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index bbbbbbcd74b..1d517ffd923 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1293,7 +1293,7 @@
src.access_news_network()
else if(href_list["ac_set_channel_name"])
- src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))
+ src.admincaster_feed_channel.channel_name = sanitize_safe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))
src.access_news_network()
else if(href_list["ac_set_channel_lock"])
@@ -1321,7 +1321,7 @@
var/list/available_channels = list()
for(var/datum/feed_channel/F in news_network.network_channels)
available_channels += F.channel_name
- src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels )
+ src.admincaster_feed_channel.channel_name = sanitize_safe(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels )
src.access_news_network()
else if(href_list["ac_set_new_message"])
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 311001f84fc..981cae52c3c 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -111,7 +111,7 @@ var/global/list/adminhelp_ignored_words = list("unknown","the","a","an","of","mo
update_ticket_panels()
if(establish_db_connection())
- var/sql_text = "HELP [src.ckey]: [sanitizeSQL(original_msg)]\n"
+ var/sql_text = "HELP [src.ckey]: [sanitize_sql(original_msg)]\n"
var/DBQuery/ticket_text = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `text` = '[sql_text]' WHERE `round` = '[game_id]' AND `inround_id` = '[ticket.id]';")
ticket_text.Execute()
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index cc865fd9490..da9195800ca 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -153,7 +153,7 @@
update_ticket_panels()
if(establish_db_connection())
- var/sql_text = "[src.ckey] -> [C.ckey]: [sanitizeSQL(msg)]\n"
+ var/sql_text = "[src.ckey] -> [C.ckey]: [sanitize_sql(msg)]\n"
var/DBQuery/ticket_text = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `text` = CONCAT(COALESCE(text,''), '[sql_text]') WHERE `round` = '[game_id]' AND `inround_id` = '[ticket.id]';")
ticket_text.Execute()
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index cc89531a4e8..25127ad555e 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -92,7 +92,7 @@
return 0
var/obj/item/paicard/card = new(T)
var/mob/living/silicon/pai/pai = new(card)
- pai.SetName(sanitizeSafe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text))
+ pai.SetName(sanitize_safe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text))
pai.real_name = pai.name
pai.key = choice.key
card.setPersonality(pai)
@@ -483,7 +483,7 @@
trap = GET_DECL(trap)
trap.forced(mob)
-/client/proc/spawn_exoplanet(exoplanet_type as anything in subtypesof(/obj/effect/overmap/visitable/sector/exoplanet))
+/client/proc/spawn_exoplanet(exoplanet_type AS_ANYTHING in subtypesof(/obj/effect/overmap/visitable/sector/exoplanet))
set category = "Debug"
set name = "Create Exoplanet"
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 992d4840c11..747cea4c332 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -467,7 +467,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(G_found.mind && !G_found.mind.active)
G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use
- new_character.mind.special_verbs = list()
else
new_character.mind_initialize()
if(!new_character.mind.assigned_role)
@@ -561,7 +560,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
to_chat(src, "Only administrators may use this command.")
return
var/input = sanitize(input(usr, "Please enter anything you want. Anything. Serious.", "What?", "") as message|null, extra = 0)
- var/customname = sanitizeSafe(input(usr, "Pick a title for the report.", "Title") as text|null)
+ var/customname = sanitize_safe(input(usr, "Pick a title for the report.", "Title") as text|null)
if(!input)
return
if(!customname)
diff --git a/code/modules/aspects/aspects.dm b/code/modules/aspects/aspects.dm
index 18fd39df96a..5adbd11af2a 100644
--- a/code/modules/aspects/aspects.dm
+++ b/code/modules/aspects/aspects.dm
@@ -32,7 +32,7 @@ var/global/list/aspect_categories = list() // Containers for ease of printing da
/decl/aspect/Initialize()
. = ..()
-
+
// This is here until there are positive traits to balance out the negative ones;
// currently the cost calc serves no purpose and looks really silly sitting at -14/5.
aspect_cost = 0
@@ -143,7 +143,7 @@ var/global/list/aspect_categories = list() // Containers for ease of printing da
/datum/admins/proc/show_aspects()
set category = "Admin"
set name = "Show Aspects"
- if(!check_rights(R_INVESTIGATE))
+ if(!check_rights(R_INVESTIGATE))
return
var/mob/M = input("Select mob.", "Select mob.") as null|anything in global.living_mob_list_
if(M)
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index b7df526e118..4e30fdbec65 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -15,6 +15,17 @@
var/obj/item/assembly/a_right = null
var/obj/special_assembly = null
+/obj/item/assembly_holder/Initialize()
+ . = ..()
+ global.listening_objects += src
+
+/obj/item/assembly_holder/Destroy()
+ global.listening_objects -= src
+ a_left = null
+ a_right = null
+ special_assembly = null
+ return ..()
+
/obj/item/assembly_holder/proc/attach(var/obj/item/D, var/obj/item/D2, var/mob/user)
return
@@ -182,16 +193,6 @@
// special_assembly.dothings()
return 1
-
-/obj/item/assembly_holder/Initialize()
- . = ..()
- global.listening_objects += src
-
-/obj/item/assembly_holder/Destroy()
- global.listening_objects -= src
- return ..()
-
-
/obj/item/assembly_holder/hear_talk(mob/living/M, msg, verb, decl/language/speaking)
if(a_right)
a_right.hear_talk(M,msg,verb,speaking)
diff --git a/code/modules/atmospherics/pipes.dm b/code/modules/atmospherics/pipes.dm
index 621d797fd71..ccf082dfd3e 100644
--- a/code/modules/atmospherics/pipes.dm
+++ b/code/modules/atmospherics/pipes.dm
@@ -120,6 +120,8 @@
if(liquid_temporary)
liquid_temporary.trans_to(loc, liquid_temporary.total_volume)
liquid_temporary = null
+ if(leaking)
+ STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
. = ..()
/obj/machinery/atmospherics/pipe/deconstruction_pressure_check()
diff --git a/code/modules/augment/active/cyberbrain.dm b/code/modules/augment/active/cyberbrain.dm
index a0b49e9224d..cd00f0e1e6c 100644
--- a/code/modules/augment/active/cyberbrain.dm
+++ b/code/modules/augment/active/cyberbrain.dm
@@ -27,9 +27,15 @@
set_extension(src, /datum/extension/assembly/modular_computer/cyberbrain)
update_icon()
-
+
install_default_hardware()
+/obj/item/organ/internal/augment/active/cyberbrain/get_contained_external_atoms()
+ . = ..()
+ var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly)
+ if(assembly)
+ LAZYREMOVE(., assembly.parts)
+
// Used to perform preset-specific hardware changes.
/obj/item/organ/internal/augment/active/cyberbrain/proc/install_default_hardware()
var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly)
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 493796a8675..d3af3dc0e1c 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -406,7 +406,8 @@ var/global/list/localhost_addresses = list(
'html/panels.css',
'html/spacemag.css',
'html/images/loading.gif',
- 'html/images/talisman.png'
+ 'html/images/talisman.png',
+ 'html/images/iseo.png'
)
var/decl/asset_cache/asset_cache = GET_DECL(/decl/asset_cache)
@@ -653,7 +654,7 @@ var/global/const/MAX_VIEW = 41
if("South")
movement_keys[key] = SOUTH
if("Say")
- winset(src, "default-\ref[key]", "parent=default;name=[key];command=say")
+ winset(src, "default-\ref[key]", "parent=default;name=[key];command=.say")
communication_hotkeys += key
if("OOC")
winset(src, "default-\ref[key]", "parent=default;name=[key];command=ooc")
diff --git a/code/modules/client/preference_setup/background/01_species.dm b/code/modules/client/preference_setup/background/01_species.dm
index a237921a5c6..85165834975 100644
--- a/code/modules/client/preference_setup/background/01_species.dm
+++ b/code/modules/client/preference_setup/background/01_species.dm
@@ -7,7 +7,7 @@
W.write("species", pref.species)
/datum/category_item/player_setup_item/background/species/load_character(datum/pref_record_reader/R)
- pref.species = R.read("species")
+ pref.species = R.read("species")
/datum/category_item/player_setup_item/background/species/sanitize_character()
. = ..()
@@ -35,7 +35,7 @@
var/decl/species/current_species = get_species_by_key(pref.species)
var/list/prefilter = get_playable_species()
var/list/playables = list()
-
+
for(var/s in prefilter)
if(!check_rights(R_ADMIN, 0) && config.usealienwhitelist)
var/decl/species/checking_species = get_species_by_key(s)
@@ -61,11 +61,11 @@
var/icon/use_preview_icon = current_species.get_preview_icon()
if(use_preview_icon)
- send_rsc(user, use_preview_icon, current_species.preview_icon_path)
+ send_rsc(user, use_preview_icon, current_species.preview_icon_path)
. += " | | "
else
. += "No preview available. | "
-
+
var/desc = current_species.description || "No additional details."
if(hide_species && length(desc) > 200)
desc = "[copytext(desc, 1, 194)] \[...\]"
diff --git a/code/modules/client/preference_setup/background/02_culture.dm b/code/modules/client/preference_setup/background/02_culture.dm
index c40f9dff1be..852a634db24 100644
--- a/code/modules/client/preference_setup/background/02_culture.dm
+++ b/code/modules/client/preference_setup/background/02_culture.dm
@@ -62,7 +62,7 @@
if(pref.cultural_info[TAG_CULTURE])
var/decl/cultural_info/check = GET_DECL(pref.cultural_info[TAG_CULTURE])
if(check)
- pref.real_name = check.sanitize_name(pref.real_name, pref.species)
+ pref.real_name = check.sanitize_cultural_name(pref.real_name, pref.species)
if(!pref.real_name)
pref.real_name = check.get_random_name(preference_mob(), pref.gender)
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 5aeea735ff5..eb256a0d4bf 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -95,7 +95,7 @@
if (!isnull(raw_name) && CanUseTopic(user))
var/decl/cultural_info/check = GET_DECL(pref.cultural_info[TAG_CULTURE])
- var/new_name = check.sanitize_name(raw_name, pref.species)
+ var/new_name = check.sanitize_cultural_name(raw_name, pref.species)
if(filter_block_message(user, new_name))
return TOPIC_NOACTION
diff --git a/code/modules/client/preference_setup/global/03_pai.dm b/code/modules/client/preference_setup/global/03_pai.dm
index 9c2541558a4..86bccf57f94 100644
--- a/code/modules/client/preference_setup/global/03_pai.dm
+++ b/code/modules/client/preference_setup/global/03_pai.dm
@@ -52,7 +52,7 @@
. = TOPIC_REFRESH
switch(href_list["option"])
if("name")
- t = sanitizeName(input(user, "Enter a name for your pAI", "Global Preference", candidate.name) as text|null, MAX_NAME_LEN, 1)
+ t = sanitize_name(input(user, "Enter a name for your pAI", "Global Preference", candidate.name) as text|null, MAX_NAME_LEN, 1)
if(t && CanUseTopic(user))
candidate.name = t
if("desc")
diff --git a/code/modules/client/preference_setup/global/05_settings.dm b/code/modules/client/preference_setup/global/05_settings.dm
index d96ac73e0e9..d49f628cd7d 100644
--- a/code/modules/client/preference_setup/global/05_settings.dm
+++ b/code/modules/client/preference_setup/global/05_settings.dm
@@ -83,7 +83,7 @@
/client/proc/get_preference_value(var/preference)
if(prefs)
var/datum/client_preference/cp = get_client_preference(preference)
- if(cp)
+ if(cp && LAZYLEN(prefs.preference_values))
return prefs.preference_values[cp.key]
else
return null
@@ -93,7 +93,7 @@
/client/proc/set_preference(var/preference, var/set_preference)
var/datum/client_preference/cp = get_client_preference(preference)
- if(!cp)
+ if(!cp || !LAZYLEN(prefs.preference_values))
return FALSE
if((prefs.preference_values[cp.key] != set_preference) && (set_preference in cp.options))
@@ -106,7 +106,7 @@
/client/proc/cycle_preference(var/preference)
var/datum/client_preference/cp = get_client_preference(preference)
- if(!cp)
+ if(!cp || !LAZYLEN(prefs.preference_values))
return FALSE
var/next_option = next_in_list(prefs.preference_values[cp.key], cp.options)
diff --git a/code/modules/client/preference_setup/loadout/lists/augmentations.dm b/code/modules/client/preference_setup/loadout/lists/augmentations.dm
index 4dd270fe541..e19a17c1301 100644
--- a/code/modules/client/preference_setup/loadout/lists/augmentations.dm
+++ b/code/modules/client/preference_setup/loadout/lists/augmentations.dm
@@ -12,7 +12,7 @@
qdel(src)
/obj/item/implant/AttemptAugmentation(mob/user, target_zone)
- if(can_implant(user, user, target_zone) && implant_in_mob(user, user, target_zone))
+ if(can_implant(user, user, target_zone) && user.get_organ(target_zone) && implant_in_mob(user, user, target_zone))
var/obj/item/organ/organ = user.get_organ(target_zone)
to_chat(user, SPAN_NOTICE("You have \a [src] implanted in your [organ.name]."))
else
diff --git a/code/modules/client/preference_setup/loadout/lists/eyegear.dm b/code/modules/client/preference_setup/loadout/lists/eyegear.dm
index 8a8dd7b83b2..b958b12d0c2 100644
--- a/code/modules/client/preference_setup/loadout/lists/eyegear.dm
+++ b/code/modules/client/preference_setup/loadout/lists/eyegear.dm
@@ -1,6 +1,6 @@
/decl/loadout_category/eyes
name = "Eyewear"
-
+
/decl/loadout_option/eyes
category = /decl/loadout_category/eyes
slot = slot_glasses_str
@@ -40,3 +40,67 @@
name = "blindfold"
path = /obj/item/clothing/glasses/blindfold
flags = GEAR_HAS_COLOR_SELECTION
+
+/decl/loadout_option/eyes/medical
+ name = "medical eyewear selection"
+ path = /obj/item/clothing/glasses
+
+/decl/loadout_option/eyes/medical/get_gear_tweak_options()
+ . = ..()
+ LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list])
+ .[/datum/gear_tweak/path/specified_types_list] |= list(
+ /obj/item/clothing/glasses/hud/health,
+ /obj/item/clothing/glasses/hud/health/prescription,
+ /obj/item/clothing/glasses/hud/health/visor,
+ /obj/item/clothing/glasses/eyepatch/hud/medical
+ )
+
+/decl/loadout_option/eyes/security
+ name = "security eyewear selection"
+ path = /obj/item/clothing/glasses
+
+/decl/loadout_option/eyes/security/get_gear_tweak_options()
+ . = ..()
+ LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list])
+ .[/datum/gear_tweak/path/specified_types_list] |= list(
+ /obj/item/clothing/glasses/hud/security,
+ /obj/item/clothing/glasses/hud/security/prescription,
+ /obj/item/clothing/glasses/sunglasses/sechud,
+ /obj/item/clothing/glasses/sunglasses/sechud/toggle,
+ /obj/item/clothing/glasses/eyepatch/hud/security
+ )
+
+/decl/loadout_option/eyes/meson
+ name = "meson eyewear selection"
+ path = /obj/item/clothing/glasses
+
+
+/decl/loadout_option/eyes/meson/get_gear_tweak_options()
+ . = ..()
+ LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list])
+ .[/datum/gear_tweak/path/specified_types_list] |= list(
+ /obj/item/clothing/glasses/meson,
+ /obj/item/clothing/glasses/meson/prescription,
+ /obj/item/clothing/glasses/eyepatch/hud/meson
+ )
+
+/decl/loadout_option/eyes/sciencegoggles
+ name = "scientific eyewear selection"
+ path = /obj/item/clothing/glasses
+
+/decl/loadout_option/eyes/sciencegoggles/get_gear_tweak_options()
+ . = ..()
+ LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list])
+ .[/datum/gear_tweak/path/specified_types_list] |= list(
+ /obj/item/clothing/glasses/science,
+ /obj/item/clothing/glasses/science/prescription,
+ /obj/item/clothing/glasses/eyepatch/hud/science
+ )
+
+/decl/loadout_option/eyes/welding
+ name = "welding goggles"
+ path = /obj/item/clothing/glasses/welding
+
+/decl/loadout_option/eyes/material
+ name = "optical material scanner"
+ path = /obj/item/clothing/glasses/material
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/lists/utility.dm b/code/modules/client/preference_setup/loadout/lists/utility.dm
index 28894d43167..81eb76f18c6 100644
--- a/code/modules/client/preference_setup/loadout/lists/utility.dm
+++ b/code/modules/client/preference_setup/loadout/lists/utility.dm
@@ -73,3 +73,23 @@
"utility knife" = /obj/item/knife/utility,
"lightweight utility knife" = /obj/item/knife/utility/lightweight
)
+
+/decl/loadout_option/utility/cheaptablet
+ name = "tablet computer, cheap"
+ path = /obj/item/modular_computer/tablet/preset/custom_loadout/cheap
+ cost = 3
+
+/decl/loadout_option/utility/normaltablet
+ name = "tablet computer, advanced"
+ path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced
+ cost = 4
+
+/decl/loadout_option/utility/cheaplaptop
+ name = "laptop computer, cheap"
+ path = /obj/item/modular_computer/laptop/preset/custom_loadout/cheap
+ cost = 3
+
+/decl/loadout_option/utility/normallaptop
+ name = "laptop computer, advanced"
+ path = /obj/item/modular_computer/laptop/preset/custom_loadout/advanced
+ cost = 4
\ No newline at end of file
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index c48b90b8814..d771fef81f2 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -75,6 +75,8 @@ var/global/list/time_prefs_fixed = list()
/datum/preferences/Destroy()
. = ..()
+ QDEL_NULL(player_setup)
+ QDEL_NULL(panel)
QDEL_LIST_ASSOC_VAL(char_render_holders)
/datum/preferences/proc/setup()
diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm
index 292bc8ffe73..9dfa71691f7 100644
--- a/code/modules/clothing/spacesuits/breaches.dm
+++ b/code/modules/clothing/spacesuits/breaches.dm
@@ -228,7 +228,7 @@
repair_breaches(BRUTE, 3, user)
return
- else if(istype(W, /obj/item/tape_roll))
+ else if(istype(W, /obj/item/ducttape))
var/datum/breach/target_breach //Target the largest unpatched breach.
for(var/datum/breach/B in breaches)
if(B.patched)
diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm
index 7cb2acf9d08..d328b7af5d6 100644
--- a/code/modules/clothing/spacesuits/rig/suits/light.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/light.dm
@@ -130,7 +130,7 @@
var/mob/M = usr
if(!M.mind) return 0
if(M.incapacitated()) return 0
- var/input = sanitizeSafe(input("What do you want to name your suit?", "Rename suit"), MAX_NAME_LEN)
+ var/input = sanitize_safe(input("What do you want to name your suit?", "Rename suit"), MAX_NAME_LEN)
if(src && input && !M.incapacitated() && in_range(M,src))
if(!findtext(input, "the", 1, 4))
input = "\improper [input]"
@@ -147,7 +147,7 @@
var/mob/M = usr
if(!M.mind) return 0
if(M.incapacitated()) return 0
- var/input = sanitizeSafe(input("Please describe your voidsuit in 128 letters or less.", "write description"), MAX_DESC_LEN)
+ var/input = sanitize_safe(input("Please describe your voidsuit in 128 letters or less.", "write description"), MAX_DESC_LEN)
if(src && input && !M.incapacitated() && in_range(M,src))
desc = input
to_chat(M, "Suit description succesful!")
diff --git a/code/modules/clothing/under/accessories/ranks.dm b/code/modules/clothing/under/accessories/ranks.dm
new file mode 100644
index 00000000000..e9dd4e672eb
--- /dev/null
+++ b/code/modules/clothing/under/accessories/ranks.dm
@@ -0,0 +1,14 @@
+//Rank accessory base item
+/obj/item/clothing/accessory/rank
+ name = "rank tabs"
+ desc = "A set of grey rank tabs."
+ slot = ACCESSORY_SLOT_RANK
+ hide_on_uniform_rolldown = TRUE
+ hide_on_uniform_rollsleeves = TRUE
+ var/ranking //Shorthand for the rank
+ var/ranking_full //Full name of the rank.
+
+/obj/item/clothing/accessory/rank/Initialize()
+ . = ..()
+ name = "[initial(name)] ([ranking_full])"
+ desc = "[initial(desc)] This set denotes a rank of [ranking_full] ([ranking])."
\ No newline at end of file
diff --git a/code/modules/codex/categories/category_recipes.dm b/code/modules/codex/categories/category_recipes.dm
index 741c99adacb..f575ffec50b 100644
--- a/code/modules/codex/categories/category_recipes.dm
+++ b/code/modules/codex/categories/category_recipes.dm
@@ -85,7 +85,7 @@
var/mechanics_text = ""
if(recipe.mechanics_text)
mechanics_text = "[recipe.mechanics_text]
"
- mechanics_text += "This recipe requires the following ingredients:
"
+ mechanics_text += "This recipe requires the following ingredients:
"
var/list/ingredients = list()
for(var/thing in recipe.reagents)
var/decl/material/thing_reagent = thing
@@ -95,27 +95,29 @@
var/count = recipe.items[thing]
ingredients += (count > 1) ? "[count]x [initial(thing_atom.name)]" : "\a [initial(thing_atom.name)]"
for(var/thing in recipe.fruit)
- ingredients += "[recipe.fruit[thing]] [thing]\s"
+ ingredients += "[recipe.fruit[thing]]x [thing]"
+ if(recipe.coating)
+ var/decl/material/coating = recipe.coating
+ ingredients += "\a [initial(coating.name)] coating"
mechanics_text += "- [jointext(ingredients, "
- ")]
"
var/atom/recipe_product = recipe.result
- mechanics_text += "
This recipe takes [CEILING(recipe.time/10)] second\s to cook in a microwave and creates \a [initial(recipe_product.name)]."
- var/lore_text = recipe.lore_text
- if(!lore_text)
- lore_text = initial(recipe_product.desc)
-
+ var/plural = recipe.result_quantity > 1
+ mechanics_text += "
This recipe takes [CEILING(recipe.time/10)] second\s to cook in [recipe.get_appliances_string()] and creates [plural ? recipe.result_quantity : "a(n)"] [initial(recipe_product.name)][plural ? "s" : ""]."
var/recipe_name = recipe.display_name || sanitize(initial(recipe_product.name))
- guide_html += "[capitalize(recipe_name)]
Place [english_list(ingredients)] into a microwave for [CEILING(recipe.time/10)] second\s."
+ guide_html += "[capitalize(recipe_name)]
Place [english_list(ingredients)] into [recipe.get_appliances_string()] for [CEILING(recipe.time/10)] second\s."
entries_to_register += new /datum/codex_entry( \
- _display_name = "[recipe_name] (microwave recipe)", \
+ _display_name = "[recipe_name] (recipe)", \
_associated_strings = list(lowertext(recipe_name)), \
- _lore_text = lore_text, \
+ _lore_text = recipe.lore_text || initial(recipe_product.desc), \
_mechanics_text = mechanics_text, \
_antag_text = recipe.antag_text \
)
for(var/datum/codex_entry/entry in entries_to_register)
SScodex.add_entry_by_string(entry.name, entry)
+ for(var/str in entry.associated_strings)
+ SScodex.add_entry_by_string(str, entry)
items |= entry.name
. = ..()
\ No newline at end of file
diff --git a/code/modules/codex/entries/cooking.dm b/code/modules/codex/entries/cooking.dm
new file mode 100644
index 00000000000..da34b6a99d4
--- /dev/null
+++ b/code/modules/codex/entries/cooking.dm
@@ -0,0 +1,26 @@
+/datum/codex_entry/rawcutlet
+ associated_paths = list(/obj/item/chems/food/rawcutlet)
+
+/datum/codex_entry/rawcutlet/New(_display_name, list/_associated_paths, list/_associated_strings, _lore_text, _mechanics_text, _antag_text)
+ . = ..()
+ var/obj/item/chems/food/rawcutlet/example = /obj/item/chems/food/rawcutlet
+ lore_text = initial(example.desc)
+ mechanics_text = "Three raw cutlets can be made by slicing a piece of raw meat with any sharp object. It can be cooked to make a cutlet."
+
+/datum/codex_entry/doughslice
+ associated_paths = list(/obj/item/chems/food/doughslice)
+
+/datum/codex_entry/doughslice/New(_display_name, list/_associated_paths, list/_associated_strings, _lore_text, _mechanics_text, _antag_text)
+ . = ..()
+ var/obj/item/chems/food/doughslice/example = /obj/item/chems/food/doughslice
+ lore_text = initial(example.desc)
+ mechanics_text = "A dough slice can be made by slicing a piece of flatdough with any sharp object."
+
+/datum/codex_entry/flatdough
+ associated_paths = list(/obj/item/chems/food/sliceable/flatdough)
+
+/datum/codex_entry/flatdough/New(_display_name, list/_associated_paths, list/_associated_strings, _lore_text, _mechanics_text, _antag_text)
+ . = ..()
+ var/obj/item/chems/food/sliceable/flatdough/example = /obj/item/chems/food/sliceable/flatdough
+ lore_text = initial(example.desc)
+ mechanics_text = "A flatdough can be made by flattening dough with a rolling pin."
diff --git a/code/modules/crafting/_crafting_holder.dm b/code/modules/crafting/_crafting_holder.dm
index 4e86dc9980d..5af8fd51747 100644
--- a/code/modules/crafting/_crafting_holder.dm
+++ b/code/modules/crafting/_crafting_holder.dm
@@ -45,7 +45,7 @@
/obj/item/crafting_holder/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/pen))
- var/new_label = sanitizeSafe(input(user, "What do you wish to label this assembly?", "Assembly Labelling", label_name), MAX_NAME_LEN)
+ var/new_label = sanitize_safe(input(user, "What do you wish to label this assembly?", "Assembly Labelling", label_name), MAX_NAME_LEN)
if(new_label && !user.incapacitated() && W.loc == user && user.Adjacent(src) && !QDELETED(src))
to_chat(user, SPAN_NOTICE("You label \the [src] with '[new_label]'."))
label_name = new_label
diff --git a/code/modules/crafting/_crafting_stage.dm b/code/modules/crafting/_crafting_stage.dm
index 6469b0f6a77..e2283ad694a 100644
--- a/code/modules/crafting/_crafting_stage.dm
+++ b/code/modules/crafting/_crafting_stage.dm
@@ -92,7 +92,7 @@
/decl/crafting_stage/tape
consume_completion_trigger = FALSE
- completion_trigger_type = /obj/item/tape_roll
+ completion_trigger_type = /obj/item/ducttape
/decl/crafting_stage/pipe
completion_trigger_type = /obj/item/pipe
diff --git a/code/modules/culture_descriptor/_culture.dm b/code/modules/culture_descriptor/_culture.dm
index 7690b7ac453..d3d46b64bf2 100644
--- a/code/modules/culture_descriptor/_culture.dm
+++ b/code/modules/culture_descriptor/_culture.dm
@@ -51,8 +51,8 @@
return _language.get_random_name(gender)
return capitalize(pick(gender==FEMALE ? global.first_names_female : global.first_names_male)) + " " + capitalize(pick(global.last_names))
-/decl/cultural_info/proc/sanitize_name(var/new_name)
- return sanitizeName(new_name)
+/decl/cultural_info/proc/sanitize_cultural_name(new_name)
+ return sanitize_name(new_name)
/decl/cultural_info/proc/get_description(var/verbose = TRUE)
LAZYSET(., "details", jointext(get_text_details(), "
"))
diff --git a/code/modules/culture_descriptor/culture/cultures_human.dm b/code/modules/culture_descriptor/culture/cultures_human.dm
index 14176a7ed69..9c70a00a896 100644
--- a/code/modules/culture_descriptor/culture/cultures_human.dm
+++ b/code/modules/culture_descriptor/culture/cultures_human.dm
@@ -23,5 +23,5 @@
/decl/language/sign
)
-/decl/cultural_info/culture/synthetic/sanitize_name(new_name)
- return sanitizeName(new_name, allow_numbers = TRUE)
+/decl/cultural_info/culture/synthetic/sanitize_cultural_name(new_name)
+ return sanitize_name(new_name, allow_numbers = TRUE)
diff --git a/code/modules/fabrication/_fabricator.dm b/code/modules/fabrication/_fabricator.dm
index 7d68380da2d..e34397bd246 100644
--- a/code/modules/fabrication/_fabricator.dm
+++ b/code/modules/fabrication/_fabricator.dm
@@ -128,15 +128,19 @@
if(length(installed_designs))
design_cache |= installed_designs
- if(!known_tech)
- known_tech = get_default_initial_tech_levels()
- var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device)
- var/datum/computer_network/network = device.get_network()
- if(network)
- for(var/obj/machinery/design_database/db in network.get_devices_by_type(/obj/machinery/design_database))
- for(var/tech in db.tech_levels)
- if(db.tech_levels[tech] > known_tech[tech])
- known_tech[tech] = db.tech_levels[tech]
+ // This is necessary to prevent database consoles from overwriting the default tech levels.
+ var/list/default_tech = get_default_initial_tech_levels()
+ LAZYINITLIST(known_tech)
+ for(var/tech_key in known_tech)
+ known_tech[tech_key] = max(default_tech[tech_key], known_tech[tech_key])
+
+ var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device)
+ var/datum/computer_network/network = device.get_network()
+ if(network)
+ for(var/obj/machinery/design_database/db in network.get_devices_by_type(/obj/machinery/design_database))
+ for(var/tech in db.tech_levels)
+ if(db.tech_levels[tech] > known_tech[tech])
+ known_tech[tech] = db.tech_levels[tech]
var/list/unlocked_tech = SSfabrication.get_unlocked_recipes(fabricator_class, known_tech)
if(length(unlocked_tech))
diff --git a/code/modules/fabrication/designs/general/designs_general.dm b/code/modules/fabrication/designs/general/designs_general.dm
index 7f9234ca2ad..a0c6cbbf25d 100644
--- a/code/modules/fabrication/designs/general/designs_general.dm
+++ b/code/modules/fabrication/designs/general/designs_general.dm
@@ -34,8 +34,8 @@
/datum/fabricator_recipe/taperecorder
path = /obj/item/taperecorder/empty
-/datum/fabricator_recipe/tape
- path = /obj/item/tape
+/datum/fabricator_recipe/taperecorder_tape
+ path = /obj/item/magnetic_tape
/datum/fabricator_recipe/tube/large
path = /obj/item/light/tube/large
diff --git a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
index 672cc53eaa8..4931a0313c8 100644
--- a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
+++ b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm
@@ -362,8 +362,9 @@
/datum/fabricator_recipe/imprinter/circuit/gibber
path = /obj/item/stock_parts/circuitboard/gibber
-/datum/fabricator_recipe/imprinter/circuit/cooker
- path = /obj/item/stock_parts/circuitboard/cooker
+// HEARTH OF HESTIA EDIT
+/datum/fabricator_recipe/imprinter/circuit/appliance
+ path = /obj/item/stock_parts/circuitboard/appliance
/datum/fabricator_recipe/imprinter/circuit/honey_extractor
path = /obj/item/stock_parts/circuitboard/honey
diff --git a/code/modules/fabrication/designs/replicator/designs_food.dm b/code/modules/fabrication/designs/replicator/designs_food.dm
index 9dafa8b26ba..a206285da9b 100644
--- a/code/modules/fabrication/designs/replicator/designs_food.dm
+++ b/code/modules/fabrication/designs/replicator/designs_food.dm
@@ -11,5 +11,5 @@
/datum/fabricator_recipe/food/soydope
path = /obj/item/chems/food/soydope
-/datum/fabricator_recipe/food/ricepudding
- path = /obj/item/chems/food/ricepudding
\ No newline at end of file
+/datum/fabricator_recipe/food/boiledrice
+ path = /obj/item/chems/food/boiledrice
\ No newline at end of file
diff --git a/code/modules/fabrication/fabricator_food.dm b/code/modules/fabrication/fabricator_food.dm
index 086832d7e68..da435bdd912 100644
--- a/code/modules/fabrication/fabricator_food.dm
+++ b/code/modules/fabrication/fabricator_food.dm
@@ -7,7 +7,8 @@
base_icon_state = "replicator"
has_recycler = FALSE
base_storage_capacity = list(
- /decl/material/liquid/nutriment = 100
+ /decl/material/liquid/nutriment = 100,
+ /decl/material/liquid/nutriment/triglyceride/oil = 20
)
/obj/machinery/fabricator/replicator/hear_talk(var/mob/M, var/text, var/verb, var/decl/language/speaking)
@@ -18,7 +19,7 @@
addtimer(CALLBACK(src, /obj/machinery/fabricator/replicator/proc/state_status), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
else if(findtext(true_text, "menu"))
addtimer(CALLBACK(src, /obj/machinery/fabricator/replicator/proc/state_menu), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
- else
+ else
for(var/datum/fabricator_recipe/recipe in design_cache)
if(recipe.hidden && !(fab_status_flags & FAB_HACKED))
continue
diff --git a/code/modules/food/machines/_appliance.dm b/code/modules/food/machines/_appliance.dm
new file mode 100644
index 00000000000..2b2e5a83115
--- /dev/null
+++ b/code/modules/food/machines/_appliance.dm
@@ -0,0 +1,665 @@
+// This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed.
+
+// Tracks precooked food to stop deep fried baked grilled grilled grilled diona nymph cereal.
+/obj/item/chems/food
+ var/tmp/list/cooked
+
+// Root type for cooking machines. See following files for specific implementations.
+/obj/machinery/appliance
+ name = "cooker"
+ desc = "You shouldn't be seeing this!"
+ icon = 'icons/obj/cooking_machines.dmi'
+ var/appliancetype = 0
+ density = 1
+ anchored = 1
+ construct_state = /decl/machine_construction/default/panel_closed
+ uncreated_component_parts = null
+ maximum_component_parts = list(/obj/item/stock_parts = 11)
+
+ pass_flags = PASS_FLAG_TABLE
+
+ use_power = 0
+ idle_power_usage = 5 // Power used when turned on, but not processing anything
+ active_power_usage = 1000 // Power used when turned on and actively cooking something
+
+ var/cooking_power = 0 // Effectiveness/speed at cooking
+ var/cooking_coeff = 0 // Part-based cooking power multiplier
+ var/heating_power = 1000 // Effectiveness at heating up; not used for mixers, should be equal to active_power_usage
+ var/max_contents = 1 // Maximum number of things this appliance can simultaneously cook
+ var/on_icon // Icon state used when cooking.
+ var/off_icon // Icon state used when not cooking.
+ var/cooking // Whether or not the machine is currently operating.
+ var/cook_type // A string value used to track what kind of food this machine makes.
+ var/can_cook_mobs // Whether or not this machine accepts grabbed mobs.
+ var/mobdamagetype = BRUTE // Burn damage for cooking appliances, brute for cereal/candy
+ var/food_color // Colour of resulting food item.
+ var/cooked_sound = 'sound/machines/ding.ogg' // Sound played when cooking completes.
+ var/can_burn_food // Can the object burn food that is left inside?
+ var/burn_chance = 10 // How likely is the food to burn?
+ var/list/cooking_objs = list() // List of things being cooked
+
+ // If the machine has multiple output modes, define them here.
+ var/selected_option
+ var/list/output_options = list()
+ var/finish_verb = "pings!"
+ var/combine_first = FALSE//If 1, this appliance will do combination cooking before checking recipes
+
+/obj/machinery/appliance/components_are_accessible(path)
+ return !cooking && ..()
+
+/obj/machinery/appliance/cannot_transition_to(state_path, mob/user)
+ if(cooking)
+ return SPAN_NOTICE("Wait for \the [src] to finish first!")
+ return ..()
+
+/obj/machinery/appliance/Initialize()
+ . = ..()
+ if(length(output_options))
+ verbs += /obj/machinery/appliance/proc/choose_output
+
+/obj/machinery/appliance/Destroy()
+ for (var/a in cooking_objs)
+ var/datum/cooking_item/CI = a
+ qdel(CI.container)//Food is fragile, it probably doesnt survive the destruction of the machine
+ cooking_objs -= CI
+ qdel(CI)
+ return ..()
+
+/obj/machinery/appliance/examine(var/mob/user)
+ . = ..()
+ if(panel_open)
+ to_chat(user, "The service panel is open.")
+ if(Adjacent(user))
+ list_contents(user)
+
+/obj/machinery/appliance/get_mechanics_info()
+ return "Control-click this to toggle its power."
+
+/obj/machinery/appliance/proc/list_contents(var/mob/user)
+ if (!length(cooking_objs))
+ to_chat(user, SPAN_NOTICE("It is empty."))
+ return
+ var/string = "Contains..."
+ for (var/datum/cooking_item/CI in cooking_objs)
+ string += "- \a [CI.container.label(null, CI.combine_target)], [report_progress(CI)]
"
+ string += "
"
+ to_chat(user, string)
+
+/obj/machinery/appliance/proc/report_progress(var/datum/cooking_item/CI)
+ if (!CI || !CI.max_cookwork)
+ return null
+
+ if (!CI.cookwork)
+ return "It is cold."
+ var/progress = CI.cookwork / CI.max_cookwork
+ var/half_overcook = (CI.overcook_mult - 1)*0.5
+ switch(progress)
+ if (0 to 0.25)
+ return "It's barely started cooking."
+ if (0.25 to 0.75)
+ return SPAN_NOTICE("It's cooking away nicely.")
+ if (0.75 to 1)
+ return SPAN_NOTICE("It's almost ready!")
+ if (progress < 1+half_overcook)
+ return FONT_COLORED(COLOR_GREEN_GRAY, "It is done!")
+ if (progress < CI.overcook_mult)
+ return SPAN_WARNING("It looks overcooked, get it out!")
+ return SPAN_DANGER("It is burning!")
+
+/obj/machinery/appliance/proc/get_cooking_item_from_container(var/obj/item/chems/cooking_container/CC)
+ for(var/datum/cooking_item/CI as anything in cooking_objs)
+ if(CI.container == CC)
+ return CI
+
+/obj/machinery/appliance/on_update_icon()
+ if ((use_power != POWER_USE_OFF) && length(cooking_objs))
+ icon_state = on_icon
+ else
+ icon_state = off_icon
+
+/obj/machinery/appliance/proc/attempt_toggle_power(mob/user)
+ if (!isliving(user))
+ return
+
+ if (!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES))
+ return
+
+ if (user.stat || user.restrained() || user.incapacitated())
+ return
+
+ if (!Adjacent(user) && !issilicon(user))
+ to_chat(user, "You can't reach [src] from here.")
+ return
+
+ update_use_power((use_power == POWER_USE_OFF) ? POWER_USE_IDLE : POWER_USE_OFF) // If on, use active power, else use no power
+ if(user)
+ user.visible_message("[user] turns [src] [use_power ? "on" : "off"].", "You turn [use_power ? "on" : "off"] [src].")
+ playsound(src, 'sound/machines/click.ogg', 40, 1)
+ update_icon()
+
+/obj/machinery/appliance/AICtrlClick(mob/user)
+ attempt_toggle_power(user, TRUE)
+
+/obj/machinery/appliance/proc/choose_output()
+ set src in view()
+ set name = "Choose output"
+ set category = "Object"
+
+ if (!isliving(usr))
+ return
+
+ if (!usr.check_dexterity(DEXTERITY_SIMPLE_MACHINES))
+ return
+
+ if (usr.stat || usr.restrained() || usr.incapacitated())
+ return
+
+ if (!Adjacent(usr) && !issilicon(usr))
+ to_chat(usr, "You can't adjust the [src] from this distance, get closer!")
+ return
+ if(!length(output_options))
+ return
+ var/choice = input("What specific food do you wish to make with [src]?", "Choose Output") as null|anything in output_options+"Default"
+ if(!choice)
+ return
+ selected_option = (choice == "Default") ? null : choice
+ to_chat(usr, SPAN_NOTICE("You decide to make [choice == "Default" ? "nothing specific" : choice] with [src]."))
+
+//Handles all validity checking and error messages for inserting things
+/obj/machinery/appliance/proc/can_insert(var/obj/item/I, var/mob/user)
+ if(!I.canremove || istype(I.loc, /mob/living/silicon) || istype(I.loc, /obj/item/rig_module))
+ return CANNOT_INSERT
+
+ // We are trying to cook a grabbed mob.
+ var/obj/item/grab/G = I
+ if(istype(G))
+
+ if(!can_cook_mobs)
+ to_chat(user, SPAN_WARNING("That's not going to fit."))
+ return CANNOT_INSERT
+
+ if(!isliving(G.affecting))
+ to_chat(user, SPAN_WARNING("You can't cook that."))
+ return CANNOT_INSERT
+
+ return INSERT_GRABBED
+
+ if (!has_space(I))
+ to_chat(user, SPAN_WARNING("There's no room in [src] for that!"))
+ return CANNOT_INSERT
+
+ if (istype(I, /obj/item/chems/cooking_container))
+ var/obj/item/chems/cooking_container/CC = I
+ if(CC.appliancetype & appliancetype)
+ return CAN_INSERT
+
+ // We're trying to cook something else. Check if it's valid.
+ var/obj/item/chems/food/check = I
+ if(istype(check) && LAZYISIN(cook_type,check.cooked))
+ to_chat(user, SPAN_WARNING("[check] has already been [cook_type]."))
+ return CANNOT_INSERT
+ else if(istype(I, /obj/item/chems/glass))
+ to_chat(user, SPAN_WARNING("That would probably break [I]."))
+ return CANNOT_INSERT
+ else if(isCrowbar(I) || isScrewdriver(I) || istype(I, /obj/item/storage/part_replacer))
+ return CANNOT_INSERT
+ else if(!istype(check) && !istype(I, /obj/item/holder))
+ to_chat(user, SPAN_WARNING("That's not edible."))
+ return CANNOT_INSERT
+ return CAN_INSERT
+
+//This function is overridden by cookers that do stuff with containers
+/obj/machinery/appliance/proc/has_space(var/obj/item/I)
+ if (length(cooking_objs) >= max_contents)
+ return FALSE
+ return TRUE
+
+/obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user)
+ if(component_attackby(I, user))
+ return TRUE
+
+ if(!cook_type || (stat & (BROKEN)))
+ to_chat(user, SPAN_WARNING("[src] is not working."))
+ return
+
+ var/result = can_insert(I, user)
+ if(result == CANNOT_INSERT)
+ return ..(I, user)
+
+ if(result == INSERT_GRABBED)
+ var/obj/item/grab/G = I
+ if (G && istype(G) && G.affecting)
+ cook_mob(G.affecting, user)
+ return
+
+ //From here we can start cooking food
+ add_content(I, user)
+ update_icon()
+ return TRUE // do not call afterattack
+
+//Override for container mechanics
+/obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user)
+ if(!user.unEquip(I))
+ return
+
+ var/datum/cooking_item/CI = has_space(I)
+ if (istype(I, /obj/item/chems/cooking_container) && CI)
+ var/obj/item/chems/cooking_container/CC = I
+ CI = new /datum/cooking_item/(CC)
+ I.forceMove(src)
+ cooking_objs.Add(CI)
+ if (CC.check_contents() == CONTAINER_EMPTY)//If we're just putting an empty container in, then dont start any processing.
+ user.visible_message("[user] puts [I] into [src].")
+ return
+ else
+ if (CI && istype(CI))
+ I.forceMove(CI.container)
+
+ else //Something went wrong
+ return
+
+ if (selected_option)
+ CI.combine_target = selected_option
+
+ // We can actually start cooking now.
+ user.visible_message("[user] puts [I] into [src].")
+ if(selected_option || length(CI.container.contents) || select_recipe(CI.container || src, appliance = CI.container.appliancetype)) // we're doing combo cooking, we're not just heating reagents, OR we have a valid reagent-only recipe
+ // this is to stop reagents from burning when you're heating stuff
+ get_cooking_work(CI)
+ cooking = TRUE
+
+ return CI
+
+/obj/machinery/appliance/proc/get_cooking_work(var/datum/cooking_item/CI)
+ for (var/obj/item/J in CI.container)
+ oilwork(J, CI)
+
+ for (var/_R in CI.container.reagents.reagent_volumes)
+ if (ispath(_R, /decl/material/liquid/nutriment))
+ CI.max_cookwork += CI.container.reagents.reagent_volumes[_R] *2//Added reagents contribute less than those in food items due to granular form
+
+ //Nonfat reagents will soak oil
+ if (!ispath(_R, /decl/material/liquid/nutriment/triglyceride))
+ CI.max_oil += CI.container.reagents.reagent_volumes[_R] * 0.25
+ else
+ CI.max_cookwork += CI.container.reagents.reagent_volumes[_R]
+ CI.max_oil += CI.container.reagents.reagent_volumes[_R]* 0.10
+
+ //Rescaling cooking work to avoid insanely long times for large things
+ var/brackets = CI.max_cookwork / 4
+ CI.max_cookwork = 4*(1-0.95**brackets)/0.05
+
+//Just a helper to save code duplication in the above
+/obj/machinery/appliance/proc/oilwork(var/obj/item/I, var/datum/cooking_item/CI)
+ var/obj/item/chems/food/S = I
+ var/work = 0
+ if (istype(S) && S.reagents)
+ for (var/_R in S.reagents.reagent_volumes)
+ if (ispath(_R, /decl/material/liquid/nutriment))
+ work += S.reagents.reagent_volumes[_R] *3//Core nutrients contribute much more than peripheral chemicals
+
+ //Nonfat reagents will soak oil
+ if (!ispath(_R, /decl/material/liquid/nutriment/triglyceride))
+ CI.max_oil += S.reagents.reagent_volumes[_R] * 0.35
+ else
+ work += S.reagents.reagent_volumes[_R]
+ CI.max_oil += S.reagents.reagent_volumes[_R] * 0.15
+
+ else if(istype(I, /obj/item/holder))
+ var/mob/living/contained = locate() in I
+ if (contained)
+ work += (contained.mob_size * contained.mob_size * 2)+2
+
+ CI.max_cookwork += work
+
+//Called every tick while we're cooking something
+/obj/machinery/appliance/proc/do_cooking_tick(var/datum/cooking_item/CI)
+ if (!CI.max_cookwork)
+ return FALSE
+
+ var/was_done = (CI.cookwork >= CI.max_cookwork)
+
+ CI.cookwork += cooking_power
+
+ if (!was_done && CI.cookwork >= CI.max_cookwork)
+ //If cookwork has gone from above to below 0, then this item finished cooking
+ finish_cooking(CI)
+
+ else if (can_burn_food && !CI.burned && CI.cookwork > CI.max_cookwork * CI.overcook_mult)
+ burn_food(CI)
+
+ // Gotta hurt.
+ for(var/obj/item/holder/H in CI.container.contents)
+ var/mob/living/M = locate() in H.contents
+ M.apply_damage(rand(1,3), mobdamagetype, BP_CHEST)
+
+ return TRUE
+
+/obj/machinery/appliance/Process()
+ if (cooking)
+ for (var/datum/cooking_item/CI as anything in cooking_objs)
+ if(cooking_power > 0)
+ do_cooking_tick(CI)
+ check_cooking()
+
+/obj/machinery/appliance/proc/check_cooking()
+ if (cooking)
+ if(!length(cooking_objs))
+ cooking = FALSE
+ return
+ var/has_contents = FALSE
+ for (var/datum/cooking_item/CI as anything in cooking_objs)
+ if(length(CI.container.contents) || CI.container.reagents.total_volume)
+ has_contents = TRUE
+ break
+ if (!has_contents)
+ cooking = FALSE
+
+/obj/machinery/appliance/proc/finish_cooking(var/datum/cooking_item/CI)
+ audible_message("[src] [finish_verb]")
+ if(cooked_sound)
+ playsound(get_turf(src), cooked_sound, 50, 1)
+ //Check recipes first, a valid recipe overrides other options
+ var/decl/recipe/recipe = null
+ var/atom/C = null
+ var/appliance
+ if (CI.container?.appliancetype)
+ C = CI.container
+ appliance = CI.container.appliancetype
+ else if(appliancetype)
+ C = src
+ appliance = appliancetype
+ if(appliance)
+ recipe = select_recipe(C, appliance = appliance)
+
+ if (recipe)
+ var/decl/recipe/oldrecipe = recipe
+ var/list/cooked_items = list()
+ while(recipe)
+ cooked_items += recipe.make_food(C)
+ recipe = select_recipe(C, appliance = appliance)
+ if (!recipe || recipe != oldrecipe)
+ break
+
+ for (var/r in cooked_items)
+ var/obj/item/chems/food/R = r
+ R.forceMove(C) //Move everything from the buffer back to the container
+ LAZYDISTINCTADD(R.cooked, cook_type)
+
+ . = TRUE //None of the rest of this function is relevant for recipe cooking
+
+ else if(CI.combine_target)
+ . = combination_cook(CI)
+
+ else
+ //Otherwise, we're just doing standard modification cooking. change a color + name
+ for (var/obj/item/i in C)
+ modify_cook(i, CI)
+
+ //Final step. Cook function just cooks batter for now.
+ for (var/obj/item/chems/food/S in C)
+ S.cook()
+
+//Combination cooking involves combining the names and reagents of ingredients into a predefined output object
+//The ingredients represent flavours or fillings. EG: donut pizza, cheese bread
+/obj/machinery/appliance/proc/combination_cook(var/datum/cooking_item/CI)
+ if(!CI.combine_target)
+ return
+ var/cook_path = output_options[CI.combine_target]
+
+ var/list/words = list()
+ var/list/cooktypes = list()
+ var/datum/reagents/buffer = new /datum/reagents(1000, global.temp_reagents_holder)
+ var/totalcolour
+
+ for (var/obj/item/I in CI.container)
+ var/obj/item/chems/food/S
+ if (istype(I, /obj/item/holder))
+ S = create_mob_food(I, CI)
+ else if (istype(I, /obj/item/chems/food))
+ S = I
+
+ if (!S)
+ continue
+
+ words |= splittext(S.name," ")
+ cooktypes |= S.cooked
+
+ if (S.reagents?.total_volume)
+ if (S.filling_color)
+ if (!totalcolour || !buffer.total_volume)
+ totalcolour = S.filling_color
+ else
+ var/t = buffer.total_volume + S.reagents.total_volume
+ t = buffer.total_volume / y
+ totalcolour = BlendRGB(totalcolour, S.filling_color, t)
+ //Blend colours in order to find a good filling color
+
+ S.reagents.trans_to_holder(buffer, S.reagents.total_volume)
+ //Cleanup these empty husk ingredients now
+ if (I)
+ qdel(I)
+ if (S)
+ qdel(S)
+
+ CI.container.reagents.trans_to_holder(buffer, CI.container.reagents.total_volume)
+
+ var/obj/item/chems/food/variable/result = new cook_path(CI.container)
+ buffer.trans_to_obj(result, buffer.total_volume)
+
+ //Filling overlay
+ var/image/I = image(result.icon, "[result.icon_state]_filling")
+ I.color = totalcolour
+ result.overlays += I
+ result.filling_color = totalcolour
+
+ //Set the name.
+ words -= list("and", "the", "in", "is", "bar", "raw", "sticks", "boiled", "fried", "deep", "-o-", "warm", "two", "flavored")
+ //Remove common connecting words and unsuitable ones from the list. Unsuitable words include those describing
+ //the shape, cooked-ness/temperature or other state of an ingredient which doesn't apply to the finished product
+ words.Remove(result.name)
+ shuffle(words)
+ var/num = 6 //Maximum number of words
+ result.name = result.get_name_sans_prefix()
+ while (num > 0)
+ num--
+ if (!length(words))
+ break
+ //Add prefixes from the ingredients in a random order until we run out or hit limit
+ result.name = "[pop(words)] [result.name]"
+
+ //This proc sets the size of the output result
+ result.update_prefix()
+ return result
+
+//Helper proc for standard modification cooking
+/obj/machinery/appliance/proc/modify_cook(var/obj/item/input, var/datum/cooking_item/CI)
+ var/obj/item/chems/food/result
+ if (istype(input, /obj/item/holder))
+ result = create_mob_food(input, CI)
+ else if (istype(input, /obj/item/chems/food))
+ result = input
+ else
+ //Nonviable item
+ return
+
+ if (!result)
+ return
+
+ LAZYDISTINCTADD(result.cooked, cook_type)
+
+ // Set icon and appearance.
+ change_product_appearance(result, CI)
+
+ // Update strings.
+ change_product_strings(result, CI)
+
+/obj/machinery/appliance/proc/burn_food(var/datum/cooking_item/CI)
+ // You dun goofed.
+ CI.burned = TRUE
+ CI.container.clear()
+ new /obj/item/chems/food/badrecipe(CI.container)
+
+ // Produce nasty smoke.
+ visible_message(SPAN_DANGER("[src] vomits a gout of rancid smoke!"))
+ var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad
+ smoke.attach(src)
+ smoke.set_up(10, 0, get_turf(src), 300)
+ smoke.start()
+
+/obj/machinery/appliance/CtrlClick(var/mob/user)
+ if(!anchored)
+ return ..()
+ attempt_toggle_power(user)
+
+/obj/machinery/appliance/physical_attack_hand(var/mob/user)
+ if (!length(cooking_objs))
+ return
+ if (removal_menu(user))
+ return
+ . = ..()
+
+/obj/machinery/appliance/proc/removal_menu(var/mob/user)
+ if (!can_remove_items(user))
+ return FALSE
+ var/list/choices = list()
+ var/list/menuoptions = list()
+ for (var/a in cooking_objs)
+ var/datum/cooking_item/CI = a
+ if (CI.container)
+ var/current_iteration_len = length(menuoptions) + 1
+ menuoptions[CI.container.label(current_iteration_len)] = CI
+ var/obj/item/icon_to_use = CI.container
+ if(CI.container.contents.len == 1)
+ var/obj/item/I = locate() in CI.container.contents
+ icon_to_use = I
+ choices[CI.container.label(current_iteration_len)] = icon_to_use
+
+ var/selection = show_radial_menu(user, src, choices, require_near = TRUE, tooltips = TRUE, no_repeat_close = TRUE)
+ if (selection)
+ var/datum/cooking_item/CI = menuoptions[selection]
+ eject(CI, user)
+ update_icon()
+ return TRUE
+
+/obj/machinery/appliance/proc/can_remove_items(var/mob/user)
+ if (!Adjacent(user) || isanimal(user) || user.incapacitated())
+ return FALSE
+
+ return TRUE
+
+/obj/machinery/appliance/proc/eject(var/datum/cooking_item/CI, var/mob/user = null)
+ var/obj/item/thing
+ var/delete = TRUE
+ var/status = CI.container.check_contents()
+ if (status == CONTAINER_SINGLE)//If theres only one object in a container then we extract that
+ thing = locate(/obj/item) in CI.container
+ delete = FALSE
+ else//If the container is empty OR contains more than one thing, then we must extract the container
+ thing = CI.container
+ cooking_objs -= CI
+ if (!user || !user.put_in_hands(thing))
+ thing.forceMove(get_turf(src))
+
+ if (delete)
+ qdel(CI)
+ else
+ CI.reset()//reset instead of deleting if the container is left inside
+ check_cooking()
+
+/obj/machinery/appliance/proc/cook_mob(var/mob/living/victim, var/mob/user)
+ return
+
+/obj/machinery/appliance/proc/change_product_strings(var/obj/item/chems/food/product, var/datum/cooking_item/CI)
+ product.name = "[cook_type] [product.name]"
+ product.desc = "[product.desc]\nIt has been [cook_type]."
+
+/obj/machinery/appliance/proc/change_product_appearance(var/obj/item/chems/food/product, var/datum/cooking_item/CI)
+ if (!product.batter_coating) //Coatings change colour through a new sprite
+ product.color = food_color
+ product.filling_color = food_color
+
+//This function creates a food item which represents a dead mob
+/obj/machinery/appliance/proc/create_mob_food(var/obj/item/holder/H, var/datum/cooking_item/CI)
+ var/mob/living/victim = locate() in H.contents
+ if (!istype(H) || !victim)
+ qdel(H)
+ return null
+ if (victim.stat != DEAD)
+ return null //Victim somehow survived the cooking, they do not become food
+
+ var/obj/item/chems/food/variable/mob/result = new /obj/item/chems/food/variable/mob(CI.container)
+ result.w_class = victim.mob_size
+ var/reagent_amount = victim.mob_size ** 2 * 3
+ if(isanimal(victim))
+ var/mob/living/simple_animal/SA = victim
+ result.kitchen_tag = initial(SA.name) // workaround for no kitchen_tag var
+ if (SA.meat_amount)
+ reagent_amount = SA.meat_amount*9 // at a rate of 9 protein per meat
+ var/digest_product_type = victim.get_digestion_product() // DOES NOT RETURN A DECL, RETURNS A PATH
+ var/list/data
+ var/meat_name = result.kitchen_tag || victim.name
+ if(ishuman(victim))
+ var/mob/living/carbon/human/CH = victim
+ meat_name = CH.species?.name || meat_name
+ if(ispath(digest_product_type, /decl/material/liquid/nutriment/protein))
+ data = list("[meat_name] meat" = reagent_amount)
+ result.reagents.add_reagent(digest_product_type, reagent_amount, data)
+
+ if (victim.reagents)
+ victim.reagents.trans_to(result, victim.reagents.total_volume)
+
+ result.appearance = victim
+ result.size = result.reagents.total_volume // so taking a bite doesn't suddenly make it HUGE
+
+ var/matrix/M = matrix()
+ M.Turn(45)
+ M.Translate(1,-2)
+ result.transform = M
+
+ // all done, now delete the old objects
+ victim.forceMove(null)
+ QDEL_NULL(victim)
+ QDEL_NULL(H)
+ check_cooking()
+
+ return result
+
+/datum/cooking_item
+ var/max_cookwork
+ var/cookwork
+ var/overcook_mult = 5
+ var/obj/item/chems/cooking_container/container = null
+ var/combine_target = null
+ var/burned = FALSE
+
+ var/oil = 0
+ var/max_oil = 0//Used for fryers.
+
+/datum/cooking_item/New(var/obj/item/I)
+ container = I
+
+//This is called for containers whose contents are ejected without removing the container
+/datum/cooking_item/proc/reset()
+ max_cookwork = 0
+ cookwork = 0
+ burned = FALSE
+ max_oil = 0
+ oil = 0
+ combine_target = null
+ //Container is not reset
+
+/obj/machinery/appliance/proc/update_cooking_power()
+ cooking_power = cooking_coeff
+
+/obj/machinery/appliance/RefreshParts()
+ ..()
+ var/scan_rating = 0
+ var/cap_rating = 0
+
+ scan_rating = total_component_rating_of_type(/obj/item/stock_parts/scanning_module) - number_of_components(/obj/item/stock_parts/scanning_module)
+ cap_rating = total_component_rating_of_type(/obj/item/stock_parts/capacitor) - number_of_components(/obj/item/stock_parts/capacitor)
+
+ change_power_consumption(initial(active_power_usage) - scan_rating * 25, POWER_USE_ACTIVE)
+ heating_power = initial(heating_power) + cap_rating * 50
+ cooking_coeff = (1 + (scan_rating + cap_rating) / 20) // 100% eff. becomes 120%, 140%, 160% w/ better parts
\ No newline at end of file
diff --git a/code/modules/food/machines/_cooker.dm b/code/modules/food/machines/_cooker.dm
new file mode 100644
index 00000000000..99cba5b8bcd
--- /dev/null
+++ b/code/modules/food/machines/_cooker.dm
@@ -0,0 +1,203 @@
+/obj/machinery/appliance/cooker
+ var/min_temp = 80 + T0C //Minimum temperature to do any cooking
+ var/optimal_temp = 200 + T0C //Temperature at which we have 100% efficiency. efficiency is lowered on either side of this
+ var/optimal_power = 0.8 //cooking power at 100%
+ var/set_temp = 200 + T0C
+ var/temp_settings = 4 // the number of temperature settings to have, including min and optimal
+ var/list/temp_options = list()
+
+ var/loss = 1 //Temp lost per proc when equalising
+ var/resistance = 320000 //Resistance to heating. combines with heating power to determine how long heating takes
+
+ var/light_x = 0
+ var/light_y = 0
+ mobdamagetype = BURN
+ cooking_coeff = 0
+ cooking_power = 0
+ atom_flags = null
+ var/starts_with = list()
+
+/obj/machinery/appliance/cooker/examine(var/mob/user)
+ . = ..()
+ if (Adjacent(user))
+ if (use_power == POWER_USE_OFF)
+ to_chat(user, SPAN_WARNING("It is switched off."))
+ else
+ if (temperature < min_temp)
+ to_chat(user, SPAN_WARNING("[src] is still heating up and is too cold to cook anything yet."))
+ else
+ to_chat(user, SPAN_NOTICE("It is running at [round(get_efficiency(), 0.1)]% efficiency!"))
+ to_chat(user, "Temperature: [round(temperature - T0C, 0.1)]C / [round(optimal_temp - T0C, 0.1)]C")
+ if(panel_open)
+ to_chat(user, "The panel is open.")
+
+/obj/machinery/appliance/cooker/MouseEntered(location, control, params)
+ . = ..()
+ var/list/modifiers = params2list(params)
+ if(modifiers["shift"] && Adjacent(usr))
+ params = replacetext(params, "shift=1;", "") // tooltip doesn't appear unless this is stripped
+ var/description = ""
+ if(!length(cooking_objs))
+ description = "It is empty."
+ else
+ description = "Contains..."
+ for(var/datum/cooking_item/CI in cooking_objs)
+ description += "- \a [CI.container.label(null, CI.combine_target)], [report_progress(CI)]
"
+ description += "
"
+ if(use_power == POWER_USE_OFF)
+ description += "It is switched off."
+ else
+ if(temperature < min_temp)
+ description += "[src] is still heating up and is too cold to cook anything yet."
+ else
+ description += "It is running at [round(get_efficiency(), 0.1)]% efficiency!"
+ description += "
Temperature: [round(temperature - T0C, 0.1)]C / [round(optimal_temp - T0C, 0.1)]C"
+ openToolTip(usr, src, params, name, description)
+
+/obj/machinery/appliance/cooker/MouseExited(location, control, params)
+ . = ..()
+ closeToolTip(usr)
+
+/obj/machinery/appliance/cooker/list_contents(var/mob/user)
+ if (length(cooking_objs))
+ var/string = "Contains..."
+ var/num = 0
+ for (var/a in cooking_objs)
+ var/datum/cooking_item/CI = a
+ num++
+ if (CI?.container)
+ string += "- [CI.container.label(num)], [report_progress(CI)]"
+ to_chat(usr, string)
+ else
+ to_chat(usr, SPAN_NOTICE("It's empty."))
+
+/obj/machinery/appliance/cooker/proc/get_efficiency()
+ . = (cooking_power / optimal_power) * 100
+
+/obj/machinery/appliance/cooker/Initialize()
+ . = ..()
+ var/interval = (optimal_temp - min_temp)/temp_settings
+ for(var/newtemp = min_temp - interval, newtemp<=optimal_temp, newtemp+=interval)
+ var/image/disp_image = image('icons/screen/radial.dmi', "radial_temp")
+ var/hue = RotateHue(hsv(0, 255, 255), 120 * (1 - (newtemp-min_temp)/(optimal_temp-min_temp)))
+ disp_image.color = HSVtoRGB(hue)
+ temp_options["[newtemp - T0C]"] = disp_image
+ temp_options["OFF"] = image('icons/misc/mark.dmi', "x3")
+ loss = (active_power_usage / resistance)*0.5
+ cooking_objs = list()
+ for(var/cctype in starts_with)
+ if (length(cooking_objs) >= max_contents)
+ break
+ if(isnum(starts_with[cctype]))
+ for(var/i = 0, i\The [user] turns [use_power ? "on" : "off"] [src].", "You turn [use_power ? "on" : "off"] [src].")
+
+/obj/machinery/appliance/cooker/on_update_icon()
+ cut_overlays()
+ var/image/light
+ if (use_power == POWER_USE_ACTIVE) // the light is only on when actively heating
+ light = image(icon, "light_on")
+ else
+ light = image(icon, "light_off")
+ light.pixel_x = light_x
+ light.pixel_y = light_y
+ add_overlay(light)
+
+/obj/machinery/appliance/cooker/Process()
+ if ((temperature >= set_temp) && (stat || use_power == 1))
+ QUEUE_TEMPERATURE_ATOMS(src) // cool every tick if we're not turned on or heating
+ if(use_power != POWER_USE_OFF)
+ heat_up()
+ . = ..()
+
+/obj/machinery/appliance/cooker/update_cooking_power()
+ var/temp_scale = 0
+ if(temperature > min_temp)
+ if(temperature >= optimal_temp)
+ temp_scale = Clamp(1 - ((optimal_temp - temperature) / optimal_temp), 0, 1)
+ else
+ temp_scale = temperature / optimal_temp
+ //If we're between min and optimal this will yield a value in the range 0.7 to 1
+ cooking_power *= temp_scale * optimal_power
+ cooking_power = optimal_power * temp_scale * cooking_coeff
+
+/obj/machinery/appliance/cooker/proc/heat_up()
+ if (temperature < set_temp)
+ if (use_power == POWER_USE_IDLE && ((set_temp - temperature) > 5))
+ playsound(src, 'sound/machines/click.ogg', 20, 1)
+ update_use_power(POWER_USE_ACTIVE) //If we're heating we use the active power
+ update_icon()
+ ADJUST_ATOM_TEMPERATURE(src, temperature + heating_power / resistance)
+ update_cooking_power()
+ else
+ if (use_power == POWER_USE_ACTIVE)
+ update_use_power(POWER_USE_IDLE)
+ playsound(src, 'sound/machines/click.ogg', 20, 1)
+ update_icon()
+ QUEUE_TEMPERATURE_ATOMS(src)
+
+/obj/machinery/appliance/cooker/ProcessAtomTemperature()
+ if( use_power != POWER_USE_OFF && !(stat & NOPOWER) ) // must be powered and turned on, to keep heating items
+ update_cooking_power() // update!
+ if(!LAZYLEN(cooking_objs))
+ return TRUE
+ for(var/datum/cooking_item/CI in cooking_objs)
+ QUEUE_TEMPERATURE_ATOMS(CI.container)
+ if(use_power != POWER_USE_OFF && temperature < set_temp) // don't cool down if we're active
+ return TRUE
+ . = ..()
+
+//Cookers do differently, they use containers
+/obj/machinery/appliance/cooker/has_space(var/obj/item/I)
+ if (istype(I, /obj/item/chems/cooking_container))
+ //Containers can go into an empty slot
+ if (length(cooking_objs) < max_contents)
+ return TRUE
+ else
+ //Any food items directly added need an empty container. A slot without a container cant hold food
+ for (var/datum/cooking_item/CI in cooking_objs)
+ if (CI.container.check_contents() == CONTAINER_EMPTY)
+ return CI
+
+ return FALSE
+
+/obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user)
+ var/datum/cooking_item/CI = ..()
+ if (CI?.combine_target)
+ to_chat(user, "[I] will be used to make a [selected_option]. Output selection is returned to default for future items.")
+ selected_option = null
\ No newline at end of file
diff --git a/code/modules/food/machines/_cooker_output.dm b/code/modules/food/machines/_cooker_output.dm
new file mode 100644
index 00000000000..539d6781fe2
--- /dev/null
+++ b/code/modules/food/machines/_cooker_output.dm
@@ -0,0 +1,173 @@
+// Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn.
+/obj/item/chems/food/variable
+ name = "cooked food"
+ icon = 'icons/obj/food_custom.dmi'
+ desc = "If you can see this description then something is wrong. Please report the bug on the tracker."
+ bitesize = 2
+
+ var/size = 5 //The quantity of reagents which is considered "normal" for this kind of food
+ //These objects will change size depending on the ratio of reagents to this value
+ var/min_scale = 0.5
+ var/max_scale = 2
+ var/scale = 1
+
+ w_class = ITEM_SIZE_SMALL
+ var/prefix
+
+/obj/item/chems/food/variable/Initialize()
+ . = ..()
+ if (reagents)
+ reagents.maximum_volume = size*8 + 10
+ else
+ create_reagents(size*8 + 10)
+ update_icon()
+
+/obj/item/chems/food/variable/on_reagent_change()
+ return
+
+/obj/item/chems/food/variable/proc/update_prefix()
+ switch(scale)
+ if (0 to 0.8)
+ prefix = "small"
+ if (0.8 to 1.2)
+ prefix = "large"
+ if (1.2 to 1.4)
+ prefix = "extra large"
+ if (1.4 to 1.6)
+ prefix = "huge"
+ if (1.6 to INFINITY)
+ prefix = "massive"
+ if(scale == min_scale)
+ prefix = "tiny"
+
+ name = "[prefix] [name]"
+
+/obj/item/chems/food/proc/get_name_sans_prefix()
+ return name
+
+/obj/item/chems/food/variable/get_name_sans_prefix()
+ return jointext(splittext(..(), " ") - prefix, " ")
+
+/obj/item/chems/food/variable/proc/update_scale()
+ if (reagents?.total_volume)
+ var/ratio = reagents.total_volume / size
+ scale = sqrt(ratio) //Scaling factor is square root of desired area
+ scale = Clamp(scale, min_scale, max_scale)
+ else
+ scale = min_scale
+ w_class = round(initial(w_class) * scale)
+
+/obj/item/chems/food/variable/on_update_icon(var/overwrite = FALSE)
+ if(!scale || overwrite)
+ update_scale()
+
+ var/matrix/M = matrix()
+ M.Scale(scale)
+ transform = M
+
+ if (!prefix || overwrite)
+ update_prefix()
+
+/obj/item/chems/food/variable/pizza
+ name = "personal pizza"
+ desc = "A personalized pan pizza meant for only one person."
+ icon_state = "personal_pizza"
+ size = 20
+ w_class = ITEM_SIZE_NORMAL
+
+/obj/item/chems/food/variable/bread
+ name = "bread"
+ desc = "Tasty bread."
+ icon_state = "breadcustom"
+ size = 40
+ w_class = ITEM_SIZE_NORMAL
+
+/obj/item/chems/food/variable/pie
+ name = "pie"
+ desc = "Tasty pie."
+ icon_state = "piecustom"
+ size = 25
+
+/obj/item/chems/food/variable/cake
+ name = "cake"
+ desc = "A popular band."
+ icon_state = "cakecustom"
+ size = 40
+ w_class = ITEM_SIZE_NORMAL
+
+/obj/item/chems/food/variable/pocket
+ name = "hot pocket"
+ desc = "You wanna put a bangin- oh, nevermind."
+ icon_state = "donk"
+ size = 8
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/kebab
+ name = "kebab"
+ desc = "Remove this!"
+ icon_state = "kabob"
+ size = 10
+
+/obj/item/chems/food/variable/waffles
+ name = "waffles"
+ desc = "Made with love."
+ icon_state = "waffles"
+ size = 12
+
+/obj/item/chems/food/variable/cookie
+ name = "cookie"
+ desc = "Sugar snap!"
+ icon_state = "cookie"
+ size = 6
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/donut
+ name = "filled donut"
+ desc = "Donut eat this!" // kill me
+ icon_state = "donut"
+ size = 8
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/jawbreaker
+ name = "flavored jawbreaker"
+ desc = "It's like cracking a molar on a rainbow."
+ icon_state = "jawbreaker"
+ size = 4
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/candybar
+ name = "flavored chocolate bar"
+ desc = "Made in a factory downtown."
+ icon_state = "bar"
+ size = 6
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/sucker
+ name = "flavored sucker"
+ desc = "Suck, suck, suck."
+ icon_state = "sucker"
+ size = 4
+ w_class = ITEM_SIZE_TINY
+
+/obj/item/chems/food/variable/jelly
+ name = "jelly"
+ desc = "All your friends will be jelly."
+ icon_state = "jellycustom"
+ size = 8
+
+/obj/item/chems/food/variable/cereal
+ name = "cereal"
+ desc = "Crispy and flaky"
+ icon_state = "cereal_box"
+ size = 30
+ w_class = ITEM_SIZE_NORMAL
+
+/obj/item/chems/food/variable/cereal/Initialize()
+ . =..()
+ name = pick(list("flakes", "krispies", "crunch", "pops", "O's", "crisp", "loops", "jacks", "clusters"))
+
+/obj/item/chems/food/variable/mob
+ desc = "Poor little thing."
+ size = 5
+ w_class = ITEM_SIZE_TINY
+ var/kitchen_tag = "animal"
diff --git a/code/game/machinery/kitchen/cooking_machines/candy.dm b/code/modules/food/machines/candy.dm
similarity index 73%
rename from code/game/machinery/kitchen/cooking_machines/candy.dm
rename to code/modules/food/machines/candy.dm
index dbfb577d743..b4ccb7387aa 100644
--- a/code/game/machinery/kitchen/cooking_machines/candy.dm
+++ b/code/modules/food/machines/candy.dm
@@ -1,10 +1,11 @@
-/obj/machinery/cooker/candy
+/obj/machinery/appliance/mixer/candy
name = "candy machine"
desc = "Get yer candied cheese wheels here!"
icon_state = "mixer_off"
off_icon = "mixer_off"
on_icon = "mixer_on"
cook_type = "candied"
+ cooking_coeff = 1.0
output_options = list(
"Jawbreaker" = /obj/item/chems/food/variable/jawbreaker,
@@ -13,6 +14,6 @@
"Jelly" = /obj/item/chems/food/variable/jelly
)
-/obj/machinery/cooker/candy/change_product_appearance(var/obj/item/chems/food/product)
+/obj/machinery/appliance/mixer/candy/change_product_appearance(var/obj/item/chems/food/product)
food_color = get_random_colour(1)
- . = ..()
+ . = ..()
\ No newline at end of file
diff --git a/code/modules/food/machines/cereal.dm b/code/modules/food/machines/cereal.dm
new file mode 100644
index 00000000000..0bfe38e0ee3
--- /dev/null
+++ b/code/modules/food/machines/cereal.dm
@@ -0,0 +1,61 @@
+/obj/machinery/appliance/mixer/cereal
+ name = "cereal maker"
+ desc = "Now with Dann O's available!"
+ icon = 'icons/obj/cooking_machines.dmi'
+ icon_state = "cereal_off"
+ cook_type = "cerealized"
+ on_icon = "cereal_on"
+ off_icon = "cereal_off"
+
+ output_options = list(
+ "Cereal" = /obj/item/chems/food/variable/cereal
+ )
+
+/*
+/obj/machinery/appliance/cereal/change_product_strings(var/obj/item/chems/food/product, var/datum/cooking_item/CI)
+ . = ..()
+ product.name = "box of [CI.object.name] cereal"
+
+/obj/machinery/appliance/cereal/change_product_appearance(var/obj/item/chems/food/product, var/datum/cooking_item/CI)
+ product.icon = 'icons/obj/food.dmi'
+ product.icon_state = "cereal_box"
+ product.filling_color = CI.object.color
+
+ var/image/food_image = image(CI.object.icon, CI.object.icon_state)
+ food_image.color = CI.object.color
+ food_image.overlays += CI.object.overlays
+ food_image.transform *= 0.7
+
+ product.overlays += food_image
+*/
+
+/obj/machinery/appliance/mixer/cereal/combination_cook(var/datum/cooking_item/CI)
+
+ var/list/images = list()
+ var/num = 0
+ for (var/obj/item/I in CI.container)
+ if (istype(I, /obj/item/chems/food/variable/cereal))
+ //Images of cereal boxes on cereal boxes is dumb
+ continue
+
+ var/image/food_image = image(I.icon, I.icon_state)
+ food_image.color = I.color
+ food_image.add_overlay(I.overlays)
+ food_image.transform *= 0.7 - (num * 0.05)
+ food_image.pixel_x = rand(-2,2)
+ food_image.pixel_y = rand(-3,5)
+
+
+ if (!images[I.icon_state])
+ images[I.icon_state] = food_image
+ num++
+
+ if (num > 3)
+ continue
+
+
+ var/obj/item/chems/food/result = ..()
+
+ result.color = result.filling_color
+ for (var/i in images)
+ result.overlays += images[i]
\ No newline at end of file
diff --git a/code/modules/food/machines/container.dm b/code/modules/food/machines/container.dm
new file mode 100644
index 00000000000..d2463e18362
--- /dev/null
+++ b/code/modules/food/machines/container.dm
@@ -0,0 +1,309 @@
+//Cooking containers are used in ovens and fryers, to hold multiple ingredients for a recipe.
+//They work fairly similar to the microwave - acting as a container for objects and reagents,
+//which can be checked against recipe requirements in order to cook recipes that require several things
+
+/obj/item/chems/cooking_container
+ icon = 'icons/obj/cooking_machines.dmi'
+ var/shortname
+ var/max_space = 20//Maximum sum of w-classes of foods in this container at once
+ volume = 80//Maximum units of reagents
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT
+ var/list/insertable = list(
+ /obj/item/chems/food,
+ /obj/item/holder,
+ /obj/item/paper,
+ /obj/item/flame/candle,
+ /obj/item/stack/material/rods,
+ /obj/item/organ/internal/brain
+ )
+ var/appliancetype // Bitfield, uses the same as appliances
+ w_class = ITEM_SIZE_NORMAL
+ material = /decl/material/solid/metal/stainlesssteel
+ applies_material_colour = FALSE
+ applies_material_name = TRUE
+ randpixel = FALSE
+
+/obj/item/chems/cooking_container/examine(var/mob/user)
+ . = ..()
+ if(length(contents))
+ to_chat(user, SPAN_NOTICE(get_content_info()))
+ if(reagents.total_volume)
+ to_chat(user, SPAN_NOTICE(get_reagent_info()))
+
+// So we can smack people with frying pans.
+/obj/item/chems/cooking_container/attack(var/mob/M, var/mob/user, var/def_zone)
+ if(can_operate(M) && do_surgery(M, user, src))
+ return
+ if(!reagents.total_volume && user.a_intent == I_HURT)
+ return ..()
+
+/obj/item/chems/cooking_container/afterattack(var/obj/target, var/mob/user, var/proximity)
+ if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) //Is the container open & are they next to whatever they're clicking?
+ return TRUE //If not, do nothing.
+ if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser?
+ return TRUE
+ if(istype(target, /obj/item/chems) && standard_pour_into(user, target)) //Pouring into another beaker?
+ return TRUE
+ if(standard_feed_mob(user, target))
+ return TRUE
+ if(user.a_intent == I_HURT)
+ if(standard_splash_mob(user,target))
+ return TRUE
+ if(reagents?.total_volume)
+ to_chat(user, SPAN_NOTICE("You splash the contents of \the [src] onto [target].")) //They are on harm intent, aka wanting to spill it.
+ reagents.splash(target, reagents.total_volume)
+ return TRUE
+ . = ..()
+
+/obj/item/chems/cooking_container/proc/get_content_info()
+ var/string = "It contains:"
+ var/list/numerical_contents = list()
+ for(var/atom/thing as anything in get_contained_external_atoms())
+ numerical_contents[thing] += 1
+ for(var/atom/key as anything in numerical_contents)
+ string += "- [(numerical_contents[key] > 1) ? "[numerical_contents[key]]x [key.name]" : "\a [key]"]
"
+ string += "
"
+ return string
+
+/obj/item/chems/cooking_container/proc/get_reagent_info()
+ return "It contains [reagents.total_volume] units of reagents."
+
+/obj/item/chems/cooking_container/MouseEntered(location, control, params)
+ . = ..()
+ var/list/modifiers = params2list(params)
+ if(modifiers["shift"] && get_dist(usr, src) <= 2)
+ params = replacetext(params, "shift=1;", "") // tooltip doesn't appear unless this is stripped
+ var/description
+ if(length(contents))
+ description = get_content_info()
+ if(reagents.total_volume)
+ if(!description)
+ description = ""
+ description += get_reagent_info()
+ openToolTip(usr, src, params, name, description)
+
+/obj/item/chems/cooking_container/MouseExited(location, control, params)
+ . = ..()
+ closeToolTip(usr)
+
+/obj/item/chems/cooking_container/attackby(var/obj/item/I, var/mob/user)
+ if(is_type_in_list(I, insertable))
+ if (!can_fit(I))
+ to_chat(user, SPAN_WARNING("There's no more space in [src] for that!"))
+ return FALSE
+
+ if(!user.unEquip(I))
+ return
+ I.forceMove(src)
+ to_chat(user, SPAN_NOTICE("You put [I] into [src]."))
+ return
+ return ..()
+
+/obj/item/chems/cooking_container/verb/empty()
+ set name = "Empty Container"
+ set category = "Object"
+ set desc = "Removes items from the container, excluding reagents."
+ set src in view(1)
+
+ do_empty(usr)
+
+/obj/item/chems/cooking_container/proc/do_empty(mob/user)
+ if (!isliving(user))
+ //Here we only check for ghosts. Animals are intentionally allowed to remove things from oven trays so they can eat it
+ return
+
+ if (user.stat || user.restrained() || user.incapacitated())
+ to_chat(user, "You are in no fit state to do this.")
+ return
+
+ if (!Adjacent(user))
+ to_chat(user, "You can't reach [src] from here.")
+ return
+
+ if (!length(contents))
+ to_chat(user, SPAN_WARNING("There's nothing in [src] you can remove!"))
+ return
+
+ for (var/contained in contents)
+ var/atom/movable/AM = contained
+ AM.forceMove(get_turf(src))
+
+ to_chat(user, SPAN_NOTICE("You remove all the solid items from [src]."))
+
+/obj/item/chems/cooking_container/proc/check_contents()
+ if (!length(contents))
+ if (!reagents?.total_volume)
+ return CONTAINER_EMPTY
+ else if (length(contents) == 1)
+ if (!reagents?.total_volume)
+ return CONTAINER_SINGLE
+ return CONTAINER_MANY
+
+/obj/item/chems/cooking_container/AltClick(var/mob/user)
+ do_empty(user)
+
+//Deletes contents of container.
+//Used when food is burned, before replacing it with a burned mess
+/obj/item/chems/cooking_container/proc/clear()
+ QDEL_NULL_LIST(contents)
+ reagents.clear_reagents()
+
+/obj/item/chems/cooking_container/proc/label(var/number, var/CT = null)
+ //This returns something like "Fryer basket 1 - empty"
+ //The latter part is a brief reminder of contents
+ //This is used in the removal menu
+ . = shortname
+ if (!isnull(number))
+ .+= " [number]"
+ .+= " - "
+ if (CT)
+ return . + CT
+ else if (LAZYLEN(contents))
+ var/obj/O = locate() in contents
+ return . + O.name //Just append the name of the first object
+ else if (reagents.total_volume > 0)
+ var/decl/material/M = reagents.get_primary_reagent_decl()
+ return . + M.name//Append name of most voluminous reagent
+ return . + "empty"
+
+
+/obj/item/chems/cooking_container/proc/can_fit(var/obj/item/I)
+ var/total = 0
+ for (var/contained in contents)
+ var/obj/item/J = contained
+ total += J.w_class
+
+ if((max_space - total) >= I.w_class)
+ return TRUE
+
+
+//Takes a reagent holder as input and distributes its contents among the items in the container
+//Distribution is weighted based on the volume already present in each item
+/obj/item/chems/cooking_container/proc/soak_reagent(var/datum/reagents/holder)
+ var/total = 0
+ var/list/weights = list()
+ for (var/contained in contents)
+ var/obj/item/I = contained
+ if (I.reagents?.total_volume)
+ total += I.reagents.total_volume
+ weights[I] = I.reagents.total_volume
+
+ if (total > 0)
+ for (var/contained in contents)
+ var/obj/item/I = contained
+ if (weights[I])
+ holder.trans_to_obj(I, weights[I] / total)
+
+
+/obj/item/chems/cooking_container/oven
+ name = "oven dish"
+ shortname = "shelf"
+ desc = "Put ingredients in this; designed for use with an oven. Warranty void if used."
+ icon_state = "ovendish"
+ max_space = 30
+ volume = 120
+ appliancetype = APPLIANCE_OVEN
+ material = /decl/material/solid/stone/ceramic
+
+/obj/item/chems/cooking_container/skillet
+ name = "skillet"
+ shortname = "skillet"
+ desc = "Chuck ingredients in this to fry something on the stove."
+ icon_state = "skillet"
+ volume = 30
+ hitsound = 'sound/weapons/smash.ogg'
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER // Will still react
+ appliancetype = APPLIANCE_SKILLET
+
+/obj/item/chems/cooking_container/saucepan
+ name = "saucepan"
+ shortname = "saucepan"
+ desc = "Is it a pot? Is it a pan? It's a saucepan!"
+ icon_state = "pan"
+ volume = 90
+ slot_flags = SLOT_HEAD
+ hitsound = 'sound/weapons/smash.ogg'
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER // Will still react
+ appliancetype = APPLIANCE_SAUCEPAN
+
+/obj/item/chems/cooking_container/pot
+ name = "cooking pot"
+ shortname = "pot"
+ desc = "Boil things with this. Maybe even stick 'em in a stew."
+ icon_state = "pot"
+ max_space = 50
+ volume = 180
+ hitsound = 'sound/weapons/smash.ogg'
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER // Will still react
+ appliancetype = APPLIANCE_POT
+ w_class = ITEM_SIZE_LARGE
+
+/obj/item/chems/cooking_container/fryer
+ name = "fryer basket"
+ shortname = "basket"
+ desc = "Put ingredients in this; designed for use with a deep fryer. Warranty void if used."
+ icon_state = "basket"
+ appliancetype = APPLIANCE_FRYER
+
+/obj/item/chems/cooking_container/grill_grate/can_fit()
+ if(length(contents) >= 3)
+ return FALSE
+ return TRUE
+
+/obj/item/chems/cooking_container/plate
+ name = "serving plate"
+ shortname = "plate"
+ desc = "A plate. You plate foods on this plate."
+ icon_state = "plate"
+ appliancetype = APPLIANCE_MIX
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER // Will still react
+ volume = 15 // for things like jelly sandwiches etc
+ max_space = 25
+ material = /decl/material/solid/stone/ceramic
+
+/obj/item/chems/cooking_container/plate/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/kitchen/utensil))
+ if(do_mix())
+ user.visible_message("\The [user] stirs \the [src] with \the [I].", SPAN_NOTICE("You stir \the [src] with \the [I]."))
+ return
+ return ..()
+
+/obj/item/chems/cooking_container/plate/proc/do_mix()
+ if(!(length(contents) || reagents?.total_volume))
+ return FALSE
+ var/decl/recipe/recipe = select_recipe(src, appliance = appliancetype)
+ if(!recipe)
+ return FALSE
+ var/list/results = recipe.make_food(src)
+ var/obj/temp = new /obj(src) //To prevent infinite loops, all results will be moved into a temporary location so they're not considered as inputs for other recipes
+ for (var/result in results)
+ var/atom/movable/AM = result
+ AM.forceMove(temp)
+
+ //making multiple copies of a recipe from one container. For example, tons of fries
+ while (select_recipe(src, appliance = appliancetype) == recipe)
+ var/list/TR = list()
+ TR += recipe.make_food(src)
+ for (var/result in TR) //Move results to buffer
+ var/atom/movable/AM = result
+ AM.forceMove(temp)
+ results += TR
+
+ for (var/r in results)
+ var/obj/item/chems/food/R = r
+ R.forceMove(src) //Move everything from the buffer back to the container
+
+ QDEL_NULL(temp) //delete buffer object
+ return TRUE
+
+/obj/item/chems/cooking_container/plate/bowl
+ name = "serving bowl"
+ shortname = "bowl"
+ desc = "A bowl. You bowl foods... wait, what?"
+ icon_state = "mixingbowl"
+ center_of_mass = @"{'x':17,'y':7}"
+ max_space = 30
+ matter = list(/decl/material/solid/metal/aluminium = 300)
+ volume = 90
+ amount_per_transfer_from_this = 10
+ possible_transfer_amounts = @"[5,10,15,25,30,60, 90]"
\ No newline at end of file
diff --git a/code/modules/food/machines/fryer.dm b/code/modules/food/machines/fryer.dm
new file mode 100644
index 00000000000..384bd36a0a5
--- /dev/null
+++ b/code/modules/food/machines/fryer.dm
@@ -0,0 +1,191 @@
+/obj/machinery/appliance/cooker/fryer
+ name = "deep fryer"
+ desc = "Deep fried everything."
+ icon_state = "fryer_off"
+ can_cook_mobs = 1
+ cook_type = "deep fried"
+ on_icon = "fryer_on"
+ off_icon = "fryer_off"
+ food_color = "#ffad33"
+ appliancetype = APPLIANCE_FRYER
+ active_power_usage = 12 KILOWATTS
+ heating_power = 12000
+ optimal_power = 0.8
+ idle_power_usage = 3.6 KILOWATTS
+ //Power used to maintain temperature once it's heated.
+ //Going with 25% of the active power. This is a somewhat arbitrary value
+ resistance = 10000 // Approx. 4 minutes.
+ max_contents = 2
+ stat = NOPOWER//Starts turned off
+ starts_with = list(
+ /obj/item/chems/cooking_container/fryer,
+ /obj/item/chems/cooking_container/fryer
+ )
+ atom_flags = ATOM_FLAG_OPEN_CONTAINER
+
+ var/optimal_oil = 9000//90 litres of cooking oil
+ var/datum/composite_sound/deep_fryer/fry_loop
+
+/obj/machinery/appliance/cooker/fryer/examine(var/mob/user)
+ . = ..()
+ if (.)//no need to duplicate adjacency check
+ to_chat(user, "Oil Level: [reagents.total_volume]/[optimal_oil]")
+
+/obj/machinery/appliance/cooker/fryer/Initialize()
+ . = ..()
+ create_reagents(optimal_oil * 1.25)
+ var/variance = rand()*0.15
+ //Fryer is always a little below full, but its usually negligible
+
+ if (prob(20))
+ //Sometimes the fryer will start with much less than full oil, significantly impacting efficiency until filled
+ variance = rand()*0.5
+ reagents.add_reagent(/decl/material/liquid/nutriment/triglyceride/oil/corn, optimal_oil*(1 - variance))
+ fry_loop = new(list(src), FALSE)
+
+/obj/machinery/appliance/cooker/fryer/update_cooking_power()
+ ..()//In addition to parent temperature calculation
+ //Fryer efficiency also drops when oil levels arent optimal
+ var/oil_level = 0
+ if (ispath(reagents.primary_reagent, /decl/material/liquid/nutriment/triglyceride/oil))
+ oil_level = reagents.reagent_volumes[reagents.primary_reagent]
+
+ var/oil_efficiency = 0
+ if (oil_level)
+ oil_efficiency = oil_level / optimal_oil
+
+ if (oil_efficiency > 1)
+ //We're above optimal, efficiency goes down as we pass too much over it
+ oil_efficiency = 1 - (oil_efficiency - 1)
+
+ cooking_power *= oil_efficiency
+
+/obj/machinery/appliance/cooker/fryer/on_update_icon()
+ ..()
+ if (cooking)
+ icon_state = on_icon
+ fry_loop.start(src)
+ else
+ icon_state = off_icon
+ fry_loop.stop(src)
+
+//Fryer gradually infuses any cooked food with oil. Moar calories
+//This causes a slow drop in oil levels, encouraging refill after extended use
+/obj/machinery/appliance/cooker/fryer/do_cooking_tick(var/datum/cooking_item/CI)
+ if(..() && (CI.oil < CI.max_oil) && prob(20))
+ var/datum/reagents/buffer = new /datum/reagents(2, global.temp_reagents_holder)
+ reagents.trans_to_holder(buffer, min(0.5, CI.max_oil - CI.oil))
+ CI.oil += buffer.total_volume
+ CI.container.soak_reagent(buffer)
+
+//To solve any odd logic problems with results having oil as part of their compiletime ingredients.
+//Upon finishing a recipe the fryer will analyse any oils in the result, and replace them with our oil
+//As well as capping the total to the max oil
+/obj/machinery/appliance/cooker/fryer/finish_cooking(var/datum/cooking_item/CI)
+ . = ..()
+ var/total_oil = 0
+ var/total_our_oil = 0
+ var/total_removed = 0
+ var/decl/material/our_oil = reagents.get_primary_reagent_decl()
+
+ for (var/obj/item/I in CI.container)
+ if (I.reagents?.total_volume)
+ for (var/_R in I.reagents.reagent_volumes)
+ if (ispath(_R, /decl/material/liquid/nutriment/triglyceride/oil))
+ total_oil += I.reagents.reagent_volumes[_R]
+ if (_R != our_oil.type)
+ total_removed += I.reagents.reagent_volumes[_R]
+ I.reagents.remove_reagent(_R, I.reagents.reagent_volumes[_R])
+ else
+ total_our_oil += I.reagents.reagent_volumes[_R]
+
+ if (total_removed > 0 || total_oil != CI.max_oil)
+ total_oil = min(total_oil, CI.max_oil)
+
+ if (total_our_oil < total_oil)
+ //If we have less than the combined total, then top up from our reservoir
+ var/datum/reagents/buffer = new /datum/reagents(INFINITY, global.temp_reagents_holder)
+ reagents.trans_to_holder(buffer, total_oil - total_our_oil)
+ CI.container.soak_reagent(buffer)
+ else if (total_our_oil > total_oil)
+ //If we have more than the maximum allowed then we delete some.
+ //This could only happen if one of the objects spawns with the same type of oil as ours
+ var/portion = 1 - (total_oil / total_our_oil) //find the percentage to remove
+ for (var/thing in CI.container)
+ var/obj/item/I = thing
+ if (I.reagents?.total_volume)
+ for (var/_R in I.reagents.reagent_volumes)
+ if (_R == our_oil.type)
+ I.reagents.remove_reagent(_R, I.reagents.reagent_volumes[_R]*portion)
+
+/obj/machinery/appliance/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user)
+
+ if(!istype(victim))
+ return
+
+ //Removed delay on this action in favour of a cooldown after it
+ //If you can lure someone close to the fryer and grab them then you deserve success.
+ //And a delay on this kind of niche action just ensures it never happens
+ //Cooldown ensures it can't be spammed to instakill someone
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN*3)
+
+ if(!victim || !victim.Adjacent(user))
+ to_chat(user, SPAN_DANGER("Your victim slipped free!"))
+ return
+
+ var/damage = rand(7,13)
+ //Though this damage seems reduced, some hot oil is transferred to the victim and will burn them for a while after
+
+ var/decl/material/liquid/nutriment/triglyceride/oil/OL = reagents.get_primary_reagent_decl()
+ if(istype(OL))
+ damage *= OL.heatdamage(victim, reagents)
+
+ var/obj/item/organ/external/E
+ var/nopain
+ if(ishuman(victim) && user.zone_sel.selecting != BP_GROIN && user.zone_sel.selecting != BP_CHEST)
+ var/mob/living/carbon/human/H = victim
+ E = H.get_organ(user.zone_sel.selecting)
+ if(!E || !H.can_feel_pain())
+ nopain = 2
+ else if(BP_IS_PROSTHETIC(E))
+ nopain = 1
+
+ var/part = E ? "'s [E.name]" : ""
+ user.visible_message(SPAN_DANGER("[user] shoves [victim][part] into [src]!"))
+ if (damage > 0)
+ if(E)
+
+ if(LAZYLEN(E.children))
+ for(var/C in E.children)
+ var/obj/item/organ/external/child = C
+ if(nopain && nopain < 2 && !BP_IS_PROSTHETIC(child))
+ nopain = 0
+ child.take_external_damage(0, damage, used_weapon = "hot oil")
+ damage -= (damage*0.5)//IF someone's arm is plunged in, the hand should take most of it
+
+ E.take_external_damage(0, damage, used_weapon = "hot oil")
+ else
+ victim.apply_damage(damage, BURN, user.zone_sel.selecting)
+
+ if(!nopain)
+ var/arrows_var1 = E ? E.name : "flesh"
+ to_chat(victim, SPAN_DANGER("Agony consumes you as searing hot oil scorches your [arrows_var1] horribly!"))
+ victim.emote("scream")
+ else
+ var/arrows_var2 = E ? E.name : "flesh"
+ to_chat(victim, SPAN_DANGER("Searing hot oil scorches your [arrows_var2]!"))
+
+ admin_attack_log(user, victim, "[cook_type]", "Was [cook_type]", cook_type)
+
+ //Coat the victim in some oil
+ reagents.trans_to(victim, 40)
+
+/obj/machinery/appliance/cooker/fryer/attackby(var/obj/item/I, var/mob/user)
+ if(istype(I, /obj/item/chems/glass) && I.reagents)
+ if (I.reagents.total_volume <= 0 && reagents)
+ //Its empty, handle scooping some hot oil out of the fryer
+ reagents.trans_to_obj(I, I.reagents.maximum_volume)
+ user.visible_message("[user] scoops some oil out of [src].", SPAN_NOTICE("You scoop some oil out of [src]."))
+ return TRUE
+ //If the above hasn't returned, then call parent as normal
+ ..()
\ No newline at end of file
diff --git a/code/modules/food/machines/mixer.dm b/code/modules/food/machines/mixer.dm
new file mode 100644
index 00000000000..904f63a94e7
--- /dev/null
+++ b/code/modules/food/machines/mixer.dm
@@ -0,0 +1,120 @@
+/*
+The mixer subtype is used for the candymaker and cereal maker. They are similar to cookers but with a few
+fundamental differences
+
+
+1. They have a single container which cant be removed. it will eject multiple contents
+2. Items can't be added or removed once the process starts
+3. Items are all placed in the same container when added directly
+4. They do combining mode only. And will always combine the entire contents of the container into an output
+*/
+
+/obj/machinery/appliance/mixer
+ max_contents = 1
+ use_power = POWER_USE_OFF
+ cooking_coeff = 0.75
+ active_power_usage = 3000
+ idle_power_usage = 50
+ appliancetype = 0
+
+/obj/machinery/appliance/mixer/examine(var/mob/user)
+ . = ..()
+ to_chat(user, SPAN_NOTICE("It is currently set to make a [selected_option]"))
+
+/obj/machinery/appliance/mixer/Initialize()
+ . = ..()
+ cooking_objs += new /datum/cooking_item(new /obj/item/chems/cooking_container(src))
+ cooking = 0
+ selected_option = pick(output_options)
+ update_cooking_power()
+
+//Mixers cannot-not do combining mode. So the default option is removed from this. A combine target must be chosen
+/obj/machinery/appliance/mixer/choose_output()
+ set src in oview(1)
+ set name = "Choose output"
+ set category = "Object"
+
+ if (!CanPhysicallyInteract(usr))
+ return
+
+ if (!usr.check_dexterity(DEXTERITY_SIMPLE_MACHINES))
+ return
+
+ if(!length(output_options))
+ return
+ var/choice = input("What specific food do you wish to make with [src]?") as null|anything in output_options
+ if(!choice)
+ return
+ selected_option = choice
+ to_chat(usr, SPAN_NOTICE("You set [src] to make \a [selected_option]."))
+ var/datum/cooking_item/CI = cooking_objs[1]
+ CI.combine_target = selected_option
+
+
+/obj/machinery/appliance/mixer/has_space(var/obj/item/I)
+ var/datum/cooking_item/CI = cooking_objs[1]
+ if (!CI || !CI.container)
+ return FALSE
+
+ if (CI.container.can_fit(I))
+ return CI
+
+ return FALSE
+
+
+/obj/machinery/appliance/mixer/can_remove_items(var/mob/user)
+ if (use_power == POWER_USE_OFF)
+ return ..()
+ to_chat(user, SPAN_WARNING("You can't remove ingredients while [src] is turned on! Turn it off first or wait for it to finish."))
+ return FALSE
+
+//Container is not removable
+/obj/machinery/appliance/mixer/removal_menu(var/mob/user)
+ if (!can_remove_items(user))
+ return FALSE
+ var/list/menuoptions = list()
+ for (var/cooking_obj in cooking_objs)
+ var/datum/cooking_item/CI = cooking_obj
+ if (CI.container?.check_contents() == CONTAINER_EMPTY)
+ to_chat(user, "There's nothing in [src] to remove!")
+ return
+ for (var/thing in CI.container)
+ var/obj/item/I = thing
+ menuoptions[I.name] = I
+
+ var/selection = show_radial_menu(user, src, menuoptions, require_near = TRUE, tooltips = TRUE, no_repeat_close = TRUE)
+ if (!selection)
+ return FALSE
+ var/obj/item/I = menuoptions[selection]
+ if (!user?.put_in_hands(I))
+ I.forceMove(get_turf(src))
+ update_icon()
+ return TRUE
+
+/obj/machinery/appliance/mixer/attempt_toggle_power(var/mob/user, ranged = FALSE)
+ . = ..(user, ranged)
+ if(!use_power)
+ return
+ for(var/i in cooking_objs)
+ var/datum/cooking_item/CI = i
+ CI.combine_target = selected_option
+ get_cooking_work(cooking_objs[1])
+
+/obj/machinery/appliance/mixer/can_insert(var/obj/item/I, var/mob/user)
+ if (use_power != POWER_USE_OFF)
+ to_chat(user, SPAN_WARNING("You can't add items while [src] is running. Wait for it to finish or turn the power off to cancel operation."))
+ return FALSE
+ return ..()
+
+/obj/machinery/appliance/mixer/finish_cooking(var/datum/cooking_item/CI)
+ ..()
+ playsound(src, 'sound/machines/click.ogg', 40, 1)
+ update_use_power(POWER_USE_OFF)
+ CI.reset()
+ update_icon()
+
+/obj/machinery/appliance/mixer/Process()
+ if (use_power == POWER_USE_OFF)
+ return
+ for (var/i in cooking_objs)
+ do_cooking_tick(i)
\ No newline at end of file
diff --git a/code/modules/food/machines/oven.dm b/code/modules/food/machines/oven.dm
new file mode 100644
index 00000000000..521fd885372
--- /dev/null
+++ b/code/modules/food/machines/oven.dm
@@ -0,0 +1,111 @@
+/obj/machinery/appliance/cooker/oven
+ name = "oven"
+ desc = "Cookies are ready, dear."
+ icon_state = "ovenopen"
+ cook_type = "baked"
+ appliancetype = APPLIANCE_OVEN
+ food_color = "#a34719"
+ can_burn_food = TRUE
+ active_power_usage = 6 KILOWATTS
+ heating_power = 6000
+ //Based on a double deck electric convection oven
+ resistance = 10000 // Approx. 4 minutes.
+ idle_power_usage = 2 KILOWATTS
+ //uses ~30% power to stay warm
+ optimal_power = 1.0
+ light_x = 2
+ max_contents = 5
+ use_power = POWER_USE_OFF //Starts turned off
+ pass_flags = 0
+ var/open = FALSE // Start closed so people don't heat up ovens with the door open
+
+ starts_with = list(
+ /obj/item/chems/cooking_container/oven,
+ /obj/item/chems/cooking_container/oven,
+ /obj/item/chems/cooking_container/oven,
+ /obj/item/chems/cooking_container/oven,
+ /obj/item/chems/cooking_container/oven
+ )
+
+ output_options = list(
+ "Pizza" = /obj/item/chems/food/variable/pizza,
+ "Bread" = /obj/item/chems/food/variable/bread,
+ "Pie" = /obj/item/chems/food/variable/pie,
+ "Cake" = /obj/item/chems/food/variable/cake,
+ "Hot Pocket" = /obj/item/chems/food/variable/pocket,
+ "Kebab" = /obj/item/chems/food/variable/kebab,
+ "Waffles" = /obj/item/chems/food/variable/waffles,
+ "Cookie" = /obj/item/chems/food/variable/cookie,
+ "Donut" = /obj/item/chems/food/variable/donut
+ )
+
+
+/obj/machinery/appliance/cooker/oven/get_mechanics_info()
+ return ..() + "Alt-click this to open/close the door."
+
+/obj/machinery/appliance/cooker/oven/on_update_icon()
+ ..()
+ if (!open)
+ if (use_power == POWER_USE_OFF)
+ icon_state = "ovenclosed_off"
+ else
+ icon_state = "ovenclosed_on"
+ else
+ icon_state = "ovenopen"
+
+/obj/machinery/appliance/cooker/oven/AltClick(var/mob/user)
+ try_toggle_door(user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+
+/obj/machinery/appliance/cooker/oven/verb/toggle_door()
+ set src in oview(1)
+ set category = "Object"
+ set name = "Open/close oven door"
+
+ try_toggle_door(usr)
+
+/obj/machinery/appliance/cooker/oven/proc/try_toggle_door(mob/user)
+ if (!isliving(user) || isAI(user))
+ return
+
+ if (!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES))
+ return
+
+ if (!Adjacent(user))
+ to_chat(user, "You can't reach the [src] from there, get closer!")
+ return
+
+ if (open)
+ open = FALSE
+ temperature_coefficient = 1
+ else
+ open = TRUE
+ temperature_coefficient = 10
+ //When the oven door is opened, oven loses heat faster
+
+ playsound(src, 'sound/machines/hatch_open.ogg', 20, 1)
+ update_icon()
+
+/obj/machinery/appliance/cooker/oven/can_insert(var/obj/item/I, var/mob/user)
+ if (!open)
+ to_chat(user, SPAN_WARNING("You can't put anything in while the door is closed!"))
+ return FALSE
+
+ else
+ return ..()
+
+/obj/machinery/appliance/cooker/oven/can_remove_items(var/mob/user)
+ if (!open)
+ to_chat(user, SPAN_WARNING("You can't take anything out while the door is closed!"))
+ return FALSE
+ return ..()
+
+
+//Oven has lots of recipes and combine options. The chance for interference is high, so
+//If a combine target is set the oven will do it instead of checking recipes
+/obj/machinery/appliance/cooker/oven/finish_cooking(var/datum/cooking_item/CI)
+ if(CI.combine_target)
+ visible_message("[src] pings!")
+ combination_cook(CI)
+ return
+ ..()
\ No newline at end of file
diff --git a/code/modules/food/machines/stove.dm b/code/modules/food/machines/stove.dm
new file mode 100644
index 00000000000..26e766dfc8d
--- /dev/null
+++ b/code/modules/food/machines/stove.dm
@@ -0,0 +1,49 @@
+/obj/machinery/appliance/cooker/stove
+ name = "stove"
+ desc = "Don't touch it!"
+ icon_state = "stove_off"
+ pass_flags = PASS_FLAG_TABLE
+ cook_type = "pan-fried"
+ appliancetype = APPLIANCE_SKILLET | APPLIANCE_SAUCEPAN | APPLIANCE_POT
+ food_color = "#a34719"
+ can_burn_food = TRUE
+ active_power_usage = 6 KILOWATTS
+ heating_power = 6000
+ on_icon = "stove_on"
+ off_icon = "stove_off"
+
+ resistance = 5000 // Approx. 2 minutes.
+ idle_power_usage = 1 KILOWATTS
+ //uses ~30% power to stay warm
+ optimal_temp = T0C + 100 // can boil water!
+ optimal_power = 1.2
+
+ max_contents = 4
+
+ use_power = POWER_USE_OFF //Starts turned off
+
+ starts_with = list(
+ /obj/item/chems/cooking_container/skillet,
+ /obj/item/chems/cooking_container/pot,
+ /obj/item/chems/cooking_container/saucepan
+ )
+
+/obj/machinery/appliance/cooker/stove/on_update_icon()
+ . = ..()
+ var/list/pans = list()
+ for(var/obj/item/chems/cooking_container/CC in contents)
+ var/image/pan_overlay
+ switch(CC.appliancetype)
+ if(APPLIANCE_SKILLET)
+ pan_overlay = image('icons/obj/cooking_machines.dmi', "skillet[Clamp(length(pans)+1, 1, 4)]")
+ if(APPLIANCE_SAUCEPAN)
+ pan_overlay = image('icons/obj/cooking_machines.dmi', "pan[Clamp(length(pans)+1, 1, 4)]")
+ if(APPLIANCE_POT)
+ pan_overlay = image('icons/obj/cooking_machines.dmi', "pot[Clamp(length(pans)+1, 1, 4)]")
+ else
+ continue
+ pan_overlay.color = CC.color
+ pans += pan_overlay
+ if(!length(pans))
+ return
+ add_overlay(pans)
\ No newline at end of file
diff --git a/code/modules/food/recipes/recipes_fryer.dm b/code/modules/food/recipes/recipes_fryer.dm
new file mode 100644
index 00000000000..8658b55c8a4
--- /dev/null
+++ b/code/modules/food/recipes/recipes_fryer.dm
@@ -0,0 +1,75 @@
+/decl/recipe/cubancarp
+ appliance = APPLIANCE_FRYER
+ fruit = list("chili" = 1)
+ coating = /decl/material/liquid/nutriment/batter
+ items = list(
+ /obj/item/chems/food/fish
+ )
+ result = /obj/item/chems/food/cubancarp
+
+/decl/recipe/fishandchips
+ appliance = APPLIANCE_FRYER
+ items = list(
+ /obj/item/chems/food/fries,
+ /obj/item/chems/food/fish
+ )
+ reagent_mix = REAGENT_REPLACE // we don't want the fries to show up twice
+ result = /obj/item/chems/food/fishandchips
+
+/decl/recipe/katsucurry
+ appliance = APPLIANCE_FRYER
+ fruit = list("apple" = 1, "carrot" = 1, "potato" = 1)
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/rice = 10, /decl/material/liquid/nutriment/flour = 5)
+ items = list(
+ /obj/item/chems/food/meat/chicken
+ )
+ reagent_mix = REAGENT_REPLACE // get the raw reagents out of there
+ result = /obj/item/chems/food/katsucurry
+
+/decl/recipe/fishfingers
+ appliance = APPLIANCE_FRYER
+ items = list(
+ /obj/item/chems/food/fish
+ )
+ coating = /decl/material/liquid/nutriment/batter
+ result = /obj/item/chems/food/fishfingers
+
+/decl/recipe/fries
+ appliance = APPLIANCE_FRYER
+ items = list(
+ /obj/item/chems/food/rawsticks
+ )
+ reagent_mix = REAGENT_REPLACE // get the raw potato out of there
+ result = /obj/item/chems/food/fries
+
+/decl/recipe/onionrings
+ appliance = APPLIANCE_FRYER
+ fruit = list("onion" = 1)
+ coating = /decl/material/liquid/nutriment/batter
+ reagents = list(/decl/material/liquid/nutriment/batter = 10)
+ result = /obj/item/chems/food/onionrings
+
+/decl/recipe/jellydonut
+ appliance = APPLIANCE_FRYER
+ reagents = list(/decl/material/liquid/drink/juice/berry = 5, /decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/dough
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/donut/jelly
+
+/decl/recipe/jellydonut/cherry
+ reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5, /decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/dough
+ )
+ result = /obj/item/chems/food/donut/cherryjelly
+
+/decl/recipe/donut
+ appliance = APPLIANCE_FRYER
+ reagents = list(/decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/dough
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/donut/normal
\ No newline at end of file
diff --git a/code/modules/food/recipes/recipes_microwave.dm b/code/modules/food/recipes/recipes_microwave.dm
new file mode 100644
index 00000000000..73369eae397
--- /dev/null
+++ b/code/modules/food/recipes/recipes_microwave.dm
@@ -0,0 +1,93 @@
+/decl/recipe/loadedbakedpotato
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_OVEN
+ fruit = list("potato" = 1)
+ items = list(/obj/item/chems/food/cheesewedge)
+ result = /obj/item/chems/food/loadedbakedpotato
+
+/decl/recipe/cheesyfries
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SKILLET
+ items = list(
+ /obj/item/chems/food/fries,
+ /obj/item/chems/food/cheesewedge,
+ )
+ result = /obj/item/chems/food/cheesyfries
+
+/decl/recipe/popcorn
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/solid/sodiumchloride = 5)
+ fruit = list("corn" = 1)
+ result = /obj/item/chems/food/popcorn
+
+/decl/recipe/plainsteak
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SKILLET
+ items = list(/obj/item/chems/food/meat)
+ result = /obj/item/chems/food/plainsteak
+
+/decl/recipe/meatsteak
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SKILLET
+ reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
+ items = list(/obj/item/chems/food/cutlet)
+ result = /obj/item/chems/food/meatsteak
+
+/decl/recipe/loadedsteak
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SKILLET
+ reagents = list(/decl/material/liquid/nutriment/garlicsauce = 5)
+ fruit = list("onion" = 1, "mushroom" = 1)
+ items = list(/obj/item/chems/food/cutlet)
+ result = /obj/item/chems/food/loadedsteak
+
+/decl/recipe/syntisteak
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SKILLET
+ reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
+ items = list(/obj/item/chems/food/meat/syntiflesh)
+ result = /obj/item/chems/food/meatsteak/synthetic
+
+/decl/recipe/rofflewaffles
+ appliance = APPLIANCE_MICROWAVE
+ reagents = list(/decl/material/liquid/psychotropics = 5, /decl/material/liquid/nutriment/batter/cakebatter = 20)
+ reagent_mix = REAGENT_REPLACE // no raw batter
+ result = /obj/item/chems/food/rofflewaffles
+
+/decl/recipe/boiledrice
+ appliance = APPLIANCE_MICROWAVE | APPLIANCE_SAUCEPAN | APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/rice = 10)
+ reagent_mix = REAGENT_REPLACE // remove the water
+ result = /obj/item/chems/food/boiledrice
+
+/decl/recipe/pastatomato
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("tomato" = 2)
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(/obj/item/chems/food/spagetti)
+ reagent_mix = REAGENT_REPLACE // get that water outta here
+ result = /obj/item/chems/food/pastatomato
+
+/decl/recipe/meatballspagetti
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/spagetti,
+ /obj/item/chems/food/meatball = 2,
+ )
+ reagent_mix = REAGENT_REPLACE // get that water outta here
+ result = /obj/item/chems/food/meatballspagetti
+
+/decl/recipe/spesslaw
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/spagetti,
+ /obj/item/chems/food/meatball = 4,
+ )
+ reagent_mix = REAGENT_REPLACE // get that water outta here
+ result = /obj/item/chems/food/spesslaw
+
+/decl/recipe/nanopasta
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/spagetti,
+ /obj/item/stack/nanopaste
+ )
+ reagent_mix = REAGENT_REPLACE // get that water outta here
+ result = /obj/item/chems/food/nanopasta
\ No newline at end of file
diff --git a/code/modules/food/recipes/recipes_mix.dm b/code/modules/food/recipes/recipes_mix.dm
new file mode 100644
index 00000000000..51658136efb
--- /dev/null
+++ b/code/modules/food/recipes/recipes_mix.dm
@@ -0,0 +1,222 @@
+/decl/recipe/superbiteburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ fruit = list("tomato" = 1)
+ reagents = list(/decl/material/solid/sodiumchloride = 5, /decl/material/solid/blackpepper = 5)
+ items = list(
+ /obj/item/chems/food/bigbiteburger,
+ /obj/item/chems/food/dough,
+ /obj/item/chems/food/meat,
+ /obj/item/chems/food/cheesewedge,
+ /obj/item/chems/food/boiledegg,
+ )
+ // use the default reagent mixing, since it should taste disgusting
+ result = /obj/item/chems/food/superbiteburger
+
+/decl/recipe/jellyburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
+ items = list(
+ /obj/item/chems/food/bun
+ )
+ result = /obj/item/chems/food/jellyburger/cherry
+
+/decl/recipe/twobread
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE // it's tradition, see
+ reagents = list(/decl/material/liquid/ethanol/wine = 5)
+ items = list(
+ /obj/item/chems/food/slice/bread = 2,
+ )
+ result = /obj/item/chems/food/twobread
+
+/decl/recipe/threebread
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/twobread,
+ /obj/item/chems/food/slice/bread,
+ )
+ result = /obj/item/chems/food/threebread
+
+/decl/recipe/cherrysandwich
+ appliance = APPLIANCE_MIX
+ reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
+ items = list(
+ /obj/item/chems/food/slice/bread = 2,
+ )
+ result = /obj/item/chems/food/jellysandwich/cherry
+
+/decl/recipe/tossedsalad
+ appliance = APPLIANCE_MIX
+ fruit = list("cabbage" = 2, "tomato" = 1, "carrot" = 1, "apple" = 1)
+ result = /obj/item/chems/food/tossedsalad
+
+/decl/recipe/aesirsalad
+ appliance = APPLIANCE_MIX
+ fruit = list("goldapple" = 1, "biteleafdeus" = 1)
+ result = /obj/item/chems/food/aesirsalad
+
+/decl/recipe/validsalad
+ appliance = APPLIANCE_MIX
+ fruit = list("potato" = 1, "biteleaf" = 3)
+ items = list(/obj/item/chems/food/meatball)
+ result = /obj/item/chems/food/validsalad
+
+/decl/recipe/classichotdog
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/holder/corgi
+ )
+ result = /obj/item/chems/food/classichotdog
+
+/decl/recipe/meatburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/chems/food/cutlet
+ )
+ result = /obj/item/chems/food/meatburger
+
+/decl/recipe/brainburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/organ/internal/brain
+ )
+ result = /obj/item/chems/food/brainburger
+
+/decl/recipe/roburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/robot_parts/head
+ )
+ result = /obj/item/chems/food/roburger
+
+/decl/recipe/xenoburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/chems/food/xenomeat
+ )
+ result = /obj/item/chems/food/xenoburger
+
+/decl/recipe/fishburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/chems/food/fish
+ )
+ result = /obj/item/chems/food/fishburger
+
+/decl/recipe/tofuburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/chems/food/tofu
+ )
+ result = /obj/item/chems/food/tofuburger
+
+/decl/recipe/ghostburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/ectoplasm //where do you even find this stuff
+ )
+ result = /obj/item/chems/food/ghostburger
+
+/decl/recipe/clownburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/clothing/mask/gas/clown_hat
+ )
+ result = /obj/item/chems/food/clownburger
+
+/decl/recipe/mimeburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/clothing/head/beret
+ )
+ result = /obj/item/chems/food/mimeburger
+
+/decl/recipe/bunbun
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun = 2
+ )
+ result = /obj/item/chems/food/bunbun
+
+/decl/recipe/hotdog
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/bun,
+ /obj/item/chems/food/sausage
+ )
+ result = /obj/item/chems/food/hotdog
+
+/decl/recipe/meatkabob
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/stack/material/rods,
+ /obj/item/chems/food/cutlet = 2
+ )
+ result = /obj/item/chems/food/meatkabob
+
+/decl/recipe/tofukabob
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/stack/material/rods,
+ /obj/item/chems/food/tofu = 2,
+ )
+ result = /obj/item/chems/food/tofukabob
+
+/decl/recipe/spellburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/meatburger,
+ /obj/item/clothing/head/wizard,
+ )
+ result = /obj/item/chems/food/spellburger
+
+/decl/recipe/bigbiteburger
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/meatburger,
+ /obj/item/chems/food/meat = 2,
+ /obj/item/chems/food/egg,
+ )
+ reagent_mix = REAGENT_REPLACE // no raw egg
+ result = /obj/item/chems/food/bigbiteburger
+
+/decl/recipe/sandwich
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_MIX
+ items = list(
+ /obj/item/chems/food/meatsteak,
+ /obj/item/chems/food/slice/bread = 2,
+ /obj/item/chems/food/cheesewedge,
+ )
+ result = /obj/item/chems/food/sandwich
+
+/decl/recipe/chazuke
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT // just stir it in a bowl, or heat it
+ reagents = list(/decl/material/liquid/nutriment/rice/chazuke = 10)
+ reagent_mix = REAGENT_REPLACE // no raw chazuke in our cooked chazuke
+ result = /obj/item/chems/food/boiledrice/chazuke
+
+/decl/recipe/taco
+ appliance = APPLIANCE_MIX|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/doughslice,
+ /obj/item/chems/food/cutlet,
+ /obj/item/chems/food/cheesewedge
+ )
+ result = /obj/item/chems/food/taco
+
+/decl/recipe/pelmen
+ appliance = APPLIANCE_MIX // uncooked
+ items = list(
+ /obj/item/chems/food/doughslice = 2,
+ /obj/item/chems/food/rawmeatball
+ )
+ result = /obj/item/chems/food/pelmen
\ No newline at end of file
diff --git a/code/modules/food/recipes/recipes_oven.dm b/code/modules/food/recipes/recipes_oven.dm
new file mode 100644
index 00000000000..d213b8a0dc3
--- /dev/null
+++ b/code/modules/food/recipes/recipes_oven.dm
@@ -0,0 +1,408 @@
+/decl/recipe/donkpocket
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/doughslice,
+ /obj/item/chems/food/meatball
+ )
+ result = /obj/item/chems/food/donkpocket //SPECIAL
+
+/decl/recipe/donkpocket/proc/warm_up(var/obj/item/chems/food/donkpocket/being_cooked)
+ being_cooked.heat()
+
+/decl/recipe/donkpocket/make_food(var/obj/container)
+ . = ..(container)
+ for(var/obj/item/chems/food/donkpocket/being_cooked in .)
+ warm_up(being_cooked)
+
+/decl/recipe/donkpocket/rawmeat
+ items = list(
+ /obj/item/chems/food/doughslice,
+ /obj/item/chems/food/rawmeatball
+ )
+
+/decl/recipe/donkpocket/warm
+ appliance = APPLIANCE_OVEN | APPLIANCE_MICROWAVE
+ reagents = list() //This is necessary since this is a child object of the above recipe and we don't want donk pockets to need flour
+ items = list(
+ /obj/item/chems/food/donkpocket
+ )
+ result = /obj/item/chems/food/donkpocket //SPECIAL
+
+/decl/recipe/donkpocket/warm/check_items(obj/container)
+ . = ..()
+ if(!.)
+ return FALSE
+ for(var/obj/item/chems/food/donkpocket/being_cooked in container.get_contained_external_atoms())
+ if(!being_cooked.warm)
+ return TRUE
+ return FALSE
+
+/decl/recipe/donkpocket/warm/make_food(var/obj/container)
+ for(var/obj/item/chems/food/donkpocket/being_cooked in container.get_contained_external_atoms())
+ if(!being_cooked.warm)
+ warm_up(being_cooked)
+ return list(being_cooked)
+
+/decl/recipe/meatbread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough = 2,
+ /obj/item/chems/food/cutlet = 2,
+ /obj/item/chems/food/cheesewedge = 2,
+ )
+ result = /obj/item/chems/food/sliceable/meatbread
+
+/decl/recipe/xenomeatbread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough = 2,
+ /obj/item/chems/food/xenomeat = 2,
+ /obj/item/chems/food/cheesewedge = 2,
+ )
+ result = /obj/item/chems/food/sliceable/xenomeatbread
+
+/decl/recipe/bananabread
+ appliance = APPLIANCE_OVEN
+ fruit = list("banana" = 2)
+ reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/dough = 2,
+ )
+ reagent_mix = REAGENT_REPLACE // Don't include the milk or sugar
+ result = /obj/item/chems/food/sliceable/bananabread
+
+/decl/recipe/muffin
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 10)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/muffin
+
+/decl/recipe/eggplantparm
+ appliance = APPLIANCE_OVEN
+ fruit = list("eggplant" = 1)
+ items = list(
+ /obj/item/chems/food/cheesewedge = 2
+ )
+ result = /obj/item/chems/food/eggplantparm
+
+/decl/recipe/pizzamargherita
+ appliance = APPLIANCE_OVEN
+ fruit = list("tomato" = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/cheesewedge = 3,
+ )
+ result = /obj/item/chems/food/sliceable/pizza/margherita
+
+/decl/recipe/meatpizza
+ appliance = APPLIANCE_OVEN
+ fruit = list("tomato" = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/cutlet = 2,
+ /obj/item/chems/food/cheesewedge
+ )
+ result = /obj/item/chems/food/sliceable/pizza/meatpizza
+
+/decl/recipe/mushroompizza
+ appliance = APPLIANCE_OVEN
+ fruit = list("mushroom" = 5, "tomato" = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/cheesewedge
+ )
+ result = /obj/item/chems/food/sliceable/pizza/mushroompizza
+
+/decl/recipe/vegetablepizza
+ appliance = APPLIANCE_OVEN
+ fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/cheesewedge
+ )
+ result = /obj/item/chems/food/sliceable/pizza/vegetablepizza
+
+/decl/recipe/spacylibertyduff
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/psychotropics = 5)
+ reagent_mix = REAGENT_REPLACE // Don't include the water
+ result = /obj/item/chems/food/spacylibertyduff
+
+/decl/recipe/cookie
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 5, /decl/material/liquid/nutriment/coco = 5)
+ reagent_mix = REAGENT_REPLACE // Don't include the cakebatter
+ result = /obj/item/chems/food/cookie
+
+/decl/recipe/fortunecookie
+ appliance = APPLIANCE_OVEN|APPLIANCE_FRYER
+ reagents = list(/decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/doughslice // our check_items override already handles the paper
+ )
+ result = /obj/item/chems/food/fortunecookie
+
+/decl/recipe/fortunecookie/make_food(obj/container)
+ . = ..(container)
+ var/obj/item/paper/paper = locate() in container.get_contained_external_atoms()
+ for (var/obj/item/chems/food/fortunecookie/being_cooked in .)
+ paper.forceMove(being_cooked)
+ being_cooked.trash = paper //so the paper is left behind as trash
+ return
+
+/decl/recipe/fortunecookie/check_items(var/obj/container)
+ . = ..()
+ if (.)
+ var/obj/item/paper/paper = locate() in container
+ if (!paper || !istype(paper))
+ return FALSE
+
+/decl/recipe/tofubread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough = 3,
+ /obj/item/chems/food/tofu = 3,
+ /obj/item/chems/food/cheesewedge = 3,
+ )
+ result = /obj/item/chems/food/sliceable/tofubread
+
+/decl/recipe/meatpie
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/cutlet
+ )
+ result = /obj/item/chems/food/meatpie
+
+/decl/recipe/tofupie
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/tofu,
+ )
+ result = /obj/item/chems/food/tofupie
+
+/decl/recipe/xemeatpie
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ /obj/item/chems/food/xenomeat,
+ )
+ result = /obj/item/chems/food/xemeatpie
+
+/decl/recipe/bananapie
+ appliance = APPLIANCE_OVEN
+ fruit = list("banana" = 1)
+ reagents = list(/decl/material/liquid/nutriment/sugar = 5)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ reagent_mix = REAGENT_REPLACE // Don't include the sugar
+ result = /obj/item/chems/food/bananapie
+
+/decl/recipe/cherrypie
+ appliance = APPLIANCE_OVEN
+ fruit = list("cherries" = 1)
+ reagents = list(/decl/material/liquid/nutriment/sugar = 10)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ )
+ reagent_mix = REAGENT_REPLACE // Don't include the sugar
+ result = /obj/item/chems/food/cherrypie
+
+/decl/recipe/berryclafoutis
+ appliance = APPLIANCE_OVEN
+ fruit = list("berries" = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough,
+ )
+ result = /obj/item/chems/food/berryclafoutis
+
+/decl/recipe/chaosdonut
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/frostoil = 5, /decl/material/liquid/capsaicin = 5, /decl/material/liquid/nutriment/sugar = 5)
+ items = list(
+ /obj/item/chems/food/dough
+ )
+ reagent_mix = REAGENT_REPLACE // special case; chaos donut adds random reagents
+ result = /obj/item/chems/food/donut/chaos
+
+/decl/recipe/amanita_pie
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/amatoxin = 5)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ result = /obj/item/chems/food/amanita_pie
+
+/decl/recipe/plump_pie
+ appliance = APPLIANCE_OVEN
+ fruit = list("plumphelmet" = 1)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ result = /obj/item/chems/food/plump_pie
+
+/decl/recipe/enchiladas
+ appliance = APPLIANCE_OVEN|APPLIANCE_FRYER
+ fruit = list("chili" = 2, "corn" = 1)
+ items = list(/obj/item/chems/food/cutlet)
+ result = /obj/item/chems/food/enchiladas
+
+/decl/recipe/creamcheesebread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough = 2,
+ /obj/item/chems/food/cheesewedge = 2,
+ )
+ result = /obj/item/chems/food/sliceable/creamcheesebread
+
+/decl/recipe/monkeysdelight
+ appliance = APPLIANCE_OVEN|APPLIANCE_MICROWAVE
+ fruit = list("banana" = 1)
+ reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1, /decl/material/liquid/nutriment/flour = 10)
+ items = list(
+ /obj/item/chems/food/monkeycube
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/monkeysdelight
+
+/decl/recipe/baguette
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
+ items = list(
+ /obj/item/chems/food/dough = 2,
+ )
+ result = /obj/item/chems/food/baguette
+
+/decl/recipe/bun
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough
+ )
+ result = /obj/item/chems/food/bun
+
+/decl/recipe/flatbread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/sliceable/flatdough
+ )
+ result = /obj/item/chems/food/flatbread
+
+/decl/recipe/bread
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/dough = 4
+ )
+ reagents = list(/decl/material/solid/sodiumchloride = 1)
+ result = /obj/item/chems/food/sliceable/bread
+
+/decl/recipe/poppypretzel
+ appliance = APPLIANCE_OVEN
+ fruit = list("poppy" = 1)
+ items = list(/obj/item/chems/food/dough)
+ result = /obj/item/chems/food/poppypretzel
+
+/decl/recipe/applepie
+ appliance = APPLIANCE_OVEN
+ fruit = list("apple" = 1)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ result = /obj/item/chems/food/applepie
+
+/decl/recipe/pumpkinpie
+ appliance = APPLIANCE_OVEN
+ fruit = list("pumpkin" = 1)
+ reagents = list(/decl/material/liquid/nutriment/sugar = 5)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ reagent_mix = REAGENT_REPLACE // Remove the sugar
+ result = /obj/item/chems/food/sliceable/pumpkinpie
+
+/decl/recipe/plumphelmetbiscuit
+ appliance = APPLIANCE_OVEN
+ fruit = list("plumphelmet" = 1)
+ reagents = list(/decl/material/liquid/nutriment/batter = 10)
+ reagent_mix = REAGENT_REPLACE // Remove the batter
+ result = /obj/item/chems/food/plumphelmetbiscuit
+
+/decl/recipe/plumphelmetbiscuitvegan
+ appliance = APPLIANCE_OVEN
+ fruit = list("plumphelmet" = 1)
+ reagents = list(/decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10)
+ reagent_mix = REAGENT_REPLACE // Remove the raw flour and the water
+ result = /obj/item/chems/food/plumphelmetbiscuit
+
+/decl/recipe/cracker
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/solid/sodiumchloride = 1)
+ items = list(
+ /obj/item/chems/food/doughslice
+ )
+ result = /obj/item/chems/food/cracker
+
+/decl/recipe/stuffing
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
+ items = list(
+ /obj/item/chems/food/sliceable/bread,
+ )
+ reagent_mix = REAGENT_REPLACE // Remove the water
+ result = /obj/item/chems/food/stuffing
+
+/decl/recipe/tofurkey
+ appliance = APPLIANCE_OVEN
+ items = list(
+ /obj/item/chems/food/tofu = 2,
+ /obj/item/chems/food/stuffing,
+ )
+ result = /obj/item/chems/food/tofurkey
+
+/decl/recipe/appletart
+ appliance = APPLIANCE_OVEN
+ fruit = list("goldapple" = 1)
+ items = list(/obj/item/chems/food/sliceable/flatdough)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/appletart
+
+// Cakes.
+/decl/recipe/cake
+ appliance = APPLIANCE_OVEN
+ reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/sliceable/plaincake
+
+/decl/recipe/cake/carrot
+ fruit = list("carrot" = 3)
+ result = /obj/item/chems/food/sliceable/carrotcake
+
+/decl/recipe/cake/cheese
+ items = list(
+ /obj/item/chems/food/cheesewedge = 2
+ )
+ result = /obj/item/chems/food/sliceable/cheesecake
+
+/decl/recipe/cake/orange
+ fruit = list("orange" = 1)
+ result = /obj/item/chems/food/sliceable/orangecake
+
+/decl/recipe/cake/lime
+ fruit = list("lime" = 1)
+ result = /obj/item/chems/food/sliceable/limecake
+
+/decl/recipe/cake/lemon
+ fruit = list("lemon" = 1)
+ result = /obj/item/chems/food/sliceable/lemoncake
+
+/decl/recipe/cake/chocolate
+ items = list(/obj/item/chems/food/chocolatebar)
+ result = /obj/item/chems/food/sliceable/chocolatecake
+
+/decl/recipe/cake/birthday
+ reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60, /decl/material/liquid/nutriment/sprinkles = 10)
+ result = /obj/item/chems/food/sliceable/birthdaycake
+
+/decl/recipe/cake/apple
+ fruit = list("apple" = 2)
+ result = /obj/item/chems/food/sliceable/applecake
+
+/decl/recipe/cake/brain
+ items = list(/obj/item/organ/internal/brain)
+ result = /obj/item/chems/food/sliceable/braincake
+
+/decl/recipe/cake/chocolatebar
+ reagents = list(/decl/material/liquid/drink/milk/chocolate = 10, /decl/material/liquid/nutriment/coco = 5, /decl/material/liquid/nutriment/sugar = 5)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/chocolatebar
\ No newline at end of file
diff --git a/code/modules/food/recipes/recipes_stove.dm b/code/modules/food/recipes/recipes_stove.dm
new file mode 100644
index 00000000000..447b7350600
--- /dev/null
+++ b/code/modules/food/recipes/recipes_stove.dm
@@ -0,0 +1,292 @@
+/decl/recipe/friedegg
+ appliance = APPLIANCE_SKILLET
+ reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
+ items = list(
+ /obj/item/chems/food/egg
+ )
+ result = /obj/item/chems/food/friedegg
+
+/decl/recipe/chocolateegg
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT // melt the chocolate
+ items = list(
+ /obj/item/chems/food/egg,
+ /obj/item/chems/food/chocolatebar,
+ )
+ result = /obj/item/chems/food/chocolateegg
+
+/decl/recipe/sausage
+ appliance = APPLIANCE_SKILLET
+ items = list(
+ /obj/item/chems/food/rawmeatball,
+ /obj/item/chems/food/rawcutlet,
+ )
+ result = /obj/item/chems/food/sausage
+
+/decl/recipe/fatsausage
+ appliance = APPLIANCE_SKILLET
+ reagents = list(/decl/material/solid/blackpepper = 2)
+ items = list(
+ /obj/item/chems/food/rawmeatball,
+ /obj/item/chems/food/rawcutlet,
+ )
+ result = /obj/item/chems/food/fatsausage
+
+/decl/recipe/candiedapple
+ appliance = APPLIANCE_SAUCEPAN
+ fruit = list("apple" = 1)
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/sugar = 5)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/candiedapple
+
+/decl/recipe/chawanmushi
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT // steamed
+ fruit = list("mushroom" = 1)
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/soysauce = 5)
+ items = list(
+ /obj/item/chems/food/egg = 2
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/chawanmushi
+
+/decl/recipe/bloodsoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/blood = 30)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/bloodsoup
+
+/decl/recipe/mysterysoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/badrecipe,
+ /obj/item/chems/food/tofu,
+ /obj/item/chems/food/egg,
+ /obj/item/chems/food/cheesewedge,
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/mysterysoup
+
+/decl/recipe/mushroomsoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("mushroom" = 1)
+ reagents = list(/decl/material/liquid/drink/milk = 10)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/mushroomsoup
+
+/decl/recipe/beetsoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("whitebeet" = 1, "cabbage" = 1)
+ reagents = list(/decl/material/liquid/water = 10)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/beetsoup
+
+/decl/recipe/milosoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/soydope = 2,
+ /obj/item/chems/food/tofu = 2,
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/milosoup
+
+/decl/recipe/tomatosoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("tomato" = 2)
+ reagents = list(/decl/material/liquid/water = 10)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/tomatosoup
+
+/decl/recipe/meatballsoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("carrot" = 1, "potato" = 1)
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(/obj/item/chems/food/meatball)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/meatballsoup
+
+/decl/recipe/vegetablesoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("carrot" = 1, "potato" = 1, "corn" = 1, "eggplant" = 1)
+ reagents = list(/decl/material/liquid/water = 10)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/vegetablesoup
+
+/decl/recipe/nettlesoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("nettle" = 1, "potato" = 1)
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/egg
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/nettlesoup
+
+/decl/recipe/wishsoup
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT // microwave works, because desperation
+ reagents = list(/decl/material/liquid/water = 20)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result= /obj/item/chems/food/wishsoup
+
+/decl/recipe/hotchili
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("chili" = 1, "tomato" = 1)
+ items = list(/obj/item/chems/food/cutlet)
+ result = /obj/item/chems/food/hotchili
+
+/decl/recipe/coldchili
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("icechili" = 1, "tomato" = 1)
+ items = list(/obj/item/chems/food/cutlet)
+ result = /obj/item/chems/food/coldchili
+
+/decl/recipe/stew
+ appliance = APPLIANCE_MICROWAVE|APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("potato" = 1, "tomato" = 1, "carrot" = 1, "eggplant" = 1, "mushroom" = 1)
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(/obj/item/chems/food/meat)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/stew
+
+/decl/recipe/mint
+ appliance = APPLIANCE_SAUCEPAN
+ reagents = list(/decl/material/liquid/nutriment/sugar = 5, /decl/material/liquid/frostoil = 5)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/mint
+
+/decl/recipe/boiledspiderleg
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/spider
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/spider/cooked
+
+/decl/recipe/pelmeni_boiled
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/pelmen = 5
+ )
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/pelmeni_boiled
+
+/decl/recipe/meatball
+ appliance = APPLIANCE_SKILLET|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/rawmeatball
+ )
+ result = /obj/item/chems/food/meatball
+
+/decl/recipe/cutlet
+ appliance = APPLIANCE_SKILLET|APPLIANCE_MICROWAVE
+ items = list(
+ /obj/item/chems/food/rawcutlet
+ )
+ result = /obj/item/chems/food/cutlet
+
+/decl/recipe/ricepudding
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/rice = 10)
+ reagent_mix = REAGENT_REPLACE // get the raw reagents out of there
+ result = /obj/item/chems/food/ricepudding
+
+/decl/recipe/stewedsoymeat
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ fruit = list("carrot" = 1, "tomato" = 1)
+ items = list(
+ /obj/item/chems/food/soydope = 2
+ )
+ result = /obj/item/chems/food/stewedsoymeat
+
+/decl/recipe/boiledspagetti
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/spagetti,
+ )
+ reagent_mix = REAGENT_REPLACE // don't fill it with water
+ result = /obj/item/chems/food/boiledspagetti
+
+/decl/recipe/boiledegg
+ appliance = APPLIANCE_SAUCEPAN|APPLIANCE_POT
+ reagents = list(/decl/material/liquid/water = 10)
+ items = list(
+ /obj/item/chems/food/egg
+ )
+ reagent_mix = REAGENT_REPLACE // shouldn't fill it with water
+ result = /obj/item/chems/food/boiledegg
+
+/decl/recipe/waffles
+ appliance = APPLIANCE_SKILLET // no waffle griddle, sadly
+ reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 20)
+ reagent_mix = REAGENT_REPLACE // the batter should be cooked
+ result = /obj/item/chems/food/waffles
+
+/decl/recipe/pancakes
+ appliance = APPLIANCE_SKILLET
+ reagents = list(/decl/material/liquid/nutriment/batter = 20)
+ reagent_mix = REAGENT_REPLACE // the batter should be cooked
+ result = /obj/item/chems/food/pancakes
+
+/decl/recipe/pancakes/blu
+ fruit = list("blueberries" = 2)
+ result = /obj/item/chems/food/pancakesblu
+
+/decl/recipe/omelette
+ appliance = APPLIANCE_SKILLET
+ reagents = list(/decl/material/liquid/nutriment/protein/egg = 6)
+ items = list(
+ /obj/item/chems/food/cheesewedge,
+ )
+ result = /obj/item/chems/food/omelette
+
+/decl/recipe/soylenviridians
+ appliance = APPLIANCE_SKILLET // considering it equivalent to waffles?
+ fruit = list("soybeans" = 1)
+ reagents = list(/decl/material/liquid/nutriment/flour = 10)
+ reagent_mix = REAGENT_REPLACE // get the flour out of there
+ result = /obj/item/chems/food/soylenviridians
+
+/decl/recipe/soylentgreen
+ appliance = APPLIANCE_SKILLET // considering it equivalent to waffles?
+ reagents = list(/decl/material/liquid/nutriment/flour = 10)
+ items = list(
+ /obj/item/chems/food/meat/human = 2
+ )
+ reagent_mix = REAGENT_REPLACE // no flour
+ result = /obj/item/chems/food/soylentgreen
+
+/decl/recipe/amanitajelly
+ appliance = APPLIANCE_SAUCEPAN
+ reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/amatoxin = 5)
+ reagent_mix = REAGENT_REPLACE // simplify end product
+ result = /obj/item/chems/food/amanitajelly
+
+/decl/recipe/amanitajelly/make_food(var/obj/container)
+ . = ..(container)
+ for(var/obj/item/chems/food/amanitajelly/being_cooked in .)
+ being_cooked.reagents.clear_reagent(/decl/material/liquid/amatoxin)
+
+/decl/recipe/toastedsandwich
+ appliance = APPLIANCE_SKILLET
+ items = list(
+ /obj/item/chems/food/sandwich
+ )
+ result = /obj/item/chems/food/toastedsandwich
+
+/decl/recipe/grilledcheese
+ appliance = APPLIANCE_SKILLET
+ items = list(
+ /obj/item/chems/food/slice/bread = 2,
+ /obj/item/chems/food/cheesewedge,
+ )
+ result = /obj/item/chems/food/grilledcheese
+/decl/recipe/jelliedtoast
+ appliance = APPLIANCE_SKILLET
+ reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
+ items = list(
+ /obj/item/chems/food/slice/bread,
+ )
+ result = /obj/item/chems/food/jelliedtoast/cherry
\ No newline at end of file
diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm
deleted file mode 100644
index 35c80f85654..00000000000
--- a/code/modules/food/recipes_microwave.dm
+++ /dev/null
@@ -1,962 +0,0 @@
-
-// see code/datums/recipe.dm
-
-
-/* No telebacon. just no...
-/decl/recipe/telebacon
- items = list(
- /obj/item/chems/food/meat,
- /obj/item/assembly/signaler
- )
- result = /obj/item/chems/food/telebacon
-
-I said no!
-/decl/recipe/syntitelebacon
- items = list(
- /obj/item/chems/food/meat/syntiflesh,
- /obj/item/assembly/signaler
- )
- result = /obj/item/chems/food/telebacon
-*/
-
-/decl/recipe/friedegg
- reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
- items = list(
- /obj/item/chems/food/egg
- )
- reagent_mix = REAGENT_REPLACE // no raw egg
- result = /obj/item/chems/food/friedegg
-
-/decl/recipe/boiledegg
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/egg
- )
- reagent_mix = REAGENT_REPLACE // no raw egg or water
- result = /obj/item/chems/food/boiledegg
-
-/decl/recipe/classichotdog
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/holder/corgi
- )
- result = /obj/item/chems/food/classichotdog
-
-/decl/recipe/jellydonut
- reagents = list(/decl/material/liquid/drink/juice/berry = 5, /decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/dough
- )
- result = /obj/item/chems/food/donut/jelly
-
-/decl/recipe/jellydonut/cherry
- reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5, /decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/dough
- )
- result = /obj/item/chems/food/donut/cherryjelly
-
-/decl/recipe/donut
- reagents = list(/decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/dough
- )
- result = /obj/item/chems/food/donut/normal
-
-/decl/recipe/meatburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/chems/food/cutlet
- )
- result = /obj/item/chems/food/meatburger
-
-/decl/recipe/brainburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/organ/internal/brain
- )
- result = /obj/item/chems/food/brainburger
-
-/decl/recipe/roburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/robot_parts/head
- )
- result = /obj/item/chems/food/roburger
-
-/decl/recipe/xenoburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/chems/food/xenomeat
- )
- result = /obj/item/chems/food/xenoburger
-
-/decl/recipe/fishburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/chems/food/fish
- )
- result = /obj/item/chems/food/fishburger
-
-/decl/recipe/tofuburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/chems/food/tofu
- )
- result = /obj/item/chems/food/tofuburger
-
-/decl/recipe/ghostburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/ectoplasm //where do you even find this stuff
- )
- result = /obj/item/chems/food/ghostburger
-
-/decl/recipe/clownburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/clothing/mask/gas/clown_hat
- )
- result = /obj/item/chems/food/clownburger
-
-/decl/recipe/mimeburger
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/clothing/head/beret
- )
- result = /obj/item/chems/food/mimeburger
-
-/decl/recipe/bunbun
- items = list(
- /obj/item/chems/food/bun = 2
- )
- result = /obj/item/chems/food/bunbun
-
-/decl/recipe/hotdog
- items = list(
- /obj/item/chems/food/bun,
- /obj/item/chems/food/sausage
- )
- result = /obj/item/chems/food/hotdog
-
-/decl/recipe/waffles
- reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 20)
- result = /obj/item/chems/food/waffles
-
-/decl/recipe/pancakesblu
- reagents = list(/decl/material/liquid/nutriment/batter = 20)
- fruit = list("blueberries" = 2)
- result = /obj/item/chems/food/pancakesblu
-
-/decl/recipe/pancakes
- reagents = list(/decl/material/liquid/nutriment/batter = 20)
- result = /obj/item/chems/food/pancakes
-
-/decl/recipe/donkpocket
- items = list(
- /obj/item/chems/food/doughslice,
- /obj/item/chems/food/meatball
- )
- result = /obj/item/chems/food/donkpocket //SPECIAL
-
-/decl/recipe/donkpocket/proc/warm_up(var/obj/item/chems/food/donkpocket/being_cooked)
- being_cooked.heat()
-
-/decl/recipe/donkpocket/make_food(var/obj/container)
- . = ..(container)
- for(var/obj/item/chems/food/donkpocket/being_cooked in .)
- warm_up(being_cooked)
-
-/decl/recipe/donkpocket/rawmeatball
- items = list(
- /obj/item/chems/food/doughslice,
- /obj/item/chems/food/rawmeatball
- )
-
-/decl/recipe/donkpocket/warm
- reagents = list() //This is necessary since this is a child object of the above recipe and we don't want donk pockets to need flour
- items = list(
- /obj/item/chems/food/donkpocket
- )
- result = /obj/item/chems/food/donkpocket //SPECIAL
-
-/decl/recipe/donkpocket/warm/check_items(obj/container)
- . = ..()
- if(!.)
- return FALSE
- for(var/obj/item/chems/food/donkpocket/being_cooked in container.get_contained_external_atoms())
- if(!being_cooked.warm)
- return TRUE
- return FALSE
-
-/decl/recipe/donkpocket/warm/make_food(var/obj/container)
- for(var/obj/item/chems/food/donkpocket/being_cooked in container.get_contained_external_atoms())
- if(!being_cooked.warm)
- warm_up(being_cooked)
- return list(being_cooked)
-
-/decl/recipe/meatbread
- items = list(
- /obj/item/chems/food/dough = 2,
- /obj/item/chems/food/cutlet = 2,
- /obj/item/chems/food/cheesewedge = 2,
- )
- result = /obj/item/chems/food/sliceable/meatbread
-
-/decl/recipe/xenomeatbread
- items = list(
- /obj/item/chems/food/dough = 2,
- /obj/item/chems/food/xenomeat = 2,
- /obj/item/chems/food/cheesewedge = 2,
- )
- result = /obj/item/chems/food/sliceable/xenomeatbread
-
-/decl/recipe/bananabread
- fruit = list("banana" = 2)
- reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/dough = 2,
- )
- result = /obj/item/chems/food/sliceable/bananabread
-
-/decl/recipe/omelette
- items = list(
- /obj/item/chems/food/egg = 2,
- /obj/item/chems/food/cheesewedge,
- )
- reagent_mix = REAGENT_REPLACE // no raw egg
- result = /obj/item/chems/food/omelette
-
-/decl/recipe/muffin
- reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 10)
- result = /obj/item/chems/food/muffin
-
-/decl/recipe/eggplantparm
- fruit = list("eggplant" = 1)
- items = list(
- /obj/item/chems/food/cheesewedge = 2
- )
- result = /obj/item/chems/food/eggplantparm
-
-/decl/recipe/soylenviridians
- fruit = list("soybeans" = 1)
- reagents = list(/decl/material/liquid/nutriment/flour = 10)
- reagent_mix = REAGENT_REPLACE // no raw flour
- result = /obj/item/chems/food/soylenviridians
-
-/decl/recipe/soylentgreen
- reagents = list(/decl/material/liquid/nutriment/flour = 10)
- items = list(
- /obj/item/chems/food/meat/human = 2
- )
- reagent_mix = REAGENT_REPLACE // no raw flour
- result = /obj/item/chems/food/soylentgreen
-
-/decl/recipe/meatpie
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/cutlet
- )
- result = /obj/item/chems/food/meatpie
-
-/decl/recipe/tofupie
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/tofu,
- )
- result = /obj/item/chems/food/tofupie
-
-/decl/recipe/xemeatpie
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/xenomeat,
- )
- result = /obj/item/chems/food/xemeatpie
-
-/decl/recipe/bananapie
- fruit = list("banana" = 1)
- reagents = list(/decl/material/liquid/nutriment/sugar = 5)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- result = /obj/item/chems/food/bananapie
-
-/decl/recipe/cherrypie
- fruit = list("cherries" = 1)
- reagents = list(/decl/material/liquid/nutriment/sugar = 10)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- )
- result = /obj/item/chems/food/cherrypie
-
-/decl/recipe/berryclafoutis
- fruit = list("berries" = 1)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- )
- result = /obj/item/chems/food/berryclafoutis
-
-/decl/recipe/chaosdonut
- reagents = list(/decl/material/liquid/frostoil = 5, /decl/material/liquid/capsaicin = 5, /decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/dough
- )
- result = /obj/item/chems/food/donut/chaos
-
-/decl/recipe/meatkabob
- items = list(
- /obj/item/stack/material/rods,
- /obj/item/chems/food/cutlet = 2
- )
- result = /obj/item/chems/food/meatkabob
-
-/decl/recipe/tofukabob
- items = list(
- /obj/item/stack/material/rods,
- /obj/item/chems/food/tofu = 2,
- )
- result = /obj/item/chems/food/tofukabob
-
-/decl/recipe/tofubread
- items = list(
- /obj/item/chems/food/dough = 3,
- /obj/item/chems/food/tofu = 3,
- /obj/item/chems/food/cheesewedge = 3,
- )
- result = /obj/item/chems/food/sliceable/tofubread
-
-/decl/recipe/loadedbakedpotato
- fruit = list("potato" = 1)
- items = list(/obj/item/chems/food/cheesewedge)
- result = /obj/item/chems/food/loadedbakedpotato
-
-/decl/recipe/cheesyfries
- items = list(
- /obj/item/chems/food/fries,
- /obj/item/chems/food/cheesewedge,
- )
- result = /obj/item/chems/food/cheesyfries
-
-/decl/recipe/cubancarp
- fruit = list("chili" = 1)
- reagents = list(/decl/material/liquid/nutriment/batter = 10)
- items = list(
- /obj/item/chems/food/fish
- )
- result = /obj/item/chems/food/cubancarp
-
-/decl/recipe/popcorn
- reagents = list(/decl/material/solid/sodiumchloride = 5)
- fruit = list("corn" = 1)
- result = /obj/item/chems/food/popcorn
-
-/decl/recipe/cookie
- reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 5, /decl/material/liquid/nutriment/coco = 5)
- reagent_mix = REAGENT_REPLACE // no raw batter
- result = /obj/item/chems/food/cookie
-
-/decl/recipe/fortunecookie
- reagents = list(/decl/material/liquid/nutriment/sugar = 5)
- items = list(
- /obj/item/chems/food/doughslice,
- /obj/item/paper,
- )
- result = /obj/item/chems/food/fortunecookie
-
-/decl/recipe/fortunecookie/make_food(obj/container)
- var/obj/item/paper/paper = locate() in container
- paper.forceMove(null) //prevent deletion
- var/obj/item/chems/food/fortunecookie/being_cooked = ..(container)
- paper.forceMove(being_cooked)
- being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn
- return being_cooked
-
-/decl/recipe/fortunecookie/check_items(var/obj/container)
- . = ..()
- if(.)
- var/obj/item/paper/paper = locate() in container
- if(!paper || !paper.info)
- return FALSE
-
-/decl/recipe/plainsteak
- items = list(/obj/item/chems/food/meat)
- result = /obj/item/chems/food/plainsteak
-
-/decl/recipe/meatsteak
- reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
- items = list(/obj/item/chems/food/cutlet)
- result = /obj/item/chems/food/meatsteak
-
-/decl/recipe/loadedsteak
- reagents = list(/decl/material/liquid/nutriment/garlicsauce = 5)
- fruit = list("onion" = 1, "mushroom" = 1)
- items = list(/obj/item/chems/food/cutlet)
- result = /obj/item/chems/food/loadedsteak
-
-/decl/recipe/syntisteak
- reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
- items = list(/obj/item/chems/food/meat/syntiflesh)
- result = /obj/item/chems/food/meatsteak/synthetic
-
-/decl/recipe/pizzamargherita
- fruit = list("tomato" = 1)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/cheesewedge = 3,
- )
- result = /obj/item/chems/food/sliceable/pizza/margherita
-
-/decl/recipe/meatpizza
- fruit = list("tomato" = 1)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/cutlet = 2,
- /obj/item/chems/food/cheesewedge
- )
- result = /obj/item/chems/food/sliceable/pizza/meatpizza
-
-/decl/recipe/mushroompizza
- fruit = list("mushroom" = 5, "tomato" = 1)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/cheesewedge
- )
- result = /obj/item/chems/food/sliceable/pizza/mushroompizza
-
-/decl/recipe/vegetablepizza
- fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1)
- items = list(
- /obj/item/chems/food/sliceable/flatdough,
- /obj/item/chems/food/cheesewedge
- )
- result = /obj/item/chems/food/sliceable/pizza/vegetablepizza
-
-/decl/recipe/spacylibertyduff
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/psychotropics = 5)
- result = /obj/item/chems/food/spacylibertyduff
-
-/decl/recipe/amanitajelly
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/amatoxin = 5)
- result = /obj/item/chems/food/amanitajelly
-
-/decl/recipe/amanitajelly/make_food(var/obj/container)
- var/obj/item/chems/food/amanitajelly/being_cooked = ..(container)
- being_cooked.reagents.clear_reagent(/decl/material/liquid/amatoxin)
- return being_cooked
-
-/decl/recipe/meatballsoup
- fruit = list("carrot" = 1, "potato" = 1)
- reagents = list(/decl/material/liquid/water = 10)
- items = list(/obj/item/chems/food/meatball)
- reagent_mix = REAGENT_REPLACE // Remove extra water
- result = /obj/item/chems/food/meatballsoup
-
-/decl/recipe/vegetablesoup
- fruit = list("carrot" = 1, "potato" = 1, "corn" = 1, "eggplant" = 1)
- reagents = list(/decl/material/liquid/water = 10)
- reagent_mix = REAGENT_REPLACE // Remove extra water
- result = /obj/item/chems/food/vegetablesoup
-
-/decl/recipe/nettlesoup
- fruit = list("nettle" = 1, "potato" = 1)
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/egg
- )
- reagent_mix = REAGENT_REPLACE // Remove extra water and egg
- result = /obj/item/chems/food/nettlesoup
-
-/decl/recipe/wishsoup
- reagents = list(/decl/material/liquid/water = 20)
- reagent_mix = REAGENT_REPLACE // Remove extra water
- result= /obj/item/chems/food/wishsoup
-
-/decl/recipe/hotchili
- fruit = list("chili" = 1, "tomato" = 1)
- items = list(/obj/item/chems/food/cutlet)
- result = /obj/item/chems/food/hotchili
-
-/decl/recipe/coldchili
- fruit = list("icechili" = 1, "tomato" = 1)
- items = list(/obj/item/chems/food/cutlet)
- result = /obj/item/chems/food/coldchili
-
-/decl/recipe/amanita_pie
- reagents = list(/decl/material/liquid/amatoxin = 5)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- result = /obj/item/chems/food/amanita_pie
-
-/decl/recipe/plump_pie
- fruit = list("plumphelmet" = 1)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- result = /obj/item/chems/food/plump_pie
-
-/decl/recipe/spellburger
- items = list(
- /obj/item/chems/food/meatburger,
- /obj/item/clothing/head/wizard,
- )
- result = /obj/item/chems/food/spellburger
-
-/decl/recipe/bigbiteburger
- items = list(
- /obj/item/chems/food/meatburger,
- /obj/item/chems/food/meat = 2,
- /obj/item/chems/food/egg,
- )
- reagent_mix = REAGENT_REPLACE // no raw egg
- result = /obj/item/chems/food/bigbiteburger
-
-/decl/recipe/enchiladas
- fruit = list("chili" = 2, "corn" = 1)
- items = list(/obj/item/chems/food/cutlet)
- result = /obj/item/chems/food/enchiladas
-
-/decl/recipe/creamcheesebread
- items = list(
- /obj/item/chems/food/dough = 2,
- /obj/item/chems/food/cheesewedge = 2,
- )
- result = /obj/item/chems/food/sliceable/creamcheesebread
-
-/decl/recipe/monkeysdelight
- fruit = list("banana" = 1)
- reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1, /decl/material/liquid/nutriment/flour = 10)
- items = list(
- /obj/item/chems/food/monkeycube
- )
- result = /obj/item/chems/food/monkeysdelight
-
-/decl/recipe/baguette
- reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
- items = list(
- /obj/item/chems/food/dough = 2,
- )
- result = /obj/item/chems/food/baguette
-
-/decl/recipe/fishandchips
- items = list(
- /obj/item/chems/food/fries,
- /obj/item/chems/food/fish
- )
- result = /obj/item/chems/food/fishandchips
-
-/decl/recipe/bread
- items = list(
- /obj/item/chems/food/dough = 2,
- /obj/item/chems/food/egg
- )
- reagent_mix = REAGENT_REPLACE // no raw egg/flour
- result = /obj/item/chems/food/sliceable/bread
-
-/decl/recipe/sandwich
- items = list(
- /obj/item/chems/food/meatsteak,
- /obj/item/chems/food/slice/bread = 2,
- /obj/item/chems/food/cheesewedge,
- )
- result = /obj/item/chems/food/sandwich
-
-/decl/recipe/toastedsandwich
- items = list(
- /obj/item/chems/food/sandwich
- )
- result = /obj/item/chems/food/toastedsandwich
-
-/decl/recipe/grilledcheese
- items = list(
- /obj/item/chems/food/slice/bread = 2,
- /obj/item/chems/food/cheesewedge,
- )
- result = /obj/item/chems/food/grilledcheese
-
-/decl/recipe/tomatosoup
- fruit = list("tomato" = 2)
- reagents = list(/decl/material/liquid/water = 10)
- result = /obj/item/chems/food/tomatosoup
-
-/decl/recipe/rofflewaffles
- reagents = list(/decl/material/liquid/psychotropics = 5, /decl/material/liquid/nutriment/batter/cakebatter = 20)
- result = /obj/item/chems/food/rofflewaffles
-
-/decl/recipe/stew
- fruit = list("potato" = 1, "tomato" = 1, "carrot" = 1, "eggplant" = 1, "mushroom" = 1)
- reagents = list(/decl/material/liquid/water = 10)
- items = list(/obj/item/chems/food/meat)
- result = /obj/item/chems/food/stew
-
-/decl/recipe/jelliedtoast
- reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
- items = list(
- /obj/item/chems/food/slice/bread,
- )
- result = /obj/item/chems/food/jelliedtoast/cherry
-
-/decl/recipe/milosoup
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/soydope = 2,
- /obj/item/chems/food/tofu = 2,
- )
- result = /obj/item/chems/food/milosoup
-
-/decl/recipe/stewedsoymeat
- fruit = list("carrot" = 1, "tomato" = 1)
- items = list(
- /obj/item/chems/food/soydope = 2
- )
- result = /obj/item/chems/food/stewedsoymeat
-
-/decl/recipe/boiledspagetti
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/spagetti,
- )
- result = /obj/item/chems/food/boiledspagetti
-
-/decl/recipe/boiledrice
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/rice = 10)
- result = /obj/item/chems/food/boiledrice
-
-/decl/recipe/chazuke
- reagents = list(/decl/material/liquid/nutriment/rice/chazuke = 10)
- result = /obj/item/chems/food/boiledrice/chazuke
-
-/decl/recipe/katsucurry
- fruit = list("apple" = 1, "carrot" = 1, "potato" = 1)
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/rice = 10, /decl/material/liquid/nutriment/flour = 5)
- items = list(
- /obj/item/chems/food/meat/chicken
- )
- result = /obj/item/chems/food/katsucurry
-
-/decl/recipe/ricepudding
- reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/rice = 10)
- result = /obj/item/chems/food/ricepudding
-
-/decl/recipe/pastatomato
- fruit = list("tomato" = 2)
- reagents = list(/decl/material/liquid/water = 10)
- items = list(/obj/item/chems/food/spagetti)
- result = /obj/item/chems/food/pastatomato
-
-/decl/recipe/poppypretzel
- fruit = list("poppy" = 1)
- items = list(/obj/item/chems/food/dough)
- result = /obj/item/chems/food/poppypretzel
-
-/decl/recipe/meatballspagetti
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/spagetti,
- /obj/item/chems/food/meatball = 2,
- )
- result = /obj/item/chems/food/meatballspagetti
-
-/decl/recipe/spesslaw
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/spagetti,
- /obj/item/chems/food/meatball = 4,
- )
- result = /obj/item/chems/food/spesslaw
-
-/decl/recipe/nanopasta
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/spagetti,
- /obj/item/stack/nanopaste
- )
- result = /obj/item/chems/food/nanopasta
-
-/decl/recipe/superbiteburger
- fruit = list("tomato" = 1)
- reagents = list(/decl/material/solid/sodiumchloride = 5, /decl/material/solid/blackpepper = 5)
- items = list(
- /obj/item/chems/food/bigbiteburger,
- /obj/item/chems/food/dough,
- /obj/item/chems/food/meat,
- /obj/item/chems/food/cheesewedge,
- /obj/item/chems/food/boiledegg,
- )
- result = /obj/item/chems/food/superbiteburger
-
-/decl/recipe/candiedapple
- fruit = list("apple" = 1)
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/sugar = 5)
- result = /obj/item/chems/food/candiedapple
-
-/decl/recipe/applepie
- fruit = list("apple" = 1)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- result = /obj/item/chems/food/applepie
-
-/decl/recipe/jellyburger
- reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
- items = list(
- /obj/item/chems/food/bun
- )
- result = /obj/item/chems/food/jellyburger/cherry
-
-/decl/recipe/twobread
- reagents = list(/decl/material/liquid/ethanol/wine = 5)
- items = list(
- /obj/item/chems/food/slice/bread = 2,
- )
- result = /obj/item/chems/food/twobread
-
-/decl/recipe/threebread
- items = list(
- /obj/item/chems/food/twobread,
- /obj/item/chems/food/slice/bread,
- )
- result = /obj/item/chems/food/threebread
-
-/decl/recipe/cherrysandwich
- reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5)
- items = list(
- /obj/item/chems/food/slice/bread = 2,
- )
- result = /obj/item/chems/food/jellysandwich/cherry
-
-/decl/recipe/bloodsoup
- reagents = list(/decl/material/liquid/blood = 30)
- result = /obj/item/chems/food/bloodsoup
-
-/decl/recipe/chocolateegg
- items = list(
- /obj/item/chems/food/egg,
- /obj/item/chems/food/chocolatebar,
- )
- reagent_mix = REAGENT_REPLACE // no raw egg
- result = /obj/item/chems/food/chocolateegg
-
-/decl/recipe/sausage
- items = list(
- /obj/item/chems/food/rawmeatball,
- /obj/item/chems/food/rawcutlet,
- )
- result = /obj/item/chems/food/sausage
-
-/decl/recipe/fatsausage
- reagents = list(/decl/material/solid/blackpepper = 2)
- items = list(
- /obj/item/chems/food/rawmeatball,
- /obj/item/chems/food/rawcutlet,
- )
- result = /obj/item/chems/food/fatsausage
-
-/decl/recipe/fishfingers
- reagents = list(/decl/material/liquid/nutriment/flour = 10)
- items = list(
- /obj/item/chems/food/egg,
- /obj/item/chems/food/fish
- )
- reagent_mix = REAGENT_REPLACE // no raw egg/fish
- result = /obj/item/chems/food/fishfingers
-
-/decl/recipe/mysterysoup
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/badrecipe,
- /obj/item/chems/food/tofu,
- /obj/item/chems/food/egg,
- /obj/item/chems/food/cheesewedge,
- )
- reagent_mix = REAGENT_REPLACE // Has its own special products
- result = /obj/item/chems/food/mysterysoup
-
-/decl/recipe/pumpkinpie
- fruit = list("pumpkin" = 1)
- reagents = list(/decl/material/liquid/nutriment/sugar = 5)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- reagent_mix = REAGENT_REPLACE // no raw flour
- result = /obj/item/chems/food/sliceable/pumpkinpie
-
-/decl/recipe/plumphelmetbiscuit
- fruit = list("plumphelmet" = 1)
- reagents = list(/decl/material/liquid/nutriment/batter = 10)
- result = /obj/item/chems/food/plumphelmetbiscuit
-
-/decl/recipe/plumphelmetbiscuitvegan
- fruit = list("plumphelmet" = 1)
- reagents = list(/decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10)
- result = /obj/item/chems/food/plumphelmetbiscuit
-
-/decl/recipe/mushroomsoup
- fruit = list("mushroom" = 1)
- reagents = list(/decl/material/liquid/drink/milk = 10)
- reagent_mix = REAGENT_REPLACE // get that milk outta here
- result = /obj/item/chems/food/mushroomsoup
-
-/decl/recipe/chawanmushi
- fruit = list("mushroom" = 1)
- reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/soysauce = 5)
- items = list(
- /obj/item/chems/food/egg = 2
- )
- reagent_mix = REAGENT_REPLACE // no raw egg
- result = /obj/item/chems/food/chawanmushi
-
-/decl/recipe/beetsoup
- fruit = list("whitebeet" = 1, "cabbage" = 1)
- reagents = list(/decl/material/liquid/water = 10)
- result = /obj/item/chems/food/beetsoup
-
-/decl/recipe/appletart
- fruit = list("goldapple" = 1)
- items = list(/obj/item/chems/food/sliceable/flatdough)
- reagent_mix = REAGENT_REPLACE // no raw flour
- result = /obj/item/chems/food/appletart
-
-/decl/recipe/tossedsalad
- fruit = list("cabbage" = 2, "tomato" = 1, "carrot" = 1, "apple" = 1)
- result = /obj/item/chems/food/tossedsalad
-
-/decl/recipe/aesirsalad
- fruit = list("goldapple" = 1, "biteleafdeus" = 1)
- result = /obj/item/chems/food/aesirsalad
-
-/decl/recipe/validsalad
- fruit = list("potato" = 1, "biteleaf" = 3)
- items = list(/obj/item/chems/food/meatball)
- result = /obj/item/chems/food/validsalad
-
-/decl/recipe/cracker
- reagents = list(/decl/material/solid/sodiumchloride = 1)
- items = list(
- /obj/item/chems/food/doughslice
- )
- result = /obj/item/chems/food/cracker
-
-/decl/recipe/stuffing
- reagents = list(/decl/material/liquid/water = 10, /decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1)
- items = list(
- /obj/item/chems/food/sliceable/bread,
- )
- result = /obj/item/chems/food/stuffing
-
-/decl/recipe/tofurkey
- items = list(
- /obj/item/chems/food/tofu = 2,
- /obj/item/chems/food/stuffing,
- )
- result = /obj/item/chems/food/tofurkey
-
-//////////////////////////////////////////
-// bs12 food port stuff
-//////////////////////////////////////////
-
-/decl/recipe/taco
- items = list(
- /obj/item/chems/food/doughslice,
- /obj/item/chems/food/cutlet,
- /obj/item/chems/food/cheesewedge
- )
- result = /obj/item/chems/food/taco
-
-/decl/recipe/bun
- items = list(
- /obj/item/chems/food/dough
- )
- result = /obj/item/chems/food/bun
-
-/decl/recipe/flatbread
- items = list(
- /obj/item/chems/food/sliceable/flatdough
- )
- result = /obj/item/chems/food/flatbread
-
-/decl/recipe/meatball
- items = list(
- /obj/item/chems/food/rawmeatball
- )
- result = /obj/item/chems/food/meatball
-
-/decl/recipe/cutlet
- items = list(
- /obj/item/chems/food/rawcutlet
- )
- result = /obj/item/chems/food/cutlet
-
-/decl/recipe/fries
- items = list(
- /obj/item/chems/food/rawsticks
- )
- result = /obj/item/chems/food/fries
-
-/decl/recipe/onionrings
- fruit = list("onion" = 1)
- reagents = list(/decl/material/liquid/nutriment/batter = 10)
- result = /obj/item/chems/food/onionrings
-
-/decl/recipe/mint
- reagents = list(/decl/material/liquid/nutriment/sugar = 5, /decl/material/liquid/frostoil = 5)
- result = /obj/item/chems/food/mint
-
-// Cakes.
-/decl/recipe/cake
- reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60)
- reagent_mix = REAGENT_REPLACE // no raw batter
- result = /obj/item/chems/food/sliceable/plaincake
-
-/decl/recipe/cake/carrot
- fruit = list("carrot" = 3)
- result = /obj/item/chems/food/sliceable/carrotcake
-
-/decl/recipe/cake/cheese
- items = list(
- /obj/item/chems/food/cheesewedge = 2
- )
- result = /obj/item/chems/food/sliceable/cheesecake
-
-/decl/recipe/cake/orange
- fruit = list("orange" = 1)
- result = /obj/item/chems/food/sliceable/orangecake
-
-/decl/recipe/cake/lime
- fruit = list("lime" = 1)
- result = /obj/item/chems/food/sliceable/limecake
-
-/decl/recipe/cake/lemon
- fruit = list("lemon" = 1)
- result = /obj/item/chems/food/sliceable/lemoncake
-
-/decl/recipe/cake/chocolate
- items = list(/obj/item/chems/food/chocolatebar)
- result = /obj/item/chems/food/sliceable/chocolatecake
-
-/decl/recipe/cake/birthday
- reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60, /decl/material/liquid/nutriment/sprinkles = 10)
- result = /obj/item/chems/food/sliceable/birthdaycake
-
-/decl/recipe/cake/apple
- fruit = list("apple" = 2)
- result = /obj/item/chems/food/sliceable/applecake
-
-/decl/recipe/cake/brain
- items = list(/obj/item/organ/internal/brain)
- result = /obj/item/chems/food/sliceable/braincake
-
-/decl/recipe/cake/chocolatebar
- reagents = list(/decl/material/liquid/drink/milk/chocolate = 10, /decl/material/liquid/nutriment/coco = 5, /decl/material/liquid/nutriment/sugar = 5)
- result = /obj/item/chems/food/chocolatebar
-
-/decl/recipe/boiledspiderleg
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/spider
- )
- result = /obj/item/chems/food/spider/cooked
-
-/decl/recipe/pelmen
- items = list(
- /obj/item/chems/food/doughslice = 2,
- /obj/item/chems/food/rawmeatball
- )
- result = /obj/item/chems/food/pelmen
-
-/decl/recipe/pelmeni_boiled
- reagents = list(/decl/material/liquid/water = 10)
- items = list(
- /obj/item/chems/food/pelmen = 5
- )
- result = /obj/item/chems/food/pelmeni_boiled
diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm
index ef0b95ebc14..2728becaa1c 100644
--- a/code/modules/ghosttrap/trap.dm
+++ b/code/modules/ghosttrap/trap.dm
@@ -89,7 +89,7 @@
if(!can_set_own_name)
return
- var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change",target.real_name) as text, MAX_NAME_LEN)
+ var/newname = sanitize_safe(input(target,"Enter a name, or leave blank for the default name.", "Name change",target.real_name) as text, MAX_NAME_LEN)
if (newname && newname != "")
target.real_name = newname
target.SetName(target.real_name)
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index c4455231f2f..7157b1a2041 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -362,3 +362,22 @@ var/global/list/fruit_icon_cache = list()
user.visible_message(SPAN_DANGER("\The [user] reflexively hurls \the [src] at \the [aiming_at]!"))
user.throw_item(get_turf(aiming_at), src)
user.trigger_aiming(TARGET_CAN_CLICK)
+
+/obj/item/chems/food/proc/get_kitchen_tags()
+ if(dry)
+ LAZYADD(., "dried")
+
+/obj/item/chems/food/grown/get_kitchen_tags()
+ . = ..()
+ if(!seed)
+ return
+ if(seed.kitchen_tag)
+ LAZYADD(., seed.kitchen_tag)
+
+/obj/item/chems/food/fruit_slice/get_kitchen_tags()
+ . = ..()
+ if(!seed)
+ return
+ if(seed.kitchen_tag)
+ LAZYADD(., seed.kitchen_tag)
+ LAZYADD(., "slice")
diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm
index 7399286c58a..c8c6fb3d839 100644
--- a/code/modules/hydroponics/seed_datums.dm
+++ b/code/modules/hydroponics/seed_datums.dm
@@ -121,8 +121,8 @@
display_name = "poison berry bush"
mutants = list("deathberries")
chems = list(
- /decl/material/liquid/nutriment = list(1),
- /decl/material/liquid/bromide = list(3,5),
+ /decl/material/liquid/nutriment = list(1),
+ /decl/material/liquid/bromide = list(3,5),
/decl/material/liquid/poisonberryjuice = list(10,5)
)
@@ -138,8 +138,8 @@
display_name = "death berry bush"
mutants = null
chems = list(
- /decl/material/liquid/nutriment = list(1),
- /decl/material/liquid/bromide = list(3,3),
+ /decl/material/liquid/nutriment = list(1),
+ /decl/material/liquid/bromide = list(3,3),
/decl/material/gas/carbon_monoxide = list(1,5)
)
@@ -255,7 +255,7 @@
display_name = "quantumato plant"
mutants = null
chems = list(
- /decl/material/liquid/nutriment = list(1,20),
+ /decl/material/liquid/nutriment = list(1,20),
/decl/material/liquid/ethanol/bluecuracao = list(10,5)
)
@@ -339,10 +339,10 @@
display_name = "biteleaf patch"
mutants = list("biteleafdeus")
chems = list(
- /decl/material/liquid/nutriment = list(1),
- /decl/material/liquid/psychoactives = list(1,8),
- /decl/material/liquid/burn_meds = list(1,8,1),
- /decl/material/liquid/brute_meds = list(1,10,1),
+ /decl/material/liquid/nutriment = list(1),
+ /decl/material/liquid/psychoactives = list(1,8),
+ /decl/material/liquid/burn_meds = list(1,8,1),
+ /decl/material/liquid/brute_meds = list(1,10,1),
/decl/material/liquid/bromide = list(1,10)
)
kitchen_tag = "biteleaf"
@@ -365,11 +365,11 @@
display_name = "biteleaf deus patch"
mutants = null
chems = list(
- /decl/material/liquid/nutriment = list(1),
- /decl/material/liquid/brute_meds = list(1,8),
- /decl/material/liquid/antidepressants = list(1,8,1),
- /decl/material/liquid/stimulants = list(1,8,1),
- /decl/material/liquid/amphetamines = list(1,10,1),
+ /decl/material/liquid/nutriment = list(1),
+ /decl/material/liquid/brute_meds = list(1,8),
+ /decl/material/liquid/antidepressants = list(1,8,1),
+ /decl/material/liquid/stimulants = list(1,8,1),
+ /decl/material/liquid/amphetamines = list(1,10,1),
/decl/material/liquid/psychoactives = list(1,10)
)
kitchen_tag = "biteleafdeus"
@@ -693,6 +693,7 @@
name = "grapes"
seed_name = "grape"
display_name = "grapevine"
+ kitchen_tag = "grape"
mutants = list("greengrapes")
chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/nutriment/sugar = list(1,5), /decl/material/liquid/drink/juice/grape = list(10,10))
@@ -726,6 +727,7 @@
name = "peanut"
seed_name = "peanut"
display_name = "peanut vine"
+ kitchen_tag = "peanut"
chems = list(/decl/material/liquid/nutriment = list(1,10))
/datum/seed/peanuts/New()
@@ -1038,7 +1040,7 @@
name = "pumpkin"
seed_name = "pumpkin"
display_name = "pumpkin vine"
- chems = list(/decl/material/liquid/nutriment = list(1,6))
+ chems = list(/decl/material/liquid/nutriment = list(1,6), /decl/material/liquid/drink/juice/pumpkinpulp = list(1,6))
kitchen_tag = "pumpkin"
/datum/seed/pumpkin/New()
diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm
index b26333ad7fb..ace7d136f95 100644
--- a/code/modules/hydroponics/seed_packets.dm
+++ b/code/modules/hydroponics/seed_packets.dm
@@ -298,4 +298,4 @@ var/global/list/plant_seed_sprites = list()
seed_type = "mollusc"
/obj/item/seeds/cotton
- seed_type = "cotton"
+ seed_type = "cotton"
\ No newline at end of file
diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm
index 100bd0841bc..85612f1fba9 100644
--- a/code/modules/hydroponics/seed_storage.dm
+++ b/code/modules/hydroponics/seed_storage.dm
@@ -52,7 +52,7 @@
/obj/machinery/seed_storage/Destroy()
QDEL_NULL_LIST(piles)
- . = ..()
+ . = ..()
/obj/machinery/seed_storage/random // This is mostly for testing, but I guess admins could spawn it
name = "Random seed storage"
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index ec199c51c17..0b90c934657 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -103,6 +103,7 @@
/obj/effect/vine/Destroy()
wake_neighbors()
+ parent = null
STOP_PROCESSING(SSvines, src)
return ..()
diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm
index 965bbabe4d0..ad3ced9b6f8 100644
--- a/code/modules/hydroponics/spreading/spreading_growth.dm
+++ b/code/modules/hydroponics/spreading/spreading_growth.dm
@@ -51,6 +51,8 @@
return neighbors
/obj/effect/vine/Process()
+ if(QDELETED(src))
+ return PROCESS_KILL
var/turf/simulated/T = get_turf(src)
if(!istype(T))
return
@@ -59,7 +61,7 @@
adjust_health(-seed.handle_environment(T,T.return_air(),null,1))
if(health <= 0)
return
-
+
//Vine fight!
for(var/obj/effect/vine/other in T)
if(other.seed != seed)
@@ -89,7 +91,7 @@
var/list/neighbors = get_neighbors()
if(neighbors.len)
spread_to(pick(neighbors))
-
+
//Try to settle down
if(can_spawn_plant())
plant = new(T,seed)
@@ -143,6 +145,8 @@
if(!istype(check_turf))
continue
for(var/obj/effect/vine/neighbor in check_turf.contents)
+ if(QDELETED(neighbor))
+ continue
START_PROCESSING(SSvines, neighbor)
/obj/effect/vine/proc/targets_in_range()
@@ -151,6 +155,8 @@
if(!istype(check_turf))
continue
for(var/mob/living/M in check_turf.contents)
+ if(QDELETED(M))
+ continue
if(prob(5) || !M.skill_check(SKILL_BOTANY, SKILL_PROF))
targets |= M
if(targets.len)
diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm
index 7f1648be88e..7f4dc00f791 100644
--- a/code/modules/hydroponics/trays/tray_process.dm
+++ b/code/modules/hydroponics/trays/tray_process.dm
@@ -1,4 +1,6 @@
/obj/machinery/portable_atmospherics/hydroponics/Process()
+ if(QDELETED(src))
+ return PROCESS_KILL
// Handle nearby smoke if any.
for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
@@ -35,13 +37,13 @@
// If there is no seed data (and hence nothing planted),
// or the plant is dead, process nothing further.
if(!seed || dead)
- if(mechanical)
+ if(mechanical)
update_icon() //Harvesting would fail to set alert icons properly.
return
// Advance plant age.
var/cur_stage = get_overlay_stage()
- if(prob(30))
+ if(prob(30))
age += 1 * HYDRO_SPEED_MULTIPLIER
if(get_overlay_stage() != cur_stage)
needs_icon_update |= 1
diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm
index e32bf103579..fdf0eab8016 100644
--- a/code/modules/integrated_electronics/core/assemblies.dm
+++ b/code/modules/integrated_electronics/core/assemblies.dm
@@ -273,7 +273,7 @@
if(!check_interactivity(M))
return
var/input = input("What do you want to name this?", "Rename", src.name) as null|text
- input = sanitizeName(input,allow_numbers = 1)
+ input = sanitize_name(input,allow_numbers = 1)
if(!check_interactivity(M))
return
if(!QDELETED(src) && input)
diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm
index 1a9ae6f0f0a..f40b4a26518 100644
--- a/code/modules/integrated_electronics/core/integrated_circuit.dm
+++ b/code/modules/integrated_electronics/core/integrated_circuit.dm
@@ -112,7 +112,7 @@ a creative player the means to solve many problems. Circuits are held inside an
if(!check_interactivity(M))
return
- var/input = sanitizeName(input(M, "What do you want to name this?", "Rename", name) as null|text, allow_numbers = TRUE)
+ var/input = sanitize_name(input(M, "What do you want to name this?", "Rename", name) as null|text, allow_numbers = TRUE)
if(check_interactivity(M))
if(!input)
input = name
diff --git a/code/modules/integrated_electronics/core/saved_circuits.dm b/code/modules/integrated_electronics/core/saved_circuits.dm
index 33cd4d38c3f..8954b3217e5 100644
--- a/code/modules/integrated_electronics/core/saved_circuits.dm
+++ b/code/modules/integrated_electronics/core/saved_circuits.dm
@@ -52,7 +52,7 @@
var/init_name = initial(name)
// Validate name
if(component_params["name"])
- sanitizeName(component_params["name"],allow_numbers=TRUE)
+ sanitize_name(component_params["name"],allow_numbers=TRUE)
// Validate input values
if(component_params["inputs"])
var/list/loaded_inputs = component_params["inputs"]
@@ -138,7 +138,7 @@
/obj/item/electronic_assembly/proc/verify_save(list/assembly_params)
// Validate name and color
if(assembly_params["name"])
- if(sanitizeName(assembly_params["name"], allow_numbers = TRUE) != assembly_params["name"])
+ if(sanitize_name(assembly_params["name"], allow_numbers = TRUE) != assembly_params["name"])
return "Bad assembly name."
if(assembly_params["desc"])
if(sanitize(assembly_params["desc"]) != assembly_params["desc"])
diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm
index 3e83eeb0be4..527e5a11598 100644
--- a/code/modules/keybindings/bindings_atom.dm
+++ b/code/modules/keybindings/bindings_atom.dm
@@ -18,10 +18,8 @@
if(!config.allow_diagonal_movement)
if(movement_dir & user.last_move_dir_pressed)
movement_dir = user.last_move_dir_pressed
- else if (movement_dir == NORTHEAST || movement_dir == NORTHWEST)
- movement_dir = NORTH
- else if (movement_dir == SOUTHEAST || movement_dir == SOUTHWEST)
- movement_dir = SOUTH
+ else
+ movement_dir = FIRST_DIR(movement_dir)
if(movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise
movement_dir = turn(movement_dir, -dir2angle(user.dir)) //By doing this we ensure that our input direction is offset by the client (camera) direction
diff --git a/code/modules/keybindings/mob.dm b/code/modules/keybindings/mob.dm
index cb66eeb935d..5e19e0f97ad 100644
--- a/code/modules/keybindings/mob.dm
+++ b/code/modules/keybindings/mob.dm
@@ -137,6 +137,6 @@
full_name = "Move Down"
description = "Makes you go down"
-/datum/keybinding/mob/move_up/down(client/user)
+/datum/keybinding/mob/move_down/down(client/user)
var/mob/M = user.mob
- M.SelfMove(DOWN)
+ M.move_down()
diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm
index f528a278e5e..a1275b3565d 100644
--- a/code/modules/materials/_materials.dm
+++ b/code/modules/materials/_materials.dm
@@ -48,7 +48,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay)
DOORS
stone
metal
- resin
+ plastic
wood
*/
diff --git a/code/modules/materials/definitions/solids/materials_solid_mineral.dm b/code/modules/materials/definitions/solids/materials_solid_mineral.dm
index a967fd53285..b39e188490c 100644
--- a/code/modules/materials/definitions/solids/materials_solid_mineral.dm
+++ b/code/modules/materials/definitions/solids/materials_solid_mineral.dm
@@ -88,7 +88,7 @@
rich_material_weight = 1
dissolves_into = list(
/decl/material/solid/sulfur = 0.75,
- /decl/material/solid/metal/iron = 0.25
+ /decl/material/solid/metal/iron = 0.25
)
/decl/material/solid/spodumene
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index e922809f7c1..56fc1204354 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -218,7 +218,7 @@
stack_merge_type = /obj/item/stack/material/pane
/obj/item/stack/material/pane/update_state_from_amount()
- if(reinf_material)
+ if(reinf_material)
icon_state = "sheet-glass-reinf"
base_state = icon_state
plural_icon_state = "sheet-glass-reinf-mult"
diff --git a/code/modules/materials/recipes_furniture.dm b/code/modules/materials/recipes_furniture.dm
index 39ef009e977..656cf98da88 100644
--- a/code/modules/materials/recipes_furniture.dm
+++ b/code/modules/materials/recipes_furniture.dm
@@ -232,7 +232,7 @@
if(.)
for(var/obj/structure/window/check_window in user.loc)
if(check_window.is_fulltile())
- to_chat(user, "There is already a fll-tile window here!")
+ to_chat(user, SPAN_WARNING("There is already a full-tile window here!"))
return FALSE
/datum/stack_recipe/furniture/fullwindow/spawn_result(mob/user, location, amount)
diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm
index aabd07c9053..377ea917b89 100644
--- a/code/modules/mechs/components/body.dm
+++ b/code/modules/mechs/components/body.dm
@@ -167,7 +167,7 @@
var/obj/machinery/portable_atmospherics/canister/C = dropping
if(pilot_coverage < 100)
to_chat(user, SPAN_NOTICE("This type of chassis doesn't support internals."))
- return TRUE
+ return TRUE
if(!C.anchored && do_after(user, 5, src))
if(C.anchored)
return
diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/mech.dm
index 92873fa7f98..41801061217 100644
--- a/code/modules/mechs/mech.dm
+++ b/code/modules/mechs/mech.dm
@@ -12,7 +12,7 @@
status_flags = PASSEMOTES
a_intent = I_HURT
mob_size = MOB_SIZE_LARGE
- atom_flags = ATOM_FLAG_SHIELD_CONTENTS | ATOM_FLAG_NO_TEMP_CHANGE
+ atom_flags = ATOM_FLAG_SHIELD_CONTENTS | ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_BLOCK_DIAGONAL_FACING
meat_type = null
meat_amount = 0
diff --git a/code/modules/mechs/mech_movement.dm b/code/modules/mechs/mech_movement.dm
index 4347de5d8f6..634421e3086 100644
--- a/code/modules/mechs/mech_movement.dm
+++ b/code/modules/mechs/mech_movement.dm
@@ -20,7 +20,7 @@
pilot.up_hint.icon_state = "uphint[!!(B && TURF_IS_MIMICKING(B))]"
/mob/living/exosuit/can_ztravel()
- if(Process_Spacemove(1)) //Handle here
+ if(Process_Spacemove(1)) //Handle here
return TRUE
//Inertia drift making us face direction makes exosuit flight a bit difficult, plus newtonian flight model yo
@@ -37,7 +37,7 @@
//For swimming
// /mob/living/exosuit/can_float()
// return FALSE //Nope
-
+
/datum/movement_handler/mob/delay/exosuit
expected_host_type = /mob/living/exosuit
diff --git a/code/modules/mining/machinery/material_extractor.dm b/code/modules/mining/machinery/material_extractor.dm
index d3a2b6aaec3..f6a31b8dc93 100644
--- a/code/modules/mining/machinery/material_extractor.dm
+++ b/code/modules/mining/machinery/material_extractor.dm
@@ -12,7 +12,7 @@
var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
////////////////////////////////////////////////////
-// Holder for the reagents_holder.
+// Holder for the reagents_holder.
// Since reagents_holder can't exist on its own for some reasons
////////////////////////////////////////////////////
/obj/input_holder
@@ -85,14 +85,14 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
. = ..()
/obj/machinery/atmospherics/unary/material/extractor/Bumped(var/obj/O)
- if(QDELETED(O)) //Because we qdel object at the input if we can process them. And its possible this might happen
+ if(QDELETED(O)) //Because we qdel object at the input if we can process them. And its possible this might happen
return
//We only override for entities touching the machine from the input's direction only
if(get_dir(loc, O.loc) != get_input_dir() || inoperable() || !O.checkpass(PASS_FLAG_TABLE) || O.anchored)
return ..()
-
- //2 possible cases here. One we got something that we can turn into liquids or gas (with or without accompanying solid reagent at STP)
- // OR we get something that only contains matter that's solid at STP, which we should just pass along so whatever else is in the
+
+ //2 possible cases here. One we got something that we can turn into liquids or gas (with or without accompanying solid reagent at STP)
+ // OR we get something that only contains matter that's solid at STP, which we should just pass along so whatever else is in the
// conveyor line can process it.
if(can_process_object(O))
if(calc_resulting_reagents_total_vol(O) > input_tank_free_volume())
@@ -125,9 +125,9 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
if(output_container)
var/output_desc = SPAN_NOTICE("It has \a [output_container.name] in place to receive reagents.")
if(is_output_container_full())
- output_desc = "[output_desc] [SPAN_WARNING("It's full!")]"
+ output_desc = "[output_desc] [SPAN_WARNING("It's full!")]"
to_chat(user, output_desc)
- else
+ else
to_chat(user, SPAN_NOTICE("It has nothing to pour reagents into."))
/obj/machinery/atmospherics/unary/material/extractor/attackby(var/obj/item/I, var/mob/user)
@@ -157,11 +157,11 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
/obj/machinery/atmospherics/unary/material/extractor/on_update_icon()
cut_overlays()
-
+
var/initial_state = initial(icon_state)
if(!use_power || inoperable())
icon_state = "[initial_state]-off"
- else
+ else
icon_state = initial_state
if(panel_open)
@@ -226,7 +226,7 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
/obj/machinery/atmospherics/unary/material/extractor/proc/is_input_tank_empty()
return round(input_buffer.reagents.total_volume, GAS_EXTRACTOR_MIN_REAGENT_AMOUNT) == 0
-
+
/obj/machinery/atmospherics/unary/material/extractor/proc/is_internal_tank_full()
return internal_tank_free_volume() <= 0
@@ -279,7 +279,7 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
for(var/mat in input_buffer.reagents?.reagent_volumes)
var/decl/material/M = GET_DECL(mat)
var/available_volume = round(REAGENT_VOLUME(input_buffer.reagents, M.type), GAS_EXTRACTOR_MIN_REAGENT_AMOUNT)
-
+
//Don't bother if we got a really small quatity, and just get rid of it
if(available_volume < GAS_EXTRACTOR_MIN_REAGENT_AMOUNT)
input_buffer.reagents.clear_reagent(M.type)
@@ -332,12 +332,12 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
//We want to convert a liquid to its gaseous state
//So we want to convert liquid units to moles.
-// We need:
+// We need:
// the volume of liquid
// the density of the liquid
// the molar mass of the liquid
//Since we have none of those currently in the material datums, just assume everything is water
-// Density: 997.07 g/L
+// Density: 997.07 g/L
// Molar Mass: 18.02 g/mol
//We'll assume a unit of reagent is 1 mL, so we'll divide the density by 1,000. We get 0.99707
// 0.99707 / 18.02 => 0.553 mol/ml
@@ -400,7 +400,7 @@ var/global/list/material_extractor_items_whitelist = list(/obj/item/ore)
desc = "Empty the internal reagents tank on the floor."
call_proc = /obj/machinery/atmospherics/unary/material/extractor/verb/FlushReagents
-#undef GAS_EXTRACTOR_GAS_TANK
+#undef GAS_EXTRACTOR_GAS_TANK
#undef GAS_EXTRACTOR_REAGENTS_TANK
#undef GAS_EXTRACTOR_REAGENTS_INPUT_TANK
#undef GAS_EXTRACTOR_OPERATING_TEMP
diff --git a/code/modules/mining/machinery/material_smelter.dm b/code/modules/mining/machinery/material_smelter.dm
index c845b82ed6e..bd4368d0ea2 100644
--- a/code/modules/mining/machinery/material_smelter.dm
+++ b/code/modules/mining/machinery/material_smelter.dm
@@ -114,7 +114,7 @@
if(samt > 0)
SSmaterials.create_object(mtype, output_turf, samt)
reagents.remove_reagent(mtype, ramt)
-
+
/obj/machinery/material_processing/smeltery/Topic(var/user, var/list/href_list)
. = ..()
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 30987444d7f..7bd16cd5520 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -73,7 +73,7 @@ var/global/list/slot_equipment_priority = list( \
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W, var/skip_store = 0)
- if(!istype(W))
+ if(!istype(W))
return FALSE
for(var/slot in slot_equipment_priority)
if(skip_store)
@@ -252,12 +252,13 @@ var/global/list/slot_equipment_priority = list( \
//Attemps to remove an object on a mob.
/mob/proc/remove_from_mob(var/obj/O, var/atom/target)
if(!O) // Nothing to remove, so we succeed.
- return 1
- src.u_equip(O)
+ return TRUE
if (src.client)
src.client.screen -= O
O.reset_plane_and_layer()
O.screen_loc = null
+ if(!src.u_equip(O))
+ return TRUE
if(istype(O, /obj/item))
var/obj/item/I = O
if(target)
@@ -265,7 +266,7 @@ var/global/list/slot_equipment_priority = list( \
else
I.dropInto(loc)
I.dropped(src)
- return 1
+ return TRUE
/mob/proc/drop_held_items()
for(var/thing in get_held_items())
@@ -275,9 +276,9 @@ var/global/list/slot_equipment_priority = list( \
/mob/proc/get_equipped_item(var/slot)
SHOULD_CALL_PARENT(TRUE)
switch(slot)
- if(slot_back_str)
+ if(slot_back_str)
return back
- if(slot_wear_mask_str)
+ if(slot_wear_mask_str)
return wear_mask
/mob/proc/get_equipped_items(var/include_carried = 0)
diff --git a/code/modules/mob/language/alien/monkey.dm b/code/modules/mob/language/alien/monkey.dm
index 4e9c4da3312..a96393b5dbd 100644
--- a/code/modules/mob/language/alien/monkey.dm
+++ b/code/modules/mob/language/alien/monkey.dm
@@ -8,3 +8,4 @@
syllables = list("ook", "eek", "hiss", "gronk")
shorthand = "Ook"
hidden_from_codex = 1
+ flags = RESTRICTED
diff --git a/code/modules/mob/language/human/misc/legalese.dm b/code/modules/mob/language/human/misc/legalese.dm
index 729cee0401a..59811db1a2b 100644
--- a/code/modules/mob/language/human/misc/legalese.dm
+++ b/code/modules/mob/language/human/misc/legalese.dm
@@ -9,9 +9,9 @@
partial_understanding = list(
/decl/language/human/common = 10
)
+ flags = RESTRICTED
syllables = list(
"hitherto", "whereof", "hereunto", "deed", "hereinbefore", "whereas", "consensus", "nonwithstanding",
"exonerated", "effecuate", "accord", "caveat", "stipulation", "pledgee", "covenant", "rights",
"lawful", "suit of law", "sequestrator", "et al", "et", "ex", "quid", "bono", "quo", "pro", "ad"
)
-
\ No newline at end of file
diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm
index 8a62d6b72cc..db498351603 100644
--- a/code/modules/mob/language/synthetic.dm
+++ b/code/modules/mob/language/synthetic.dm
@@ -7,7 +7,7 @@
exclaim_verb = "whistles loudly"
colour = "changeling"
key = "6"
- flags = NO_STUTTER
+ flags = NO_STUTTER | RESTRICTED
syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz")
space_chance = 10
speech_sounds = list(
@@ -20,7 +20,7 @@
'sound/voice/eal/eal7.ogg',
'sound/voice/eal/eal8.ogg'
)
-
+
/decl/language/binary
name = "Robot Talk"
desc = "Most human facilities support free-use communications protocols and routing hubs for synthetic use."
diff --git a/code/modules/mob/living/carbon/human/descriptors/descriptors_age.dm b/code/modules/mob/living/carbon/human/descriptors/descriptors_age.dm
index 7d84653ec14..5578d2a661e 100644
--- a/code/modules/mob/living/carbon/human/descriptors/descriptors_age.dm
+++ b/code/modules/mob/living/carbon/human/descriptors/descriptors_age.dm
@@ -5,7 +5,7 @@
"a toddler" = 3,
"a child" = 7,
"a teenager" = 13,
- "a young adult" = 17,
+ "a young adult" = 18, // HEARTH OF HESTIA EDIT
"an adult" = 25,
"middle-aged" = 40,
"aging" = 55,
@@ -19,11 +19,11 @@
"somewhat younger than you",
"younger than you",
"much younger than you",
- "a child compared to you"
+ "very young compared to you" // HEARTH OF HESTIA EDIT
)
comparative_value_descriptors_larger = list(
"slightly older than you",
- "older than you",
+ "older than you",
"much older than you",
"ancient compared to you"
)
@@ -59,7 +59,7 @@
/datum/appearance_descriptor/age/get_min_chargen_value()
var/age_key = standalone_value_descriptors[chargen_min_index]
return standalone_value_descriptors[age_key]
-
+
/datum/appearance_descriptor/age/get_max_chargen_value()
var/age_key = standalone_value_descriptors[min(length(standalone_value_descriptors), chargen_max_index+1)]
. = standalone_value_descriptors[age_key]-1
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 384a6dbc3f2..bb12325ab39 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -55,6 +55,7 @@
global.human_mob_list -= src
worn_underwear = null
QDEL_NULL(attack_selector)
+ QDEL_NULL(vessel)
LAZYCLEARLIST(smell_cooldown)
. = ..()
QDEL_NULL_LIST(organs)
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 410759068b6..fd41a3cca19 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -320,6 +320,7 @@ This function restores all organs.
var/obj/item/organ/external/current_organ = organs_by_name[bodypart]
if(istype(current_organ))
current_organ.rejuvenate(ignore_prosthetic_prefs)
+ bad_external_organs.Cut() // otherwise hanging refs will prevent gc after rejuv
verbs -= /mob/living/carbon/human/proc/undislocate
/mob/living/carbon/human/proc/HealDamage(zone, brute, burn)
diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm
index ee12983abfc..ddbbd6bb8b9 100644
--- a/code/modules/mob/living/carbon/human/human_organs.dm
+++ b/code/modules/mob/living/carbon/human/human_organs.dm
@@ -8,7 +8,7 @@
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
-/mob/living/carbon/human/proc/recheck_bad_external_organs()
+/mob/living/carbon/human/proc/should_recheck_bad_external_organs()
var/damage_this_tick = getToxLoss()
for(var/obj/item/organ/external/O in organs)
damage_this_tick += O.burn_dam + O.brute_dam
@@ -17,20 +17,24 @@
. = TRUE
last_dam = damage_this_tick
+/mob/living/carbon/human/proc/recheck_bad_external_organs()
+ bad_external_organs.Cut()
+ for(var/obj/item/organ/external/E in organs)
+ if(!E || !E.need_process())
+ continue
+ bad_external_organs |= E
+
// Takes care of organ related updates, such as broken and missing limbs
/mob/living/carbon/human/proc/handle_organs()
-
- var/force_process = recheck_bad_external_organs()
-
- if(force_process)
- bad_external_organs.Cut()
- for(var/obj/item/organ/external/Ex in organs)
- bad_external_organs |= Ex
-
//processing internal organs is pretty cheap, do that first.
for(var/obj/item/organ/I in internal_organs)
I.Process()
+ var/force_process = should_recheck_bad_external_organs()
+
+ if(force_process)
+ recheck_bad_external_organs()
+
handle_stance()
handle_grasp()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index ed1ef2c9daf..63e5f2b17b4 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -693,7 +693,7 @@
healths_ma.icon_state = "blank"
healths_ma.overlays = null
- if(has_chemical_effect(CE_PAINKILLER, 100))
+ if(has_chemical_effect(CE_PAINKILLER, 400))
healths_ma.icon_state = "health_numb"
else
// Generate a by-limb health display.
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index 41884d7d012..ef5845b2ba9 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -60,6 +60,8 @@
if(!speaking)
if(istype(other, /mob/living/silicon))
return TRUE
+ if(istype(other, /mob/announcer))
+ return TRUE
if(istype(other, /mob/living/carbon/brain))
return TRUE
return ..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index e51ac679a09..b4e70e70177 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -244,7 +244,11 @@ Please contact me on #coderbus IRC. ~Carn x
else
M.Scale(desired_scale_x, desired_scale_y)
M.Translate(0, 16*(desired_scale_y-1))
- animate(src, transform = M, time = transform_animate_time)
+ if(transform_animate_time)
+ animate(src, transform = M, time = transform_animate_time)
+ else
+ transform = M
+ return transform
var/global/list/damage_icon_parts = list()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 7b2a2786126..7ce30552a97 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -569,10 +569,6 @@ default behaviour is:
to_chat(src, "You extricate yourself from \the [holster].")
H.forceMove(get_turf(H))
else if(istype(H.loc,/obj))
- if(istype(H.loc, /obj/machinery/cooker))
- var/obj/machinery/cooker/C = H.loc
- C.cooking_obj = null
- C.check_cooking_obj()
to_chat(src, "You struggle free of \the [H.loc].")
H.forceMove(get_turf(H))
diff --git a/code/modules/mob/living/silicon/ai/power.dm b/code/modules/mob/living/silicon/ai/power.dm
index d63b67ad527..99dea1409d1 100644
--- a/code/modules/mob/living/silicon/ai/power.dm
+++ b/code/modules/mob/living/silicon/ai/power.dm
@@ -133,6 +133,7 @@
/mob/living/silicon/ai/proc/update_power_usage()
var/newusage = calculate_power_usage()
newusage *= AI_POWERUSAGE_OXYLOSS_TO_WATTS_MULTIPLIER
+ newusage = newusage / 2
if(psupply)
psupply.change_power_consumption(newusage, POWER_USE_ACTIVE)
psupply.update_power_state()
diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm
index ad11c22e560..da9259ba3f4 100644
--- a/code/modules/mob/living/silicon/pai/recruit.dm
+++ b/code/modules/mob/living/silicon/pai/recruit.dm
@@ -65,7 +65,7 @@ var/global/datum/paiController/paiController // Global handler for pAI candida
switch(option)
if("name")
- t = sanitizeSafe(input("Enter a name for your pAI", "pAI Name", candidate.name) as text, MAX_NAME_LEN)
+ t = sanitize_safe(input("Enter a name for your pAI", "pAI Name", candidate.name) as text, MAX_NAME_LEN)
if(t)
candidate.name = t
if("desc")
@@ -94,7 +94,7 @@ var/global/datum/paiController/paiController // Global handler for pAI candida
candidate.savefile_load(usr)
//In case people have saved unsanitized stuff.
if(candidate.name)
- candidate.name = sanitizeSafe(candidate.name, MAX_NAME_LEN)
+ candidate.name = sanitize_safe(candidate.name, MAX_NAME_LEN)
if(candidate.description)
candidate.description = sanitize(candidate.description)
if(candidate.role)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 716e49ae3cb..6a5c8735375 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -326,7 +326,7 @@
spawn(0)
var/newname
- newname = sanitizeName(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN, allow_numbers = 1)
+ newname = sanitize_name(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN, allow_numbers = 1)
if (newname)
custom_name = newname
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index 2ee77af149c..31261bd5f2d 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -206,7 +206,7 @@
/obj/item/pen/robopen/proc/RenamePaper(mob/user, obj/item/paper/paper)
if ( !user || !paper )
return
- var/n_name = sanitizeSafe(input(user, "What would you like to label the paper?", "Paper Labelling", null) as text, 32)
+ var/n_name = sanitize_safe(input(user, "What would you like to label the paper?", "Paper Labelling", null) as text, 32)
if ( !user || !paper )
return
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 7022ad9edb8..33c43b92118 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -127,7 +127,7 @@
/mob/living/simple_animal/cat/hitby(atom/movable/AM, var/datum/thrownthing/TT)
. = ..()
set_flee_target(TT.thrower? TT.thrower : src.loc)
-
+
/mob/living/simple_animal/cat/harvest_skin()
. = ..()
. += new/obj/item/cat_hide(get_turf(src))
@@ -136,7 +136,7 @@
name = "cat hide"
desc = "The by-product of cat farming."
icon = 'icons/obj/items/sheet_hide.dmi'
- icon_state = "sheet-cat"
+ icon_state = "sheet-cat"
//Basic friend AI
/mob/living/simple_animal/cat/fluff
@@ -144,7 +144,7 @@
var/befriend_job = null
/mob/living/simple_animal/cat/fluff/handle_movement_target()
- if (friend)
+ if (!QDELETED(friend))
var/follow_dist = 4
if (friend.stat >= DEAD || friend.is_asystole()) //danger
follow_dist = 1
@@ -172,12 +172,12 @@
if (prob(10))
say("Meow!")
- if (!friend || movement_target != friend)
+ if (QDELETED(friend) || movement_target != friend)
..()
/mob/living/simple_animal/cat/fluff/do_delayed_life_action()
..()
- if (stat || !friend)
+ if (stat || QDELETED(friend))
return
if (get_dist(src, friend) <= 1)
if (friend.stat >= DEAD || friend.is_asystole())
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index 2d71665bb3d..92dc41cdb89 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -114,6 +114,10 @@
. = ..()
udder = new(50, src)
+/mob/living/simple_animal/cow/Destroy()
+ QDEL_NULL(udder)
+ . = ..()
+
/mob/living/simple_animal/cow/attackby(var/obj/item/O, var/mob/user)
var/obj/item/chems/glass/G = O
if(stat == CONSCIOUS && istype(G) && ATOM_IS_OPEN_CONTAINER(G))
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm
index ddc66701420..f1bcae968bf 100644
--- a/code/modules/mob/living/simple_animal/hostile/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bat.dm
@@ -25,6 +25,10 @@
if(istype(L))
owner = L
+/mob/living/simple_animal/hostile/scarybat/Destroy()
+ owner = null
+ return ..()
+
/mob/living/simple_animal/hostile/scarybat/FindTarget()
. = ..()
if(.)
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index 12563ab518e..6a03420ecf4 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -45,9 +45,10 @@
/mob/living/simple_animal/hostile/carp/on_update_icon()
. = ..()
color = carp_color
- var/image/I = image(icon, "[icon_state]-eyes")
- I.appearance_flags |= RESET_COLOR
- add_overlay(I)
+ if(check_state_in_icon("[icon_state]-eyes", icon))
+ var/image/I = image(icon, "[icon_state]-eyes")
+ I.appearance_flags |= RESET_COLOR
+ add_overlay(I)
/mob/living/simple_animal/hostile/carp/Process_Spacemove()
return 1 //No drifting in space for space carp! //original comments do not steal
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 5c8e8326809..b72eb4b9b9c 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -43,6 +43,11 @@
/obj/structure/wall_frame,
/obj/structure/railing)
+/mob/living/simple_animal/hostile/Destroy()
+ LAZYCLEARLIST(friends)
+ target_mob = null
+ return ..()
+
/mob/living/simple_animal/hostile/proc/can_act()
if(QDELETED(src) || stat || stop_automation || incapacitated())
return FALSE
@@ -101,7 +106,7 @@
walk_to(src, pick(orange(2, src)), 1, move_to_delay)
return
stop_automated_movement = 1
- if(!target_mob || SA_attackable(target_mob))
+ if(QDELETED(target_mob) || SA_attackable(target_mob))
stance = HOSTILE_STANCE_IDLE
if(target_mob in ListTargets(10))
if(ranged)
@@ -240,18 +245,10 @@
visible_message("\The [src] [fire_desc] at \the [target]!", 1)
if(rapid)
- spawn(1)
- Shoot(target, src.loc, src)
- if(casingtype)
- new casingtype(get_turf(src))
- spawn(4)
- Shoot(target, src.loc, src)
- if(casingtype)
- new casingtype(get_turf(src))
- spawn(6)
- Shoot(target, src.loc, src)
- if(casingtype)
- new casingtype(get_turf(src))
+ var/datum/callback/shoot_cb = CALLBACK(src, .proc/shoot_wrapper, target, loc, src)
+ addtimer(shoot_cb, 1)
+ addtimer(shoot_cb, 4)
+ addtimer(shoot_cb, 6)
else
Shoot(target, src.loc, src)
if(casingtype)
@@ -261,6 +258,11 @@
target_mob = null
return
+/mob/living/simple_animal/hostile/proc/shoot_wrapper(target, location, user)
+ Shoot(target, location, user)
+ if (casingtype)
+ new casingtype(loc)
+
/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
index 23b1066fec8..d4a4a3a4dc1 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
@@ -171,6 +171,7 @@
qdel(src)
/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy()
+ QDEL_NULL(ion_trail)
//some random debris left behind
if(has_loot)
spark_at(src, cardinal_only = TRUE)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/exoplanet.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/exoplanet.dm
index cdedbc02ef3..24614b53cdf 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/exoplanet.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/exoplanet.dm
@@ -54,7 +54,7 @@
for(var/obj/effect/overmap/visitable/sector/exoplanet/E)
if(src in E.animals)
var/newname = input("What do you want to name this species?", "Species naming", E.get_random_species_name()) as text|null
- newname = sanitizeName(newname, allow_numbers = TRUE, force_first_letter_uppercase = FALSE)
+ newname = sanitize_name(newname, allow_numbers = TRUE, force_first_letter_uppercase = FALSE)
if(newname && CanInteract(usr, global.conscious_topic_state))
if(E.rename_species(type, newname))
to_chat(usr,"This species will be known from now on as '[newname]'.")
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm
index 21bb73a44ce..70a67a3ba7c 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm
@@ -104,6 +104,15 @@
update_icon()
+/mob/living/simple_animal/hostile/retaliate/parrot/Destroy()
+ QDEL_NULL(ears)
+ parrot_interest = null
+ parrot_perch = null
+ if(held_item)
+ held_item.dropInto(loc)
+ held_item = null
+ return ..()
+
/mob/living/simple_animal/hostile/retaliate/parrot/death(gibbed, deathmessage, show_dead_message)
if(held_item)
held_item.dropInto(loc)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
index dca1f4ee607..4c0ea689fc7 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
@@ -1,6 +1,10 @@
/mob/living/simple_animal/hostile/retaliate
var/list/enemies = list()
+/mob/living/simple_animal/hostile/retaliate/Destroy()
+ LAZYCLEARLIST(enemies)
+ return ..()
+
/mob/living/simple_animal/hostile/retaliate/Found(var/atom/A)
if(isliving(A))
var/mob/living/L = A
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 7909b011cfa..73e9a16cdb4 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -85,10 +85,12 @@
if(eyeobj)
eyeobj.possess(src)
- client.update_skybox(1)
events_repository.raise_event(/decl/observ/logged_in, src)
hud_reset(TRUE)
+
+ client.update_skybox(1)
+
if(machine)
machine.on_user_login(src)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 508a1eb99e9..e3617cd0a15 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -19,18 +19,18 @@
clear_fullscreen()
if(istype(ai))
QDEL_NULL(ai)
+ remove_screen_obj_references()
if(client)
- remove_screen_obj_references()
for(var/atom/movable/AM in client.screen)
var/obj/screen/screenobj = AM
- if(!istype(screenobj) || !screenobj.globalscreen)
+ if(istype(screenobj) && !screenobj.globalscreen)
qdel(screenobj)
client.screen = list()
- if(mind && mind.current == src)
- spellremove(src)
+ if(mind)
+ mind.handle_mob_deletion(src)
+ teleop = null
ghostize()
- ..()
- return QDEL_HINT_HARDDEL
+ return ..()
/mob/proc/remove_screen_obj_references()
hands = null
@@ -45,9 +45,12 @@
healths = null
throw_icon = null
nutrition_icon = null
+ hydration_icon = null
pressure = null
pain = null
+ up_hint = null
item_use_icon = null
+ radio_use_icon = null
gun_move_icon = null
gun_setting_icon = null
ability_master = null
@@ -224,6 +227,8 @@
/mob/proc/Life()
SHOULD_NOT_SLEEP(TRUE)
+ if(QDELETED(src))
+ return PROCESS_KILL
if(ability_master)
ability_master.update_spells(0)
@@ -1032,7 +1037,7 @@
return
client.mouse_pointer_icon = initial(client.mouse_pointer_icon)
-
+
if(examine_cursor_icon && client.keys_held["Shift"])
client.mouse_pointer_icon = examine_cursor_icon
@@ -1081,11 +1086,11 @@
var/turf/T = loc
// We're inside something else.
- if(!istype(T))
+ if(!istype(T))
return WEATHER_PROTECTED
-
+
// Either we're outside being rained on, or we're in turf-local weather being rained on.
- if(T.is_outside() || T.weather == weather)
+ if(T.is_outside() || T.weather == weather)
var/list/weather_protection = get_weather_protection()
if(LAZYLEN(weather_protection))
return WEATHER_PROTECTED
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index d5c2f3cd246..af4c60d9cb0 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -58,7 +58,6 @@
var/obj/screen/gun/item/item_use_icon = null
var/obj/screen/gun/radio/radio_use_icon = null
var/obj/screen/gun/move/gun_move_icon = null
- var/obj/screen/gun/run/gun_run_icon = null
var/obj/screen/gun/mode/gun_setting_icon = null
var/obj/screen/movable/ability_master/ability_master = null
@@ -136,8 +135,8 @@
var/blinded = null
//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition)
- var/weakref/last_handled_by_mob
-
+ var/weakref/last_handled_by_mob
+
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/update_icon = 1 //Set to 1 to trigger update_icon() at the next life() call
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index bc3c614bc38..bfa3f26f8ed 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -26,6 +26,10 @@
forceMove(null)
verbs += /mob/proc/toggle_antag_pool
+/mob/new_player/Destroy()
+ panel = null
+ . = ..()
+
/mob/new_player/proc/show_lobby_menu(force = FALSE)
if(!SScharacter_setup.initialized && !force)
return // Not ready yet.
@@ -54,7 +58,7 @@
panel = new(src, "Welcome","Welcome to [global.using_map.full_name]", 560, 280, src)
panel.set_window_options("can_close=0")
panel.set_content(JOINTEXT(output))
- panel.open()
+ panel.open(FALSE)
/mob/new_player/Stat()
. = ..()
@@ -341,7 +345,7 @@
dat = header + dat
var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 450, 640)
popup.set_content(jointext(dat, null))
- popup.open(0)
+ popup.open(FALSE)
/mob/new_player/proc/create_character(var/turf/spawn_turf)
spawning = 1
@@ -410,7 +414,7 @@
//show_browser(src, dat, "window=manifest;size=370x420;can_close=1")
var/datum/browser/popup = new(src, "Crew Manifest", "Crew Manifest", 370, 420, src)
popup.set_content(dat)
- popup.open()
+ popup.open(FALSE)
/mob/new_player/Move()
return 0
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index 72609f783bb..9f198bde157 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -94,7 +94,7 @@
update_icon = TRUE
if(update_icon)
- mannequin.update_icon()
+ mannequin.refresh_visible_overlays()
/datum/preferences/proc/update_preview_icon()
var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey)
diff --git a/code/modules/mob/observer/eye/blueprints_eye.dm b/code/modules/mob/observer/eye/blueprints_eye.dm
index ffbb8715edc..9bbd541ac19 100644
--- a/code/modules/mob/observer/eye/blueprints_eye.dm
+++ b/code/modules/mob/observer/eye/blueprints_eye.dm
@@ -52,7 +52,7 @@
. = ..()
/mob/observer/eye/blueprints/proc/create_area()
- var/area_name = sanitizeSafe(input("New area name:","Area Creation", ""), MAX_NAME_LEN)
+ var/area_name = sanitize_safe(input("New area name:","Area Creation", ""), MAX_NAME_LEN)
if(!area_name || !length(area_name))
return
if(length(area_name) > 50)
@@ -89,7 +89,7 @@
if(!check_modification_validity())
return
var/prevname = A.name
- var/new_area_name = sanitizeSafe(input("Edit area name:","Area Editing", prevname), MAX_NAME_LEN)
+ var/new_area_name = sanitize_safe(input("Edit area name:","Area Editing", prevname), MAX_NAME_LEN)
if(!new_area_name || !LAZYLEN(new_area_name) || new_area_name==prevname)
return
if(length(new_area_name) > 50)
diff --git a/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm b/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm
index e6d1b671cb5..5d1a810562f 100644
--- a/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm
+++ b/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm
@@ -84,7 +84,7 @@
if(force_synth || issynth)
to_chat(user, SPAN_WARNING("You send an activation signal to \the [assembly_name], but it does not respond."))
else
- to_chat(user, SPAN_WARNING("You press the power button but \the [assembly_name], does not respond."))
+ to_chat(user, SPAN_WARNING("You press the power button but \the [assembly_name] does not respond."))
shutdown_device()
/datum/extension/assembly/modular_computer/shutdown_device()
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index 4c099ded936..6adc6d9f51a 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -1,3 +1,9 @@
+/obj/item/modular_computer/get_contained_external_atoms()
+ . = ..()
+ var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly)
+ if(assembly)
+ LAZYREMOVE(., assembly.parts)
+
/obj/item/modular_computer/Process()
var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly)
if(assembly)
diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm
index d47d9727888..ee2d1ae7109 100644
--- a/code/modules/modular_computers/file_system/programs/command/card.dm
+++ b/code/modules/modular_computers/file_system/programs/command/card.dm
@@ -206,7 +206,7 @@
if(computer && can_run(user, 1))
var/static/regex/hash_check = regex(@"^[0-9a-fA-F]{32}$")
if(href_list["name"])
- var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE)
+ var/temp_name = sanitize_name(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE)
if(temp_name && CanUseTopic(user))
id_card.registered_name = temp_name
id_card.formal_name_suffix = initial(id_card.formal_name_suffix)
diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
index b046ffd5b01..995e5504edf 100644
--- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
@@ -70,7 +70,7 @@
if(href_list["PRG_newchannel"])
. = 1
var/mob/living/user = usr
- var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64)
+ var/channel_title = sanitize_safe(input(user,"Enter channel name or leave blank to cancel:"), 64)
if(!channel_title)
return
var/datum/chat_conversation/C = new/datum/chat_conversation(network)
diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm
index 5f9c37cf0ee..41aa43a65a5 100644
--- a/code/modules/modular_computers/hardware/_hardware.dm
+++ b/code/modules/modular_computers/hardware/_hardware.dm
@@ -30,6 +30,8 @@
/obj/item/stock_parts/computer/Destroy()
if(istype(loc, /obj/item/modular_computer))
var/datum/extension/assembly/modular_computer/assembly = get_extension(loc, /datum/extension/assembly)
+ if(assembly.is_critical_part(src))
+ assembly.shutdown_device() // avoid the critical failure message
if(assembly)
assembly.uninstall_component(null, src)
return ..()
diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm
index 23fc33db210..d53025c98d9 100644
--- a/code/modules/modular_computers/laptop_vendor.dm
+++ b/code/modules/modular_computers/laptop_vendor.dm
@@ -127,7 +127,7 @@
var/datum/extension/assembly/modular_computer/assembly
if(fabricate)
fabricated_tablet = new(src)
- assembly = get_extension(fabricated_laptop, /datum/extension/assembly)
+ assembly = get_extension(fabricated_tablet, /datum/extension/assembly)
assembly.add_replace_component(null, PART_CPU, new/obj/item/stock_parts/computer/processor_unit/small(fabricated_tablet))
total_price = 199
switch(dev_battery)
diff --git a/code/modules/modular_computers/networking/machinery/mainframe.dm b/code/modules/modular_computers/networking/machinery/mainframe.dm
index 9aded3f8938..e39c4268130 100644
--- a/code/modules/modular_computers/networking/machinery/mainframe.dm
+++ b/code/modules/modular_computers/networking/machinery/mainframe.dm
@@ -20,6 +20,7 @@
. = ..()
var/datum/extension/network_device/mainframe/M = get_extension(src, /datum/extension/network_device)
M.roles |= initial_roles
+ M.update_roles()
/obj/machinery/network/mainframe/ui_data(mob/user, ui_key)
var/data = ..()
diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm
index f63402c8eab..1360d30d76a 100644
--- a/code/modules/multiz/movement.dm
+++ b/code/modules/multiz/movement.dm
@@ -8,11 +8,14 @@
set name = "Move Down"
set category = "IC"
- SelfMove(DOWN)
+ move_down()
/mob/proc/move_up()
SelfMove(UP)
+/mob/proc/move_down()
+ SelfMove(DOWN)
+
/mob/living/carbon/human/move_up()
var/turf/old_loc = loc
..()
@@ -148,7 +151,7 @@
for(var/atom/A in below)
if(!A.CanPass(src, location_override))
return FALSE
-
+
//We cannot sink if we can swim
if(location_override.get_fluid_depth() >= FLUID_DEEP && (below == loc))
if(!(below.get_fluid_depth() >= 0.95 * FLUID_MAX_DEPTH)) //No salmon skipping up a stream of falling water
diff --git a/code/modules/organs/ailments/_ailment.dm b/code/modules/organs/ailments/_ailment.dm
index 0439d84f672..0d5c501b7ec 100644
--- a/code/modules/organs/ailments/_ailment.dm
+++ b/code/modules/organs/ailments/_ailment.dm
@@ -3,7 +3,7 @@
var/timer_id // Current timer waiting to proc next symptom message.
var/min_time = 2 MINUTES // Minimum time between symptom messages.
var/max_time = 5 MINUTES // Maximum time between symptom messages.
- var/category = /datum/ailment // Used similar to heirarchies, if category == type then the
+ var/category = /datum/ailment // Used similar to hierarchies, if category == type then the
// ailment is a category and won't be applied to organs.
var/obj/item/organ/organ // Organ associated with the ailment (ailment is in organ.ailments list).
@@ -13,16 +13,18 @@
var/specific_organ_subtype = /obj/item/organ/external // What organ subtype, if any, does the ailment apply to?
// Treatment types
- var/treated_by_item_type // What item type can be used in physical interaction to cure the ailment?
- var/treated_by_item_cost = 1 // If treated_by_item_type is a stack, how many should be used?
- var/treated_by_reagent_type // What reagent type cures this ailment when metabolized?
- var/treated_by_reagent_dosage = 1 // What is the minimum dosage for a reagent to cure this ailment?
+ var/treated_by_item_type // What item type can be used in physical interaction to cure the ailment?
+ var/treated_by_item_cost = 1 // If treated_by_item_type is a stack, how many should be used?
+ var/treated_by_reagent_type // What reagent type cures this ailment when metabolized?
+ var/treated_by_reagent_dosage = 1 // What is the minimum dosage for a reagent to cure this ailment?
+ var/treated_by_chem_effect // What chemical effect cures this ailment?
+ var/treated_by_chem_effect_strength = 1 // How strong must the chemical effect be to cure this ailment?
// Fluff strings
var/initial_ailment_message = "Your $ORGAN$ doesn't feel quite right..." // Shown in New()
- var/third_person_treatement_message = "$USER$ treats $TARGET$'s ailment with $ITEM$." // Shown when treating other with an item.
- var/self_treatement_message = "$USER$ treats $USER_HIS$ ailment with $ITEM$." // Shown when treating self with an item.
- var/medication_treatment_message = "Your ailment abates." // Shown when treated by a metabolized reagent.
+ var/third_person_treatment_message = "$USER$ treats $TARGET$'s ailment with $ITEM$." // Shown when treating other with an item.
+ var/self_treatment_message = "$USER$ treats $USER_HIS$ ailment with $ITEM$." // Shown when treating self with an item.
+ var/medication_treatment_message = "Your ailment abates." // Shown when treated by a metabolized reagent or CE_X effect.
var/manual_diagnosis_string /* ex: "$USER_HIS$ $ORGAN$ has something wrong with it" */ // Shown when grab-diagnosed by a doctor. Leave null to be undiagnosable.
var/scanner_diagnosis_string /* ex: "Significant swelling" */ // Shown on the handheld and body scanners. Leave null to be undiagnosable.
@@ -31,7 +33,7 @@
if(_organ)
organ = _organ
if(organ.owner)
- to_chat(organ.owner, SPAN_WARNING(capitalize(replacetext(initial_ailment_message, "$ORGAN$", organ.name))))
+ to_chat(organ.owner, SPAN_WARNING(replace_tokens(initial_ailment_message)))
begin_ailment_event()
/datum/ailment/proc/can_apply_to(var/obj/item/organ/_organ)
@@ -83,13 +85,13 @@
/datum/ailment/proc/was_treated_by_item(var/obj/item/treatment, var/mob/user, var/mob/target)
var/show_message
- if(user == target && self_treatement_message)
- show_message = self_treatement_message
+ if(user == target && self_treatment_message)
+ show_message = self_treatment_message
else
- show_message = third_person_treatement_message
+ show_message = third_person_treatment_message
if(!show_message)
return
-
+
user.visible_message(SPAN_NOTICE(replace_tokens(show_message, treatment, user, target)))
if(istype(treatment, /obj/item/stack))
@@ -100,7 +102,11 @@
/datum/ailment/proc/treated_by_medication(var/decl/material/reagent, var/dosage)
return treated_by_reagent_type && istype(reagent, treated_by_reagent_type) && dosage >= treated_by_reagent_dosage
-/datum/ailment/proc/was_treated_by_medication(var/datum/reagents/dose)
- dose.remove_reagent(treated_by_reagent_type, treated_by_reagent_dosage)
- to_chat(organ.owner, SPAN_NOTICE(capitalize(replacetext(medication_treatment_message, "$ORGAN$", organ.name))))
+/datum/ailment/proc/was_treated_by_medication(var/datum/reagents/source, var/reagent_type)
+ source.remove_reagent(reagent_type, treated_by_reagent_dosage)
+ to_chat(organ.owner, SPAN_NOTICE(replace_tokens(medication_treatment_message)))
+ qdel(src)
+
+/datum/ailment/proc/was_treated_by_chem_effect()
+ to_chat(organ.owner, SPAN_NOTICE(replace_tokens(medication_treatment_message)))
qdel(src)
diff --git a/code/modules/organs/ailments/ailments_medical.dm b/code/modules/organs/ailments/ailments_medical.dm
index f4c3d091ec9..694165ff25f 100644
--- a/code/modules/organs/ailments/ailments_medical.dm
+++ b/code/modules/organs/ailments/ailments_medical.dm
@@ -4,8 +4,8 @@
/datum/ailment/head/headache
name = "headache"
- treated_by_reagent_type = /decl/material/liquid/painkillers
- treated_by_reagent_dosage = 1
+ treated_by_chem_effect = CE_PAINKILLER
+ treated_by_chem_effect_strength = 25
medication_treatment_message = "Your headache grudgingly fades away."
/datum/ailment/head/headache/on_ailment_event()
@@ -55,8 +55,8 @@
name = "sprained limb"
applies_to_organ = list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
treated_by_item_type = /obj/item/stack/medical/bruise_pack
- third_person_treatement_message = "$USER$ wraps $TARGET$'s sprained $ORGAN$ in $ITEM$."
- self_treatement_message = "$USER$ wraps $USER_HIS$ sprained $ORGAN$ in $ITEM$."
+ third_person_treatment_message = "$USER$ wraps $TARGET$'s sprained $ORGAN$ in $ITEM$."
+ self_treatment_message = "$USER$ wraps $USER_HIS$ sprained $ORGAN$ in $ITEM$."
manual_diagnosis_string = "$USER_HIS$ $ORGAN$ is visibly swollen."
/datum/ailment/sprain/on_ailment_event()
@@ -69,21 +69,21 @@
/datum/ailment/rash
name = "rash"
treated_by_item_type = /obj/item/stack/medical/ointment
- third_person_treatement_message = "$USER$ salves $TARGET$'s rash-stricken $ORGAN$ with $ITEM$."
- self_treatement_message = "$USER$ salves $USER_HIS$ rash-stricken $ORGAN$ with $ITEM$."
+ third_person_treatment_message = "$USER$ salves $TARGET$'s rash-stricken $ORGAN$ with $ITEM$."
+ self_treatment_message = "$USER$ salves $USER_HIS$ rash-stricken $ORGAN$ with $ITEM$."
manual_diagnosis_string = "$USER_HIS$ $ORGAN$ is covered in a bumpy red rash."
/datum/ailment/rash/on_ailment_event()
to_chat(organ.owner, SPAN_DANGER("A bright red rash on your [organ.name] itches distractingly."))
organ.owner.setClickCooldown(3)
-
+
/datum/ailment/coughing
name = "coughing"
specific_organ_subtype = /obj/item/organ/internal/lungs
applies_to_organ = list(BP_LUNGS)
treated_by_reagent_type = /decl/material/liquid/antiseptic
- medication_treatment_message = "The tickling in your throat fades away."
- manual_diagnosis_string = "$USER_HIS$ throat is red and inflamed."
+ medication_treatment_message = "Your lungs no longer ache."
+ scanner_diagnosis_string = "$USER$ displays some inflammation in $USER_HIS$ lungs."
/datum/ailment/coughing/can_apply_to(obj/item/organ/_organ)
. = ..()
@@ -97,7 +97,8 @@
/datum/ailment/sore_joint
name = "sore joint"
- treated_by_reagent_type = /decl/material/liquid/painkillers
+ treated_by_chem_effect = CE_PAINKILLER
+ treated_by_chem_effect_strength = 25
medication_treatment_message = "The dull pulse of pain in your $ORGAN$ fades away."
manual_diagnosis_string = "$USER_HIS$ $ORGAN$ is visibly swollen."
@@ -115,7 +116,8 @@
/datum/ailment/sore_back
name = "sore back"
applies_to_organ = list(BP_CHEST)
- treated_by_reagent_type = /decl/material/liquid/painkillers
+ treated_by_chem_effect = CE_PAINKILLER
+ treated_by_chem_effect_strength = 25
medication_treatment_message = "You straighten, finding that your back is no longer hurting."
/datum/ailment/sore_back/on_ailment_event()
@@ -128,6 +130,7 @@
applies_to_organ = list(BP_STOMACH)
treated_by_reagent_type = /decl/material/solid/carbon
medication_treatment_message = "The nausea in your $ORGAN$ slowly fades away."
+ scanner_diagnosis_string = "$USER$'s $ORGAN$ appears inflamed."
/datum/ailment/stomach_ache/on_ailment_event()
to_chat(organ.owner, SPAN_DANGER("Your stomach roils unpleasantly."))
@@ -135,7 +138,7 @@
/datum/ailment/cramps
name = "cramps"
- treated_by_reagent_type = /decl/material/liquid/painkillers
+ treated_by_reagent_type = /decl/material/liquid/sedatives // in lieu of muscle relaxants
medication_treatment_message = "The painful cramping in your $ORGAN$ relaxes."
/datum/ailment/cramps/on_ailment_event()
diff --git a/code/modules/organs/ailments/faults/_fault.dm b/code/modules/organs/ailments/faults/_fault.dm
index 563948419c3..589d3759664 100644
--- a/code/modules/organs/ailments/faults/_fault.dm
+++ b/code/modules/organs/ailments/faults/_fault.dm
@@ -3,6 +3,6 @@
category = /datum/ailment/fault
treated_by_item_type = /obj/item/stack/nanopaste
treated_by_item_cost = 3
- third_person_treatement_message = "$USER$ patches $TARGET$'s faulty $ORGAN$ with $ITEM$."
- self_treatement_message = "$USER$ patches $USER_HIS$'s faulty $ORGAN$ with $ITEM$."
+ third_person_treatment_message = "$USER$ patches $TARGET$'s faulty $ORGAN$ with $ITEM$."
+ self_treatment_message = "$USER$ patches $USER_HIS$'s faulty $ORGAN$ with $ITEM$."
initial_ailment_message = "Damage to your $ORGAN$ has caused a fault..."
diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm
index 622aa1969fb..04ad984c161 100644
--- a/code/modules/organs/external/_external.dm
+++ b/code/modules/organs/external/_external.dm
@@ -137,6 +137,7 @@
if(owner)
owner.organs -= src
owner.organs_by_name -= organ_tag
+ owner.bad_external_organs -= src
LAZYCLEARLIST(autopsy_data)
QDEL_NULL_LIST(implants)
@@ -1170,7 +1171,7 @@ Note that amputating the affected organ does in fact remove the infection from t
if(!ispath(company, /decl/prosthetics_manufacturer))
PRINT_STACK_TRACE("Limb [type] robotize() was supplied a null or non-decl manufacturer: '[company]'")
company = /decl/prosthetics_manufacturer
-
+
var/decl/prosthetics_manufacturer/R = GET_DECL(company)
if(!R.check_can_install(organ_tag, (owner?.get_bodytype_category() || global.using_map.default_bodytype), (owner?.get_species_name() || global.using_map.default_species)))
R = GET_DECL(/decl/prosthetics_manufacturer)
diff --git a/code/modules/organs/external/head.dm b/code/modules/organs/external/head.dm
index df089d2b120..68d285a4d98 100644
--- a/code/modules/organs/external/head.dm
+++ b/code/modules/organs/external/head.dm
@@ -52,7 +52,7 @@
to_chat(penman, "There is no room left to write on [head_name]!")
return
- var/graffiti = sanitizeSafe(input(penman, "Enter a message to write on [head_name]:") as text|null, MAX_NAME_LEN)
+ var/graffiti = sanitize_safe(input(penman, "Enter a message to write on [head_name]:") as text|null, MAX_NAME_LEN)
if(graffiti)
if(!target.Adjacent(penman))
to_chat(penman, "[head_name] is too far away.")
diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm
index 643a2ee62fa..be8614a0c3d 100644
--- a/code/modules/organs/internal/brain.dm
+++ b/code/modules/organs/internal/brain.dm
@@ -211,7 +211,7 @@
/obj/item/organ/internal/brain/proc/brain_damage_callback(var/damage) //Confuse them as a somewhat uncommon aftershock. Side note: Only here so a spawn isn't used. Also, for the sake of a unique timer.
if(!QDELETED(owner))
- to_chat(owner, SPAN_NOTICE("I can't remember which way is forward..."))
+ to_chat(owner, SPAN_NOTICE(FONT_HUGE("I can't remember which way is forward...")))
ADJ_STATUS(owner, STAT_CONFUSE, damage)
/obj/item/organ/internal/brain/proc/handle_disabilities()
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index 0886e9a8a8a..da44e42a4ad 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -146,30 +146,22 @@
if(owner && length(ailments))
for(var/datum/ailment/ailment in ailments)
- if(!ailment.treated_by_reagent_type)
- continue
- var/treated
- var/datum/reagents/bloodstr_reagents = owner.get_injected_reagents()
- var/datum/reagents/ingested_reagents = owner.get_ingested_reagents()
- if(bloodstr_reagents)
- if(REAGENT_VOLUME(bloodstr_reagents, ailment.treated_by_reagent_type) >= ailment.treated_by_reagent_dosage)
- treated = bloodstr_reagents
- else if(REAGENT_VOLUME(owner.reagents, ailment.treated_by_reagent_type) >= ailment.treated_by_reagent_dosage)
- treated = owner.reagents
- else if(REAGENT_VOLUME(ingested_reagents, ailment.treated_by_reagent_type) >= ailment.treated_by_reagent_dosage)
- treated = ingested_reagents
- else
- var/datum/reagents/inhaled_reagents = owner.get_inhaled_reagents()
- if(inhaled_reagents && REAGENT_VOLUME(inhaled_reagents, ailment.treated_by_reagent_type) >= ailment.treated_by_reagent_dosage)
- treated = inhaled_reagents
-
- if(treated)
- ailment.was_treated_by_medication(treated)
+ handle_ailment(ailment)
//check if we've hit max_damage
if(damage >= max_damage)
die()
+/obj/item/organ/proc/handle_ailment(var/datum/ailment/ailment)
+ if(ailment.treated_by_reagent_type)
+ for(var/datum/reagents/source in list(owner.get_inhaled_reagents(), owner.get_injected_reagents(), owner.reagents, owner.get_ingested_reagents()))
+ for(var/reagent_type in source.reagent_volumes)
+ if(ailment.treated_by_medication(source.reagent_volumes[reagent_type]))
+ ailment.was_treated_by_medication(source, reagent_type)
+ return
+ if(ailment.treated_by_chem_effect && owner.has_chemical_effect(ailment.treated_by_chem_effect, ailment.treated_by_chem_effect_strength))
+ ailment.was_treated_by_chem_effect()
+
/obj/item/organ/proc/is_preserved()
if(istype(loc,/obj/item/organ))
var/obj/item/organ/O = loc
diff --git a/code/modules/overmap/exoplanets/exoplanet_flora.dm b/code/modules/overmap/exoplanets/exoplanet_flora.dm
index b183986ec9b..f512cfd104f 100644
--- a/code/modules/overmap/exoplanets/exoplanet_flora.dm
+++ b/code/modules/overmap/exoplanets/exoplanet_flora.dm
@@ -32,7 +32,7 @@
if(color == "RANDOM")
color = get_random_colour(0,75,190)
S.set_trait(TRAIT_LEAVES_COLOUR,color)
- S.chems[/decl/material/solid/wood] = 1
+ S.chems[/decl/material/solid/wood] = list(1, 1)
adapt_seed(S)
big_flora_types += S
diff --git a/code/modules/overmap/ftl_shunt/_shunt.dm b/code/modules/overmap/ftl_shunt/_shunt.dm
index ea641c1e9b8..80ce41b86cc 100644
--- a/code/modules/overmap/ftl_shunt/_shunt.dm
+++ b/code/modules/overmap/ftl_shunt/_shunt.dm
@@ -1,6 +1,7 @@
#define CHARGE_TIME_PER_TON 0.1 //In deciseconds.
#define JOULES_PER_TON 5000
#define REQUIRED_CHARGE_MULTIPLIER 0.005
+#define JUMP_TIME_PER_TILE 20 SECONDS
#define FTL_START_FAILURE_FUEL 1 //Not enough fuel.
#define FTL_START_FAILURE_POWER 2 //Not enough power.
diff --git a/code/modules/overmap/ftl_shunt/computer.dm b/code/modules/overmap/ftl_shunt/computer.dm
index 94d4a35dfaa..bbe88c028ea 100644
--- a/code/modules/overmap/ftl_shunt/computer.dm
+++ b/code/modules/overmap/ftl_shunt/computer.dm
@@ -29,8 +29,7 @@
if(!istype(sector))
return INFINITY
var/jump_dist = get_dist(linked, locate(linked_core.shunt_x, linked_core.shunt_y, sector.z))
- var/jump_cost = ((linked.vessel_mass * JOULES_PER_TON) / 1000) * jump_dist
- return jump_cost
+ return jump_dist
/obj/machinery/computer/ship/ftl/proc/recalc_cost_power()
if(!linked_core)
@@ -41,8 +40,7 @@
return INFINITY
var/jump_dist = get_dist(linked, locate(linked_core.shunt_x, linked_core.shunt_y, sector.z))
- var/jump_cost = ((linked.vessel_mass * JOULES_PER_TON) / 1000) * jump_dist
- var/jump_cost_power = jump_cost * REQUIRED_CHARGE_MULTIPLIER
+ var/jump_cost_power = ((jump_dist * linked.vessel_mass)* REQUIRED_CHARGE_MULTIPLIER)*1000
return jump_cost_power
/obj/machinery/computer/ship/ftl/proc/get_status()
@@ -123,13 +121,12 @@
data["shunt_y"] = linked_core.shunt_y
data["to_plot_x"] = to_plot_x
data["to_plot_y"] = to_plot_y
- data["fuel_joules"] = (linked_core.get_fuel(linked_core.fuel_ports) / 1000)
- data["fuel_conversion"] = linked_core.get_total_fuel_conversion_rate()
+ data["fuel_joules"] = linked_core.get_charges() || 0
data["jumpcost"] = recalc_cost()
- data["powercost"] = recalc_cost_power()
+ data["powercost"] = recalc_cost_power()/1000
data["chargetime"] = linked_core.get_charge_time()
data["chargepercent"] = linked_core.chargepercent
- data["maxfuel"] = linked_core.get_fuel_maximum(linked_core.fuel_ports)
+ data["maxfuel"] = linked_core.get_max_charges()
data["jump_status"] = get_status()
data["power_input"] = linked_core.allowed_power_usage / 1000
data["max_power"] = linked_core.max_power_usage / 1000
diff --git a/code/modules/overmap/ftl_shunt/core.dm b/code/modules/overmap/ftl_shunt/core.dm
index f289af20a5e..afe4d1b34b3 100644
--- a/code/modules/overmap/ftl_shunt/core.dm
+++ b/code/modules/overmap/ftl_shunt/core.dm
@@ -3,12 +3,24 @@
icon = 'icons/obj/shunt_drive.dmi'
var/initial_id_tag = "ftl"
+/obj/effect/shunt_dummy
+ icon = 'icons/obj/ftl_drive_96x96.dmi'
+ vis_flags = VIS_INHERIT_ID
+ appearance_flags = KEEP_TOGETHER
+ layer = EMISSIVE_LAYER
+ plane = EMISSIVE_PLANE
+
/obj/machinery/ftl_shunt/core
name = "superluminal shunt core"
desc = "An immensely powerful transdimensional superluminal bridge initiator capable of forming a micro-wormhole and shunting an entire ship through it in a nanosecond."
base_type = /obj/machinery/ftl_shunt/core
uncreated_component_parts = list(/obj/item/stock_parts/ftl_core = 1)
construct_state = /decl/machine_construction/default/no_deconstruct
+ icon = 'icons/obj/ftl_drive_96x96.dmi'
+ icon_state = "ftl_core"
+ pixel_x = -32
+ pixel_y = -32
+ density = TRUE
var/list/fuel_ports = list() //We mainly use fusion fuels.
var/charge_time //Actually, we do use power now. This is here for the console.
@@ -19,8 +31,7 @@
var/chargepercent = 0
var/last_percent_tick = 0
var/obj/machinery/computer/ship/ftl/ftl_computer
- var/required_fuel_joules
- var/required_charge //This is a function of the required fuel joules.
+ var/required_charge
var/accumulated_charge
var/max_charge = 2000000
var/target_charge
@@ -36,22 +47,53 @@
var/last_power_drawn
var/jump_delay = 2 MINUTES
var/jump_timer //used to cancel the jump.
+ var/required_jump_cores = 0
+ //HEARTH EXCLUSIVE
+ var/cached_security_level
+ //HEARTH EXCLUSIVE END
+ var/datum/event/ftl_event
+ var/last_stress_sound
+
+ var/power_on_animation_played = FALSE
+ var/power_off_animation_played = FALSE
+
+ var/width = 3
+ var/height = 3
var/static/datum/announcement/priority/ftl_announcement = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice2.ogg'))
- var/static/shunt_start_text = "Attention! Superluminal shunt warm-up initiated! Spool-up ETA: %%TIME%%"
- var/static/shunt_cancel_text = "Attention! Faster-than-light transition cancelled."
- var/static/shunt_complete_text = "Attention! Faster-than-light transition completed."
+ var/static/shunt_start_text = "Attention! Superluminal shunt warm-up initiated! ETA to subsector jump: %%TIME%%"
+ var/static/shunt_cancel_text = "Attention! Subsector superluminal transition cancelled."
+ var/static/shunt_entered_text = "Attention! Vessel has completed superluminal translation; FTL exit in %%TIME%% seconds."
+ var/static/shunt_complete_text = "Attention! Subsector superluminal transition completed."
var/static/shunt_spooling_text = "Attention! Superluminal shunt warm-up complete, spooling up."
var/static/shunt_sabotage_text_minor = "Warning! Electromagnetic flux beyond safety limits - aborting shunt!"
var/static/shunt_sabotage_text_major = "Warning! Critical electromagnetic flux in accelerator core! Dumping core and aborting shunt!"
var/static/shunt_sabotage_text_critical = "ALERT! Critical malfunction in microsingularity containment core! Safety systems offline!"
+ var/obj/effect/shunt_dummy/breakers
+ var/obj/effect/shunt_dummy/conduits
+ var/obj/effect/shunt_dummy/portal
+ var/obj/effect/shunt_dummy/charge_indicator
+ var/obj/effect/shunt_dummy/pumps
+
+ var/static/ftl_sounds = list(
+ 'sound/effects/thunder/thunder1.ogg',
+ 'sound/effects/thunder/thunder2.ogg',
+ 'sound/effects/thunder/thunder3.ogg',
+ 'sound/effects/thunder/thunder4.ogg',
+ 'sound/effects/thunder/thunder5.ogg',
+ 'sound/effects/thunder/thunder6.ogg',
+ 'sound/effects/thunder/thunder7.ogg',
+ 'sound/effects/thunder/thunder8.ogg',
+ 'sound/effects/thunder/thunder9.ogg',
+ 'sound/effects/thunder/thunder10.ogg'
+ )
+
use_power = POWER_USE_OFF
power_channel = EQUIP
idle_power_usage = 1600
- icon_state = "bsd"
light_color = COLOR_BLUE
//Base procs
@@ -62,13 +104,35 @@
if(initial_id_tag)
var/datum/extension/local_network_member/local_network = get_extension(src, /datum/extension/local_network_member)
local_network.set_tag(null, initial_id_tag)
- find_ports()
- set_light(2)
target_charge = max_charge * 0.25 //Target charge set to a quarter of our maximum charge, just for weirdness prevention
- if(populate_parts)
- var/obj/item/stock_parts/power/terminal/term = get_component_of_type(/obj/item/stock_parts/power/terminal)
- if(!term.terminal)
- term.make_terminal(src)
+ breakers = new
+ breakers.icon_state = "breakers_off"
+ conduits = new
+ conduits.icon_state = "conduits"
+ portal = new
+ portal.icon_state = "loop-base"
+ charge_indicator = new
+ charge_indicator.icon_state = null
+ pumps = new
+ pumps.icon_state = "coolant_pumps_composite_off"
+ pumps.layer = STRUCTURE_LAYER
+ pumps.plane = DEFAULT_PLANE
+ portal.add_filter("glow",1,list(type = "drop_shadow", size = 2, x = 0, y = 0, offset = 2, color = COLOR_CYAN_BLUE))
+ vis_contents += breakers
+ vis_contents += conduits
+ vis_contents += portal
+ vis_contents += charge_indicator
+ vis_contents += pumps
+
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/ftl_shunt/core/proc/SetBounds()
+ bound_width = width * world.icon_size
+ bound_height = height * world.icon_size
+
+/obj/machinery/ftl_shunt/core/LateInitialize()
+ . = ..()
+ find_ports()
/obj/machinery/ftl_shunt/core/modify_mapped_vars(map_hash)
..()
@@ -85,22 +149,84 @@
/obj/machinery/ftl_shunt/core/on_update_icon()
cut_overlays()
+ var/new_charge_color
- if(charging)
- var/image/I = image('icons/obj/shunt_drive.dmi', "activating")
- var/matrix/M = new()
- I.transform = M
- add_overlay(I)
+ if(chargepercent == 0 || isnull(chargepercent))
+ new_charge_color ="#fa0a0a"
+ else
+ #if DM_VERSION > 513
+ new_charge_color = gradient("#fa0a0a", "#0de405", clamp(chargepercent/100, 0, 100))
+ #endif
+ #if DM_VERSION < 514
+ new_charge_color = HSVtoRGB(RotateHue(hsv(0, 255, 255), 120 * (1 - chargepercent/100)))
+ #endif
+ animate(charge_indicator, color = new_charge_color, 1 SECOND)
+
+ if(stat & BROKEN)
+ add_overlay(image(icon, "right_breaker_malf"))
+ add_overlay(image(icon, "left_breaker_malf"))
+ return
+
+ if((stat & NOPOWER) && !power_off_animation_played)
+ flick("breakers_turn_off", breakers)
+ breakers.icon_state = "breakers_off"
+ flick("loop-turn-off", portal)
+ portal.icon_state = null
+ flick("charge_state_turn_off", charge_indicator)
+ charge_indicator.icon_state = "null"
+ if(charging)
+ flick("coolant_pumps_composite_turn_off", pumps)
+ pumps.icon_state = "coolant_pumps_composite_off"
+ conduits.icon_state = null
+
+ power_off_animation_played = TRUE
+ power_on_animation_played = FALSE
+
+ if(!(stat & NOPOWER) && !power_on_animation_played)
+ flick("breakers_turn_on", breakers)
+ breakers.icon_state = "breakers_on"
+ flick("loop-turn-on", portal)
+ portal.icon_state = "loop-idle-off"
+ flick("charge_state_turn_on", charge_indicator)
+ charge_indicator.icon_state = "charge_state"
+ if(charging)
+ flick("coolant_pumps_composite_turn_on", pumps)
+ pumps.icon_state = "coolant_pumps_composite_on"
+
+ power_off_animation_played = FALSE
+ power_on_animation_played = TRUE
+
+ if(charging && !(stat & NOPOWER))
+ add_overlay(image(icon, "turbine_on"))
+ if(!conduits.filter_data)
+ conduits.add_filter("glow", 1, list(type="drop_shadow", x=0,y=0,size=2,color=COLOR_ORANGE))
+ conduits.icon_state = "conduits_glow"
+ pumps.icon_state = "coolant_pumps_composite_on"
+ portal.icon_state = "loop-charging"
+
+ if(!charging)
+ conduits.icon_state = null
if(jumping)
- add_overlay(image('icons/obj/shunt_drive.dmi', "activated"))
- var/image/S = image('icons/obj/objects.dmi', "bhole3")
- var/matrix/M = new()
- M.Scale(0.75)
- S.transform = M
- S.alpha = 0
- animate(S, alpha = 255, time = 5.9 SECONDS)
- add_overlay(S)
+ add_overlay(image(icon, "loop-idle-on"))
+
+ if(sabotaged)
+ if(portal.filter_data)
+ if(portal.filter_data["glow"]["color"] != COLOR_RED)
+ portal.animate_filter("glow", list(color = COLOR_RED, time = 1))
+ portal.update_filters()
+ if(rand(15))
+ portal.animate_filter("glow", list(size = sabotaged*3, time = 1 SECONDS, offset = sabotaged*rand(1,3)))
+ addtimer(CALLBACK(src, /atom/movable/proc/animate_filter, "glow", list(size = 2, time = 1 SECONDS, offset = 2)), 2 SECONDS)
+
+ if(!sabotaged)
+ if(portal.filter_data)
+ if(portal.filter_data["glow"]["color"] != COLOR_CYAN_BLUE)
+ portal.animate_filter("glow", list(color = COLOR_CYAN_BLUE, time = 1))
+ portal.update_filters()
+ if(rand(15))
+ portal.animate_filter("glow", list(size = rand(1,2)*2, time = 1 SECONDS, offset = 2*rand(1,3)))
+ addtimer(CALLBACK(src, /atom/movable/proc/animate_filter, "glow", list(size = 2, time = 1 SECONDS, offset = 2)), 2 SECONDS)
/obj/machinery/ftl_shunt/core/examine(mob/user)
. = ..()
@@ -196,6 +322,8 @@
//Starts the teleport process, returns 1-6, with 6 being the all-clear.
/obj/machinery/ftl_shunt/core/proc/start_shunt()
+ var/decl/security_state/security_state = GET_DECL(global.using_map.security_state)
+
if(isnull(ftl_computer))
return
@@ -222,7 +350,7 @@
if(max_charge < required_charge)
return FTL_START_FAILURE_POWER
- if(required_fuel_joules > get_fuel(fuel_ports))
+ if(required_jump_cores > get_charges())
return FTL_START_FAILURE_FUEL
if(sabotaged)
@@ -235,6 +363,9 @@
var/announcetxt = replacetext(shunt_start_text, "%%TIME%%", "[round(jump_delay/600)] minutes.")
ftl_announcement.Announce(announcetxt, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg'))
+
+ cached_security_level = security_state.current_security_level
+ security_state.set_security_level(GET_DECL(/decl/security_level/default/code_yellow), TRUE)
update_icon()
if(check_charge())
@@ -248,23 +379,27 @@
var/vessel_mass = ftl_computer.linked.get_vessel_mass()
var/shunt_turf = locate(shunt_x, shunt_y, O.z)
shunt_distance = get_dist(get_turf(ftl_computer.linked), shunt_turf)
- required_fuel_joules = (vessel_mass * JOULES_PER_TON) * shunt_distance
- required_charge = required_fuel_joules * REQUIRED_CHARGE_MULTIPLIER
+ required_jump_cores = shunt_distance
+ required_charge = ((shunt_distance * vessel_mass)* REQUIRED_CHARGE_MULTIPLIER)*1000
//Cancels the in-progress shunt.
/obj/machinery/ftl_shunt/core/proc/cancel_shunt(var/silent = FALSE)
+ var/decl/security_state/security_state = GET_DECL(global.using_map.security_state)
if(!jump_timer)
return
deltimer(jump_timer)
charge_time = null
cooldown = null
- required_fuel_joules = null
+ required_jump_cores = null
if(!silent)
ftl_announcement.Announce(shunt_cancel_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg'))
update_icon()
jump_timer = null
+ //HEARTH EXCLUSIVE
+ security_state.set_security_level(cached_security_level, TRUE)
+ //END HEARTH EXCLUSIVE
-//Starts the shunt, and then hands off to do_shunt to finish it.
+//Starts the shunt, and then hands off to enter_shunt to finish it.
/obj/machinery/ftl_shunt/core/proc/execute_shunt()
ftl_announcement.Announce(shunt_spooling_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg'))
if(sabotaged)
@@ -273,8 +408,8 @@
ftl_computer.jump_plotted = FALSE
return
- if(use_fuel(required_fuel_joules))
- jump_timer = addtimer(CALLBACK(src, .proc/execute_shunt), jump_delay, TIMER_STOPPABLE)
+ if(can_use_fuel(required_jump_cores))
+ use_fuel(required_jump_cores)
else
cancel_shunt()
return //If for some reason we don't have fuel now, just return.
@@ -283,9 +418,7 @@
if(O)
var/destination = locate(shunt_x, shunt_y, O.z)
var/jumpdist = get_dist(get_turf(ftl_computer.linked), destination)
- var/obj/effect/portal/wormhole/W = new(destination) //Generate a wormhole effect on overmap to give some indication that something is about to happen.
- QDEL_IN(W, 6 SECONDS)
- addtimer(CALLBACK(src, .proc/do_shunt, shunt_x, shunt_y, jumpdist, destination), 6 SECONDS)
+ addtimer(CALLBACK(src, .proc/enter_shunt, shunt_x, shunt_y, jumpdist, destination), 6 SECONDS)
jumping = TRUE
update_icon()
for(var/mob/living/carbon/M in global.living_mob_list_)
@@ -293,8 +426,23 @@
continue
sound_to(M, 'sound/machines/hyperspace_begin.ogg')
-/obj/machinery/ftl_shunt/core/proc/do_shunt(var/turfx, var/turfy, var/jumpdist, var/destination) //this does the actual teleportation, execute_shunt is there to give us time to do our fancy effects
+/obj/machinery/ftl_shunt/core/proc/enter_shunt(var/shunt_x, var/shunt_x, var/jumpdist, var/destination)
+ var/announcetxt = replacetext(shunt_entered_text, "%%TIME%%", "[round((jumpdist*JUMP_TIME_PER_TILE)/60)]")
+ var/datum/event_meta/EM = new(EVENT_LEVEL_MUNDANE, "FTL", /datum/event/ftl, add_to_queue = FALSE, is_one_shot = TRUE)
+ ftl_event = new /datum/event/ftl(EM)
+ ftl_event.startWhen = 0
+ ftl_event.endWhen = INFINITY
+ ftl_event.affecting_z = ftl_computer.linked.map_z
+ ftl_computer.linked.forceMove(null)
+ ftl_computer.linked.halted = TRUE
+
+ ftl_announcement.Announce(announcetxt, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg'))
+ addtimer(CALLBACK(src, .proc/end_shunt, shunt_x, shunt_y, jumpdist, destination),jumpdist*JUMP_TIME_PER_TILE)
+
+/obj/machinery/ftl_shunt/core/proc/end_shunt(var/turfx, var/turfy, var/jumpdist, var/destination) //this does the actual teleportation, execute_shunt is there to give us time to do our fancy effects
+ var/decl/security_state/security_state = GET_DECL(global.using_map.security_state)
ftl_computer.linked.forceMove(destination)
+ ftl_computer.linked.halted = FALSE
ftl_announcement.Announce(shunt_complete_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg'))
cooldown = world.time + cooldown_delay
do_effects(jumpdist)
@@ -304,6 +452,12 @@
accumulated_charge -= required_charge
jump_timer = null
ftl_computer.jump_plotted = FALSE
+ //HEARTH EXCLUSIVE
+ addtimer(CALLBACK(security_state, /decl/security_state/.proc/set_security_level, cached_security_level, TRUE), 4 SECONDS)
+ //END HEARTH EXCLUSIVE
+ if(ftl_event)
+ ftl_event.kill()
+ ftl_event = null
//Handles all the effects of the jump.
/obj/machinery/ftl_shunt/core/proc/do_effects(var/distance) //If we're jumping too far, have some !!FUN!! with people and ship systems.
@@ -333,7 +487,7 @@
switch(shunt_sev)
if(SHUNT_SEVERITY_MINOR)
to_chat(H, SPAN_NOTICE("You feel your insides flutter about inside of you as you are briefly shunted into an alternate dimension.")) //No major effects.
- shake_camera(H, 2, 1)
+ shake_camera(H, 3, 3)
if(SHUNT_SEVERITY_MAJOR)
to_chat(H, SPAN_WARNING("You feel your insides twisted inside and out as you are violently shunted between dimensions, and you feel like something is watching you!"))
@@ -341,7 +495,7 @@
H.set_hallucination(50, 50)
if(prob(15))
H.vomit()
- shake_camera(H, 2, 1)
+ shake_camera(H, 3, 3)
if(SHUNT_SEVERITY_CRITICAL)
to_chat(H, SPAN_DANGER("You feel an overwhelming sense of nausea and vertigo wash over you, your instincts screaming that something is wrong!"))
@@ -356,10 +510,10 @@
continue
switch(shunt_sev)
if(SHUNT_SEVERITY_MINOR)
- if(prob(15))
+ if(prob(25))
L.flicker()
if(SHUNT_SEVERITY_MAJOR)
- if(prob(35))
+ if(prob(45))
L.flicker()
for(var/obj/machinery/power/apc/A in SSmachines.machinery)
@@ -367,9 +521,9 @@
continue
switch(shunt_sev)
if(SHUNT_SEVERITY_MAJOR)
- if(prob(15))
+ if(prob(25))
A.energy_fail(rand(30, 80))
- if(prob(10))
+ if(prob(35))
A.overload_lighting(25)
if(SHUNT_SEVERITY_CRITICAL)
@@ -431,7 +585,6 @@
ftl_announcement.Announce(announcetxt, "FTL Shunt Management System", new_sound = sound('sound/misc/ftlsiren.ogg'))
-
//Returns status to ftl computer.
/obj/machinery/ftl_shunt/core/proc/get_status()
if(stat & (BROKEN|NOPOWER))
@@ -443,79 +596,42 @@
else
return FTL_STATUS_GOOD
-/obj/machinery/ftl_shunt/core/proc/get_fuel(var/list/input)
- . = 0
- for(var/obj/machinery/ftl_shunt/fuel_port/F in input)
- . += F.get_fuel_joules(FALSE)
-
-/obj/machinery/ftl_shunt/core/proc/get_fuel_maximum(var/list/input)
- . = 0
- for(var/obj/machinery/ftl_shunt/fuel_port/F in input)
- . += F.get_fuel_joules(TRUE)
-
-/obj/machinery/ftl_shunt/core/proc/fuelpercentage()
- if(!length(fuel_ports))
- return 0
- var/fuel_max = get_fuel_maximum(fuel_ports)
- if(fuel_max == 0)
- return 0
- return round(100.0*get_fuel(fuel_ports)/fuel_max, 0.1)
-
-
-/obj/machinery/ftl_shunt/core/proc/use_fuel(var/joules_req)
- var/avail_fuel = get_fuel(fuel_ports)
-
- if(joules_req > avail_fuel) //Not enough fuel in the system.
+/obj/machinery/ftl_shunt/core/proc/can_use_fuel(var/charges_required)
+ var/avaliable_charges
+ for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
+ avaliable_charges += F.get_charge()
+ if(avaliable_charges >= charges_required)
+ return TRUE
+ else
return FALSE
- var/list/fueled_ports = list()
- var/total_joules
- var/joules_per_port
- var/joule_debt
-
- for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports) //Step one, loop through ports, sort them by those who are fully fueled and those that are not.
- if(!F.has_fuel())
- continue
- fueled_ports += F
-
- joules_per_port = (joules_req / length(fueled_ports))
+/obj/machinery/ftl_shunt/core/proc/use_fuel(var/charges_required)
+ var/avaliable_charges
+ var/used_charges
- for(var/obj/machinery/ftl_shunt/fuel_port/F in fueled_ports) //Loop through all our ports, use fuel from those that have enough and those that are partially empty.
- if(F.get_fuel_joules() >= joules_per_port) //Enough fuel in this one!
- if(F.use_fuel_joules(joules_per_port))
- total_joules += joules_per_port
- continue
- else //Not enough fuel in this port to meet the per-port quota - take as much as we can and pick up the slack with others.
- var/available_fuel = F.get_fuel_joules()
- if(F.use_fuel_joules(available_fuel))
- total_joules += available_fuel
- joule_debt += joules_per_port - available_fuel
- fueled_ports -= F //Remove this one from the pool of avaliable ports, since it's used up.
- continue
-
- if(total_joules == joules_req)
- return TRUE //All ports supplied enough fuel first go around, return early.
-
- if(joule_debt) //We haven't rallied up enough energy for the jump, probably from ports that were only partially fueled.
- var/fuel_debt_spread = joule_debt / length(fueled_ports)
- for(var/obj/machinery/ftl_shunt/fuel_port/F in fueled_ports) //Loop through all our ports, use fuel from those that have enough and those that are partially empty.
- if(F.get_fuel_joules() >= fuel_debt_spread) //Enough fuel in this one!
- if(F.use_fuel_joules(fuel_debt_spread))
- total_joules += fuel_debt_spread
- continue
- else //Not enough fuel in this port to meet the per-port quota - take as much as we can and pick up the slack with others.
- var/available_fuel_debt = F.get_fuel_joules()
- if(F.use_fuel_joules(available_fuel_debt))
- total_joules += available_fuel_debt
- joule_debt -= available_fuel_debt
- continue
+ for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
+ avaliable_charges += F.get_charge()
+ if(avaliable_charges >= charges_required)
+ for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
+ F.use_charge()
+ F.update_icon()
+ used_charges++
+ if(used_charges == charges_required)
+ break
+
+/obj/machinery/ftl_shunt/core/proc/get_charges()
+ for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
+ . += F.get_charge()
- if(total_joules == joules_req && !joule_debt)
- return TRUE
+/obj/machinery/ftl_shunt/core/proc/get_max_charges()
+ for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
+ . += 1
/obj/machinery/ftl_shunt/core/proc/get_charge_time()
if(isnull(last_power_drawn))
return "UNKNOWN"
+ if(last_power_drawn == 0)
+ return "UNKNOWN"
return "[clamp(round((target_charge-accumulated_charge)/((last_power_drawn*CELLRATE) * 1 SECOND / SSmachines.wait), 0.1),0, INFINITY)] Seconds"
/obj/machinery/ftl_shunt/core/proc/check_charge()
@@ -526,18 +642,13 @@
if(stat & NOPOWER)
return FALSE
- var/drawn_charge = use_power_oneoff(input)
- last_power_drawn = drawn_charge
- accumulated_charge += drawn_charge * CELLRATE
+ if(!use_power_oneoff(input,EQUIP))
+ last_power_drawn = input
+ accumulated_charge += input * CELLRATE
- return TRUE
-
-/obj/machinery/ftl_shunt/core/proc/get_total_fuel_conversion_rate()
- var/rate
- for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports)
- rate += F.get_fuel_conversion_rate()
- . = round((rate / length(fuel_ports)), 0.1)
-
+ return TRUE
+ else
+ return FALSE
/obj/machinery/ftl_shunt/core/Process()
if(stat & (BROKEN|NOPOWER))
@@ -551,98 +662,14 @@
SSradiation.radiate(src, (active_power_usage / 1000))
chargepercent = round(100*(accumulated_charge/max_charge), 0.1)
-/obj/machinery/ftl_shunt/fuel_port
- name = "superluminal shunt fuel port"
- desc = "A fuel port for an FTL shunt."
- icon_state = "empty"
-
- var/static/list/fuels = list(
- /decl/material/gas/hydrogen/tritium = 25000,
- /decl/material/gas/hydrogen/deuterium = 25000,
- /decl/material/gas/hydrogen = 25000,
- /decl/material/solid/exotic_matter = 50000
- )
- var/obj/item/fuel_assembly/fuel
- var/obj/machinery/ftl_shunt/core/master
- var/max_fuel = 0
-
-/obj/machinery/ftl_shunt/fuel_port/on_update_icon()
- if(fuel)
- icon_state = "full"
- else
- icon_state = "empty"
-
-/obj/machinery/ftl_shunt/fuel_port/Initialize()
- set_extension(src, /datum/extension/local_network_member)
- if(initial_id_tag)
- var/datum/extension/local_network_member/local_network = get_extension(src, /datum/extension/local_network_member)
- local_network.set_tag(null, initial_id_tag)
- . = ..()
-
-/obj/machinery/ftl_shunt/fuel_port/modify_mapped_vars(map_hash)
- ..()
- ADJUST_TAG_VAR(initial_id_tag, map_hash)
-
-/obj/machinery/ftl_shunt/fuel_port/Destroy()
- . = ..()
- if(master)
- master.fuel_ports -= src
- master = null
- QDEL_NULL(fuel)
-
-/obj/machinery/ftl_shunt/fuel_port/attackby(var/obj/item/O, var/mob/user)
- if(istype(O, /obj/item/fuel_assembly))
- if(!fuel)
- if(!do_after(user, 2 SECONDS, src) || fuel)
- return
- if(!user || !user.unEquip(O, src))
- return
- fuel = O
- max_fuel = get_fuel_joules(TRUE)
- update_icon()
- return TRUE
-
- . = ..()
-
-/obj/machinery/ftl_shunt/fuel_port/physical_attack_hand(var/mob/user)
- if(fuel)
- to_chat(user, SPAN_NOTICE("You begin to remove the fuel assembly from [src]..."))
- if(!do_after(user, 2 SECONDS, src) || !fuel || fuel.loc != src)
- return FALSE
- fuel.dropInto(loc)
- user.put_in_hands(fuel)
- fuel = null
- max_fuel = 0
- to_chat(user, SPAN_NOTICE("You remove the fuel assembly!"))
- return TRUE
-
- . = ..()
-
-/obj/machinery/ftl_shunt/fuel_port/proc/has_fuel()
- return !!fuel
-
-/obj/machinery/ftl_shunt/fuel_port/proc/get_fuel_joules(var/get_fuel_maximum)
- if(fuel)
- for(var/G in fuel.matter)
- if(G in fuels)
- . += (get_fuel_maximum ? 10000 : fuel.matter[G]) * fuels[G]
-
-/obj/machinery/ftl_shunt/fuel_port/proc/get_fuel_conversion_rate() //This is mostly a fluff proc, since internally everything is done in joules.
- if(fuel)
- for(var/G in fuel.matter)
- if(G in fuels)
- . = fuels[G]
-
-/obj/machinery/ftl_shunt/fuel_port/proc/use_fuel_joules(var/joules)
- if(!fuel)
- return FALSE
-
- for(var/G in fuel.matter)
- if(G in fuels)
- var/fuel_to_use = joules / fuels[G]
- fuel.matter[G] -= fuel_to_use
-
- return TRUE
+ if(jumping)
+ if(prob(15) && last_stress_sound < world.time + 2 SECONDS)
+ for(var/mob/living/carbon/M in global.living_mob_list_)
+ if(!(M.z in ftl_computer.linked.map_z))
+ continue
+ sound_to(M, pick(ftl_sounds))
+ shake_camera(M, rand(1,2), rand(1,2))
+ last_stress_sound = world.time
//
// Construction MacGuffins down here.
@@ -653,7 +680,6 @@
board_type = "machine"
build_path = /obj/machinery/ftl_shunt/core
origin_tech = "{'programming':3,'magnets':5,'materials':5,'wormholes':5}"
- additional_spawn_components = list(/obj/item/stock_parts/power/terminal = 1)
/obj/item/stock_parts/ftl_core
name = "exotic matter bridge"
@@ -663,3 +689,5 @@
icon_state = "smes_coil"
color = COLOR_YELLOW
matter = list(/decl/material/solid/exotic_matter = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/plasteel = MATTER_AMOUNT_PRIMARY)
+
+
diff --git a/code/modules/overmap/ftl_shunt/ftl_event.dm b/code/modules/overmap/ftl_shunt/ftl_event.dm
new file mode 100644
index 00000000000..9ad8b0ebe73
--- /dev/null
+++ b/code/modules/overmap/ftl_shunt/ftl_event.dm
@@ -0,0 +1,17 @@
+/datum/event/ftl
+ has_skybox_image = TRUE
+ endWhen = INFINITY
+ var/static/lightning_color
+ var/static/background_color
+
+/datum/event/ftl/get_skybox_image()
+ if(!background_color)
+ background_color = pick(COLOR_BLUE, COLOR_BLUE_GRAY, COLOR_BLUE_LIGHT, COLOR_CYAN, COLOR_CYAN_BLUE, COLOR_NAVY_BLUE)
+ if(!lightning_color)
+ lightning_color = pick("#ffd98c", "#ebc7ff", "#bdfcff", "#bdd2ff", "#b0ffca", "#ff8178", "#ad74cc")
+ var/image/res = overlay_image('icons/skybox/ftlbox.dmi', "ftl", lightning_color, RESET_COLOR)
+ var/image/res_2 = overlay_image('icons/skybox/electrobox.dmi', "lightning", lightning_color, RESET_COLOR)
+ res.overlays += res_2
+ res_2.blend_mode = BLEND_ADD
+ res.blend_mode = BLEND_OVERLAY
+ return res
diff --git a/code/modules/overmap/ftl_shunt/fuel_port.dm b/code/modules/overmap/ftl_shunt/fuel_port.dm
new file mode 100644
index 00000000000..30da071cc3c
--- /dev/null
+++ b/code/modules/overmap/ftl_shunt/fuel_port.dm
@@ -0,0 +1,125 @@
+/obj/machinery/ftl_shunt/fuel_port
+ name = "superluminal shunt fuel port"
+ desc = "A fuel port for an FTL shunt."
+ icon_state = "empty"
+ icon = 'icons/obj/ftlshunt_fuelport.dmi'
+
+ var/obj/item/jumpcore/fuel
+ var/obj/machinery/ftl_shunt/core/master
+
+/obj/machinery/ftl_shunt/fuel_port/on_update_icon()
+ cut_overlays()
+ var/image/I = image(icon, "spent_overlay")
+ if(fuel)
+ icon_state = "full"
+ else
+ icon_state = "empty"
+ if(fuel)
+ if(fuel.spent)
+ I.color = COLOR_RED
+ else
+ I.color = COLOR_GREEN
+ add_overlay(I)
+
+/obj/machinery/ftl_shunt/fuel_port/Initialize()
+ set_extension(src, /datum/extension/local_network_member)
+ if(initial_id_tag)
+ var/datum/extension/local_network_member/local_network = get_extension(src, /datum/extension/local_network_member)
+ local_network.set_tag(null, initial_id_tag)
+ . = ..()
+
+/obj/machinery/ftl_shunt/fuel_port/modify_mapped_vars(map_hash)
+ ..()
+ ADJUST_TAG_VAR(initial_id_tag, map_hash)
+
+/obj/machinery/ftl_shunt/fuel_port/Destroy()
+ . = ..()
+ if(master)
+ master.fuel_ports -= src
+ master = null
+ QDEL_NULL(fuel)
+
+/obj/machinery/ftl_shunt/fuel_port/attackby(var/obj/item/O, var/mob/user)
+ if(istype(O, /obj/item/jumpcore))
+ if(!fuel)
+ if(!do_after(user, 2 SECONDS, src) || fuel)
+ return
+ if(!user || !user.unEquip(O, src))
+ return
+ fuel = O
+ flick("insert", src)
+ update_icon()
+ return TRUE
+
+ . = ..()
+
+/obj/machinery/ftl_shunt/fuel_port/physical_attack_hand(var/mob/user)
+ if(fuel)
+ to_chat(user, SPAN_NOTICE("You begin to remove the fuel assembly from [src]..."))
+ if(!do_after(user, 2 SECONDS, src) || !fuel || fuel.loc != src)
+ return FALSE
+ fuel.dropInto(loc)
+ user.put_in_hands(fuel)
+ fuel = null
+ to_chat(user, SPAN_NOTICE("You remove the fuel assembly!"))
+ return TRUE
+
+ . = ..()
+
+/obj/machinery/ftl_shunt/fuel_port/proc/has_fuel()
+ return fuel && !fuel.spent
+
+/obj/machinery/ftl_shunt/fuel_port/proc/get_charge()
+ if(fuel && !fuel.spent)
+ return TRUE
+
+/obj/machinery/ftl_shunt/fuel_port/proc/use_charge()
+ if(fuel && !fuel.spent)
+ fuel.use_charge()
+ fuel.update_icon()
+
+//
+// Jump cores down here
+//
+/obj/item/jumpcore
+ name = "superluminal fuel core"
+ icon = 'icons/obj/ftlshunt_fuelport.dmi'
+ icon_state = "rod_v2"
+ desc = "A container for an exotic blend of radioactive materials utilized in going faster-than-light."
+ w_class = ITEM_SIZE_LARGE
+ var/spent = FALSE
+
+/obj/item/jumpcore/Initialize(ml, material_key)
+ . = ..()
+ update_icon()
+
+/obj/item/jumpcore/Destroy()
+ . = ..()
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/jumpcore/examine(mob/user, distance, infix, suffix)
+ . = ..()
+ if(spent)
+ to_chat(user, SPAN_WARNING("This one is spent."))
+
+/obj/item/jumpcore/proc/use_charge()
+ spent = TRUE
+ START_PROCESSING(SSobj, src)
+
+/obj/item/jumpcore/Process()
+ if(!spent)
+ return PROCESS_KILL
+
+ if(istype(loc, /turf))
+ SSradiation.radiate(src,5)
+
+/obj/item/jumpcore/on_update_icon()
+ cut_overlays()
+ var/image/I = image(icon, "rod_v2_overlay")
+ if(spent)
+ I.color = COLOR_RED
+ else
+ I.color = COLOR_CYAN
+ add_overlay(I)
+ return
+
diff --git a/code/modules/overmap/ships/device_types/gas_thruster.dm b/code/modules/overmap/ships/device_types/gas_thruster.dm
index 3c02b574678..334723e059b 100644
--- a/code/modules/overmap/ships/device_types/gas_thruster.dm
+++ b/code/modules/overmap/ships/device_types/gas_thruster.dm
@@ -29,6 +29,8 @@
/datum/extension/ship_engine/gas/proc/get_propellant(var/sample_only = TRUE, var/partial = 1)
var/obj/machinery/atmospherics/unary/engine/E = holder
+ if(thrust_limit <= 0)
+ return null
var/datum/gas_mixture/removed = E.air_contents.remove_ratio((volume_per_burn * thrust_limit * partial) / E.air_contents.volume)
if(sample_only)
var/datum/gas_mixture/sample = new(removed.volume)
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index d353b49915a..aa0c0e51a54 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -36,7 +36,7 @@
to_chat(user, "You put the [W] into \the [src].")
update_icon()
else if(istype(W, /obj/item/pen))
- var/n_name = sanitizeSafe(input(usr, "What would you like to label the folder?", "Folder Labelling", null) as text, MAX_NAME_LEN)
+ var/n_name = sanitize_safe(input(usr, "What would you like to label the folder?", "Folder Labelling", null) as text, MAX_NAME_LEN)
if((loc == usr && usr.stat == 0))
SetName("folder[(n_name ? text("- '[n_name]'") : null)]")
return
diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm
index c91a77a0645..6210655fa26 100644
--- a/code/modules/paperwork/handlabeler.dm
+++ b/code/modules/paperwork/handlabeler.dm
@@ -56,7 +56,7 @@
if(mode)
to_chat(user, "You turn on \the [src].")
//Now let them chose the text.
- var/str = sanitizeSafe(input(user,"Label text?","Set label",""), MAX_LNAME_LEN)
+ var/str = sanitize_safe(input(user,"Label text?","Set label",""), MAX_LNAME_LEN)
if(!str || !length(str))
to_chat(user, "Invalid text.")
return
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 0e6e2e69309..62c8c556bf3 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -105,7 +105,7 @@
if((MUTATION_CLUMSY in usr.mutations) && prob(50))
to_chat(usr, "You cut yourself on the paper.")
return
- var/n_name = sanitizeSafe(input(usr, "What would you like to label the paper?", "Paper Labelling", null) as text, MAX_NAME_LEN)
+ var/n_name = sanitize_safe(input(usr, "What would you like to label the paper?", "Paper Labelling", null) as text, MAX_NAME_LEN)
// We check loc one level up, so we can rename in clipboards and such. See also: /obj/item/photo/rename()
if(!n_name || !CanInteract(usr, global.deep_inventory_topic_state))
@@ -165,9 +165,9 @@
while(locid < MAX_FIELDS)
var/istart = 0
if(links)
- istart = findtext(info_links, "", laststart)
+ istart = findtext_char(info_links, "", laststart)
else
- istart = findtext(info, "", laststart)
+ istart = findtext_char(info, "", laststart)
if(istart==0)
return // No field found with matching id
@@ -177,20 +177,20 @@
if(locid == id)
var/iend = 1
if(links)
- iend = findtext(info_links, "", istart)
+ iend = findtext_char(info_links, "", istart)
else
- iend = findtext(info, "", istart)
+ iend = findtext_char(info, "", istart)
textindex = iend
break
if(links)
- var/before = copytext(info_links, 1, textindex)
- var/after = copytext(info_links, textindex)
+ var/before = copytext_char(info_links, 1, textindex)
+ var/after = copytext_char(info_links, textindex)
info_links = before + text + after
else
- var/before = copytext(info, 1, textindex)
- var/after = copytext(info, textindex)
+ var/before = copytext_char(info, 1, textindex)
+ var/after = copytext_char(info, textindex)
info = before + text + after
updateinfolinks()
@@ -360,8 +360,8 @@
if(user.mind && (user.mind.assigned_role == "Clown"))
clown = 1
- if(istype(P, /obj/item/tape_roll))
- var/obj/item/tape_roll/tape = P
+ if(istype(P, /obj/item/ducttape))
+ var/obj/item/ducttape/tape = P
tape.stick(src, user)
return
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index 1d15d3728e4..e27719a8d35 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -46,7 +46,7 @@
to_chat(user, "You add \the [W.name] to [(src.name == "paper bundle") ? "the paper bundle" : src.name].")
qdel(W)
else
- if(istype(W, /obj/item/tape_roll))
+ if(istype(W, /obj/item/ducttape))
return 0
if(istype(W, /obj/item/pen))
show_browser(user, "", "window=[name]") //Closes the dialog
@@ -185,7 +185,7 @@
set category = "Object"
set src in usr
- var/n_name = sanitizeSafe(input(usr, "What would you like to label the bundle?", "Bundle Labelling", null) as text, MAX_NAME_LEN)
+ var/n_name = sanitize_safe(input(usr, "What would you like to label the bundle?", "Bundle Labelling", null) as text, MAX_NAME_LEN)
if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0)
SetName("[(n_name ? text("[n_name]") : "paper")]")
add_fingerprint(usr)
diff --git a/code/modules/paperwork/paper_sticky.dm b/code/modules/paperwork/paper_sticky.dm
index 2756fc1412b..ea745dc6064 100644
--- a/code/modules/paperwork/paper_sticky.dm
+++ b/code/modules/paperwork/paper_sticky.dm
@@ -42,7 +42,7 @@
if(writing_space <= 0)
to_chat(user, SPAN_WARNING("There is no room left on \the [src]."))
return
- var/text = sanitizeSafe(input("What would you like to write?") as text, writing_space)
+ var/text = sanitize_safe(input("What would you like to write?") as text, writing_space)
if(!text || thing.loc != user || (!Adjacent(user) && loc != user) || user.incapacitated())
return
user.visible_message(SPAN_NOTICE("\The [user] jots a note down on \the [src]."))
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index c6da65ce65a..1631ff94409 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -92,7 +92,7 @@ var/global/photo_count = 0
set category = "Object"
set src in usr
- var/n_name = sanitizeSafe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN)
+ var/n_name = sanitize_safe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN)
//loc.loc check is for making possible renaming photos in clipboards
if(!n_name || !CanInteract(usr, global.deep_inventory_topic_state))
return
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 881ef6dfd22..98a72f48766 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -99,7 +99,7 @@ var/global/list/all_apcs = list()
initial_access = list(access_engine_equip)
clicksound = "switch"
layer = ABOVE_WINDOW_LAYER
- var/needs_powerdown_sound
+ var/powered_down = FALSE
var/area/area
var/areastring = null
var/shorted = 0
@@ -226,8 +226,9 @@ var/global/list/all_apcs = list()
/obj/machinery/power/apc/proc/energy_fail(var/duration)
if(emp_hardened)
return
+ if(!failure_timer && duration)
+ playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0)
failure_timer = max(failure_timer, round(duration))
- playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0)
/obj/machinery/power/apc/proc/init_round_start()
var/obj/item/stock_parts/power/terminal/term = get_component_of_type(/obj/item/stock_parts/power/terminal)
@@ -611,12 +612,13 @@ var/global/list/all_apcs = list()
area.power_change()
var/obj/item/cell/cell = get_cell()
- if(!cell || cell.charge <= 0)
- if(needs_powerdown_sound == TRUE)
+ if(!powered_down)
+ if(!cell || cell.charge <= 0)
playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0)
- needs_powerdown_sound = FALSE
- else
- needs_powerdown_sound = TRUE
+ powered_down = TRUE
+
+ else if(cell?.charge > 0)
+ powered_down = FALSE
/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
return wires.IsIndexCut(wireIndex)
diff --git a/code/modules/power/fuel_assembly/fuel_assembly.dm b/code/modules/power/fuel_assembly/fuel_assembly.dm
index 38fd9d0e61c..7ff32e265d1 100644
--- a/code/modules/power/fuel_assembly/fuel_assembly.dm
+++ b/code/modules/power/fuel_assembly/fuel_assembly.dm
@@ -13,7 +13,7 @@
/obj/item/fuel_assembly/Initialize(mapload, var/_material, var/list/makeup, var/_colour)
. = ..(mapload, _material)
LAZYINITLIST(matter)
-
+
if(LAZYLEN(makeup))
if(length(makeup) == 1) // Rod is only made from one material.
var/decl/material/mat = GET_DECL(makeup[1])
@@ -78,7 +78,7 @@
/obj/item/fuel_assembly/tritium
material = /decl/material/gas/hydrogen/tritium
-
+
/obj/item/fuel_assembly/supermatter
material = /decl/material/solid/exotic_matter
diff --git a/code/modules/power/fuel_assembly/fuel_compressor.dm b/code/modules/power/fuel_assembly/fuel_compressor.dm
index 0f1646f14d2..c283c7959c7 100644
--- a/code/modules/power/fuel_assembly/fuel_compressor.dm
+++ b/code/modules/power/fuel_assembly/fuel_compressor.dm
@@ -21,11 +21,11 @@
for(var/mat_type in stored_material)
var/decl/material/mat = GET_DECL(mat_type)
data["stored_material"] += list(list("name" = mat.name, "amount" = stored_material[mat_type]))
-
+
for(var/mat_type in rod_makeup)
var/decl/material/mat = GET_DECL(mat_type)
data["rod_makeup"] += list(list("name" = mat.name, "amount" = rod_makeup[mat_type]))
-
+
ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "fuel_compressor.tmpl", name, 500, 600)
@@ -64,7 +64,7 @@
stored_material -= mat_type
else if(!isnull(stored_material[mat_type]))
stored_material -= mat_type
-
+
return TOPIC_REFRESH
/obj/machinery/fuel_compressor/proc/make_rod()
@@ -77,7 +77,7 @@
if(rod_makeup[mat_p] > stored_material[mat_p])
visible_message(SPAN_WARNING("\The [src] flashes an 'Insufficient Materials' error!"))
return TOPIC_HANDLED
-
+
if(!LAZYLEN(rod_makeup) || !total_matter)
visible_message(SPAN_WARNING("\The [src] flashes a 'No Recipe' error!"))
return TOPIC_HANDLED
@@ -86,7 +86,7 @@
stored_material[mat_p] -= rod_makeup[mat_p]
if(stored_material[mat_p] == 0)
stored_material -= mat_p
-
+
visible_message(SPAN_NOTICE("\The [src] compresses the material into a new fuel assembly."))
new /obj/item/fuel_assembly(get_turf(src), null, rod_makeup)
return TOPIC_REFRESH
@@ -107,7 +107,7 @@
amt = round(Clamp(amt, 0, MAX_ROD_MATERIAL))
if(!amt)
rod_makeup -= mat_type
- return TOPIC_REFRESH
+ return TOPIC_REFRESH
rod_makeup[mat_type] = amt
return TOPIC_REFRESH
@@ -125,7 +125,7 @@
var/taking_reagent = REAGENT_VOLUME(thing.reagents, R)
thing.reagents.remove_reagent(R, taking_reagent)
stored_material[R] += taking_reagent
-
+
to_chat(user, SPAN_NOTICE("You add the contents of \the [thing] to \the [src]'s material buffer."))
return TRUE
@@ -138,7 +138,7 @@
if(istype(thing, /obj/item/stack/material))
var/obj/item/stack/material/M = thing
var/decl/material/mat = M.get_material()
-
+
var/taken = min(M.amount, 5)
M.use(taken)
stored_material[mat.type] += taken * SHEET_MATERIAL_AMOUNT
diff --git a/code/modules/power/fusion/kinetic_harvester.dm b/code/modules/power/fusion/kinetic_harvester.dm
index 0c631fb31c1..a2f34d1be94 100644
--- a/code/modules/power/fusion/kinetic_harvester.dm
+++ b/code/modules/power/fusion/kinetic_harvester.dm
@@ -45,7 +45,7 @@
var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member)
var/datum/local_network/lan = lanm.get_local_network()
- if(lan)
+ if(lan)
var/list/fusion_cores = lan.get_devices(/obj/machinery/power/fusion_core)
if(fusion_cores && fusion_cores.len)
harvest_from = fusion_cores[1]
@@ -121,7 +121,7 @@
return TOPIC_REFRESH
if(href_list["toggle_power"])
- use_power = (use_power >= POWER_USE_ACTIVE ? POWER_USE_IDLE : POWER_USE_ACTIVE)
+ update_use_power((use_power >= POWER_USE_ACTIVE ? POWER_USE_IDLE : POWER_USE_ACTIVE))
queue_icon_update()
return TOPIC_REFRESH
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index c1d944b6199..b51ba41107c 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -87,7 +87,7 @@
return
var/tmp_label = ""
- var/label_text = sanitizeSafe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), MAX_NAME_LEN)
+ var/label_text = sanitize_safe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), MAX_NAME_LEN)
if(length(label_text) > 20)
to_chat(user, "The inscription can be at most 20 characters long.")
else if(!label_text)
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index a86b2089866..76ce28ce4ad 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -62,10 +62,13 @@
//Everyone saw that!
for(var/mob/living/mob in global.living_mob_list_)
var/turf/T = get_turf(mob)
- var/area/A1 = T.loc
- if(T && (T != TO) && (TO.z == T.z) && !mob.blinded)
+ var/area/A1 = get_area(mob)
+ if(!T || !A1)
+ CHECK_TICK
+ continue
+ if((T != TO) && (TO.z == T.z) && !mob.blinded)
var/visible = FALSE
- if(A1 && (A1.area_flags & AREA_FLAG_EXTERNAL))
+ if(A1.area_flags & AREA_FLAG_EXTERNAL)
visible = TRUE
else
var/dir = get_dir(T,TO)
@@ -74,7 +77,7 @@
pos = get_step(pos, dir)
if(pos.opacity)
break
- A1 = pos.loc
+ A1 = get_area(pos)
if(A1 && (A1.area_flags & AREA_FLAG_EXTERNAL))
visible = TRUE
break
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index f8f901271ba..3cb1aeeb88b 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -157,6 +157,7 @@ var/global/obj/temp_reagents_holder = new
update_total()
if(!safety)
HANDLE_REACTIONS(src)
+ SSfluids.holders_to_update -= src
if(my_atom)
my_atom.on_reagent_change()
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 357c5182e4d..be35db04849 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -167,7 +167,7 @@
var/amount_per_pill = reagents.total_volume/count
if (amount_per_pill > 30) amount_per_pill = 30
- var/name = sanitizeSafe(input(usr,"Name:","Name your pill!","[reagents.get_primary_reagent_name()] ([amount_per_pill]u)"), MAX_NAME_LEN)
+ var/name = sanitize_safe(input(usr,"Name:","Name your pill!","[reagents.get_primary_reagent_name()] ([amount_per_pill]u)"), MAX_NAME_LEN)
if(!CanInteract(user, state))
return
@@ -226,7 +226,7 @@
. = JOINTEXT(.)
/obj/machinery/chem_master/proc/create_bottle(mob/user)
- var/name = sanitizeSafe(input(usr,"Name:","Name your bottle!",reagents.get_primary_reagent_name()), MAX_NAME_LEN)
+ var/name = sanitize_safe(input(usr,"Name:","Name your bottle!",reagents.get_primary_reagent_name()), MAX_NAME_LEN)
var/obj/item/chems/glass/bottle/P = new/obj/item/chems/glass/bottle(loc)
if(!name)
name = reagents.get_primary_reagent_name()
diff --git a/code/modules/reagents/chems/chems_compounds.dm b/code/modules/reagents/chems/chems_compounds.dm
index fd041a7f84c..c7529b50223 100644
--- a/code/modules/reagents/chems/chems_compounds.dm
+++ b/code/modules/reagents/chems/chems_compounds.dm
@@ -428,7 +428,7 @@
to_chat(M, SPAN_NOTICE("You feel a deep, sharp tugging sensation as your [I.name] is mended."))
I.heal_damage(rand(1,3))
break
- else
+ else
to_chat(M, SPAN_DANGER("Your flesh is being lacerated from within!"))
M.adjustBruteLoss(rand(3,6))
if(prob(10))
diff --git a/code/modules/reagents/chems/chems_drinks.dm b/code/modules/reagents/chems/chems_drinks.dm
index 01992387ea3..f9272f37848 100644
--- a/code/modules/reagents/chems/chems_drinks.dm
+++ b/code/modules/reagents/chems/chems_drinks.dm
@@ -243,6 +243,14 @@
glass_name = "pear juice"
glass_desc = "Delicious juice made from pears."
+/decl/material/liquid/drink/juice/pumpkinpulp
+ name = "pumpkin pulp"
+ lore_text = "It's almost juice, but not really. Someone's been Smashing Pumpkins Today."
+ taste_description = "pumpkin"
+ color = "#d88b4c"
+ uid = "chem_drink_pumpkin"
+ // no glass
+
// Everything else
/decl/material/liquid/drink/milk
@@ -635,7 +643,7 @@
/decl/material/liquid/drink/tea/affect_ingest(var/mob/living/M, var/alien, var/removed, var/datum/reagents/holder)
..()
-
+
if(M.HasTrait(/decl/trait/metabolically_inert))
return
@@ -706,6 +714,12 @@
glass_name = "redbush tea"
glass_desc = "A caffeine-free dark red tea, flavorful and full of antioxidants."
+/decl/material/liquid/drink/syrup/sugar
+ name = "simple syrup"
+ lore_text = "A rich simple syrup, made of sugar dissolved in boiling water. It's sickeningly sweet."
+ taste_description = "sweetness"
+ uid = "chem_drink_simplesyrup"
+
/decl/material/liquid/drink/syrup
abstract_type = /decl/material/liquid/drink/syrup
var/coffee_priority
@@ -799,7 +813,7 @@
/decl/material/liquid/drink/beastenergy/affect_ingest(var/mob/living/M, var/alien, var/removed, var/datum/reagents/holder)
..()
-
+
if(M.HasTrait(/decl/trait/metabolically_inert))
return
diff --git a/code/modules/reagents/chems/chems_nutriment.dm b/code/modules/reagents/chems/chems_nutriment.dm
index eaf2fd6ca58..d8cabbc51b6 100644
--- a/code/modules/reagents/chems/chems_nutriment.dm
+++ b/code/modules/reagents/chems/chems_nutriment.dm
@@ -50,7 +50,7 @@
if(M.HasTrait(/decl/trait/metabolically_inert))
return
- M.heal_organ_damage(0.5 * removed, 0) //what
+ M.heal_organ_damage(0.5 * removed, 0) //what
M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed)
/decl/material/liquid/nutriment/proc/adjust_nutrition(var/mob/living/carbon/M, var/alien, var/removed)
@@ -138,7 +138,7 @@
/decl/material/liquid/nutriment/batter
name = "batter"
lore_text = "A gooey mixture of eggs and flour, a base for turning wheat into food."
- taste_description = "blandness"
+ taste_description = "batter"
nutriment_factor = 3
color = "#ffd592"
slipperiness = -1
@@ -156,6 +156,107 @@
color = "#ffe992"
uid = "chem_nutriment_cakebatter"
+// HEARTH EDIT START
+// TODO - MODULARISE HEARTH COOKING
+/decl/material/liquid/nutriment/batter
+ var/icon_raw = "batter_raw"
+ var/icon_cooked = "batter_cooked"
+ // todo - reimplement raw/uncooked batter as separate materials
+ var/coated_adj = "battered"
+
+/decl/material/liquid/nutriment/batter/beerbatter
+ name = "beer batter mix"
+ color = "#f5f4e9"
+ icon_raw = "batter_raw"
+ icon_cooked = "batter_cooked"
+ coated_adj = "beer-battered"
+ taste_description = "beer batter"
+ uid = "chem_nutriment_beerbatter"
+
+/decl/material/liquid/nutriment/batter/beerbatter/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
+ ..()
+ M.add_chemical_effect(CE_ALCOHOL, removed*0.02) //Very slightly alcoholic
+
+//Fats
+//=========================
+/decl/material/liquid/nutriment/triglyceride
+ name = "triglyceride"
+ lore_text = "More commonly known as fat, the third macronutrient, with over double the energy content of carbs and protein"
+
+ nutriment_factor = 27//The caloric ratio of carb/protein/fat is 4:4:9
+ color = "#cccccc"
+ taste_description = "fat"
+ uid = "chem_nutriment_triglyceride"
+
+/decl/material/liquid/nutriment/triglyceride/oil
+ //Having this base class in case we want to add more variants of oil
+ name = "oil"
+ lore_text = "Oils are liquid fats."
+ color = "#c79705"
+ touch_met = 1.5
+ taste_description = "some sort of oil"
+ taste_mult = 0.1
+ uid = "chem_oil"
+
+/decl/material/liquid/nutriment/triglyceride/oil/touch_turf(var/turf/simulated/T, var/datum/reagents/holder)
+ if(!istype(T))
+ return
+
+ if(holder.reagent_volumes[type] >= 3)
+ T.wet_floor()
+
+//Calculates a scaling factor for scalding damage, based on the temperature of the oil and creature's heat resistance
+/decl/material/liquid/nutriment/triglyceride/oil/proc/heatdamage(var/mob/living/carbon/M, var/datum/reagents/holder)
+ var/threshold = 360//Human heatdamage threshold
+ var/decl/species/S = M.get_species(1)
+ if (S && istype(S))
+ threshold = S.heat_level_1
+
+ //If temperature is too low to burn, return a factor of 0. no damage
+ if (!holder?.my_atom || (holder.my_atom.temperature < threshold))
+ return 0
+
+ //Step = degrees above heat level 1 for 1.0 multiplier
+ var/step = 60
+ if (S && istype(S))
+ step = (S.heat_level_2 - S.heat_level_1)*1.5
+
+ . = holder.my_atom.temperature - threshold
+ . /= step
+ . = min(., 2.5)//Cap multiplier at 2.5
+
+/decl/material/liquid/nutriment/triglyceride/oil/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
+ var/dfactor = heatdamage(M, holder)
+ if (dfactor)
+ M.take_organ_damage(0, removed * 1.5 * dfactor)
+ to_chat(M, SPAN_DANGER("The hot oil clings to your skin and burns you!"))
+
+/decl/material/liquid/nutriment/triglyceride/oil/corn
+ name = "corn oil"
+ lore_text = "An oil derived from corn."
+ taste_description = "corn oil"
+ uid = "chem_oil_corn"
+
+// From Synnono's Cooking Expansion on Aurora
+/decl/material/liquid/nutriment/browniemix
+ name = "brownie mix"
+ lore_text = "A dry mix for making delicious brownies."
+ color = "#441a03"
+ nutriment_factor = 5
+ taste_mult = 1.3
+ taste_description = "chocolate"
+ uid = "chem_browniemix"
+
+// Caramel sugar from Hestia
+/decl/material/liquid/nutriment/caramelsugar
+ name = "caramel sugar"
+ lore_text = "Caramelised sugar, used in various recipes."
+ taste_description = "toasty sweetness"
+ taste_mult = 1.5
+ nutriment_factor = 1.5
+ uid = "chem_caramelsugar"
+// HEARTH EDIT END
+
/decl/material/liquid/nutriment/coffee
name = "coffee powder"
lore_text = "A bitter powder made by grinding coffee beans."
diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm
index 78b3b7024b1..89a6c815769 100644
--- a/code/modules/reagents/dispenser/dispenser2.dm
+++ b/code/modules/reagents/dispenser/dispenser2.dm
@@ -117,7 +117,7 @@
to_chat(user, "You set \the [RC] on \the [src].")
SSnano.update_uis(src) // update all UIs attached to src
return TRUE
-
+
return ..()
/obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1)
diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/dispenser/dispenser_presets.dm
index 9415df0e75c..d0f2b5beeb7 100644
--- a/code/modules/reagents/dispenser/dispenser_presets.dm
+++ b/code/modules/reagents/dispenser/dispenser_presets.dm
@@ -44,7 +44,7 @@
/obj/item/chems/chem_disp_cartridge/antibiotics,
/obj/item/chems/chem_disp_cartridge/sedatives
)
-
+
buildable = FALSE
@@ -116,7 +116,7 @@
/obj/item/chems/chem_disp_cartridge/ale,
/obj/item/chems/chem_disp_cartridge/mead
)
-
+
buildable = FALSE
/obj/machinery/chemical_dispenser/bar_coffee
diff --git a/code/modules/reagents/reactions/reaction_recipe.dm b/code/modules/reagents/reactions/reaction_recipe.dm
index e99e1747cd7..6748eb14353 100644
--- a/code/modules/reagents/reactions/reaction_recipe.dm
+++ b/code/modules/reagents/reactions/reaction_recipe.dm
@@ -115,3 +115,59 @@
required_reagents = list(/decl/material/liquid/nutriment/rice = 10, /decl/material/liquid/drink/tea/green = 1)
result_amount = 10
mix_message = "The tea mingles with the rice."
+
+/decl/chemical_reaction/recipe/caramelisation
+ name = "Caramelised Sugar"
+ result = /decl/material/liquid/nutriment/caramelsugar
+ required_reagents = list(/decl/material/liquid/nutriment/sugar = 1)
+ result_amount = 1
+ minimum_temperature = T0C + 82
+ // no maximum! i mean technically it should burn at some point but ehh
+ mix_message = "The sugar melts into a sticky, brown liquid."
+
+/decl/chemical_reaction/recipe/simplesyrup
+ name = "Simple Syrup"
+ result = /decl/material/liquid/drink/syrup/sugar
+ required_reagents = list(/decl/material/liquid/nutriment/sugar = 2, /decl/material/liquid/water = 1) // rich simple syrup, technically, but still
+ result_amount = 3
+ minimum_temperature = T20C + 10
+ maximum_temperature = T0C + 82 // Sugar caramelises after this point.
+ mix_message = "The sugar dissolves into the solution."
+
+/decl/chemical_reaction/recipe/caramelsyrup
+ name = "Caramel Syrup"
+ result = /decl/material/liquid/drink/syrup/caramel
+ required_reagents = list(/decl/material/liquid/nutriment/caramelsugar = 2, /decl/material/liquid/drink/syrup/sugar = 3)
+ result_amount = 5
+ mix_message = "The solution takes on a light brown hue and the aroma of caramel."
+
+/decl/chemical_reaction/recipe/chocosyrup
+ name = "Chocolate Syrup"
+ result = /decl/material/liquid/drink/syrup/chocolate
+ required_reagents = list(/decl/material/liquid/nutriment/coco = 2, /decl/material/liquid/drink/syrup/sugar = 3)
+ result_amount = 5
+ mix_message = "The solution takes on a brown hue and the aroma of chocolate."
+
+/decl/chemical_reaction/recipe/pumpkinsyrup
+ name = "Pumpkin Spice Syrup"
+ result = /decl/material/liquid/drink/syrup/pumpkin
+ required_reagents = list(/decl/material/liquid/drink/juice/pumpkinpulp = 2, /decl/material/liquid/drink/syrup/sugar = 3)
+ result_amount = 5
+ mix_message = "The solution takes on an orange hue and the aroma of pumpkin spice."
+
+// HEARTH EDIT START
+/decl/chemical_reaction/recipe/browniemix
+ name = "Brownie Mix"
+ result = /decl/material/liquid/nutriment/browniemix
+ required_reagents = list(/decl/material/liquid/nutriment/flour = 5, /decl/material/liquid/nutriment/coco = 5, /decl/material/liquid/nutriment/sugar = 5)
+ result_amount = 15
+ mix_message = "The solution is mixed into a light brown powder."
+
+/decl/chemical_reaction/recipe/beerbatter
+ name = "Beer Batter Mix"
+ result = /decl/material/liquid/nutriment/batter/beerbatter
+ required_reagents = list(/decl/material/liquid/nutriment/protein/egg = 3, /decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/ethanol/beer = 5,/decl/material/solid/sodiumchloride = 2)
+ result_amount = 20
+ mix_message = "The solution thickens into a light batter."
+
+ //HEARTH EDIT END
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 7db9020a940..694494ca720 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -59,8 +59,13 @@
return
/obj/item/chems/attackby(obj/item/W, mob/user)
+ if(istype(W, /obj/item/chems/food))
+ var/obj/item/chems/food/dipped = W
+ . = dipped.attempt_apply_coating(src, user)
+ if(.)
+ return .
if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen))
- var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
+ var/tmp_label = sanitize_safe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
if(length(tmp_label) > 10)
to_chat(user, "The label can be at most 10 characters long.")
else
diff --git a/code/modules/reagents/reagent_containers/beaker.dm b/code/modules/reagents/reagent_containers/beaker.dm
index f1d3a34a8de..8fd774f5e2b 100644
--- a/code/modules/reagents/reagent_containers/beaker.dm
+++ b/code/modules/reagents/reagent_containers/beaker.dm
@@ -78,19 +78,6 @@
material_force_multiplier = 0.5
w_class = ITEM_SIZE_LARGE
-/obj/item/chems/glass/beaker/bowl
- name = "mixing bowl"
- desc = "A large mixing bowl."
- icon = 'icons/obj/items/chem/mixingbowl.dmi'
- center_of_mass = @"{'x':16,'y':10}"
- volume = 180
- amount_per_transfer_from_this = 10
- possible_transfer_amounts = @"[5,10,15,25,30,60,180]"
- atom_flags = ATOM_FLAG_OPEN_CONTAINER
- unacidable = 0
- material = /decl/material/solid/metal/steel
- material_force_multiplier = 0.2
-
/obj/item/chems/glass/beaker/noreact
name = "cryostasis beaker"
desc = "A cryostasis beaker that allows for chemical storage without reactions."
@@ -167,4 +154,12 @@
/obj/item/chems/glass/beaker/sulphuric/Initialize()
. = ..()
reagents.add_reagent(/decl/material/liquid/acid, 60)
- update_icon()
\ No newline at end of file
+ update_icon()
+
+/obj/item/chems/glass/beaker/measuringcup
+ name = "measuring cup"
+ desc = "A measuring cup, used to measure ingredients for cooking."
+ icon = 'icons/obj/items/chem/beakers/measuringcup.dmi'
+
+/obj/item/chems/glass/beaker/measuringcup/attack_self()
+ return
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/condiment.dm b/code/modules/reagents/reagent_containers/condiment.dm
index 30256ef845d..ed346a004c8 100644
--- a/code/modules/reagents/reagent_containers/condiment.dm
+++ b/code/modules/reagents/reagent_containers/condiment.dm
@@ -33,7 +33,7 @@
/obj/item/chems/condiment/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen))
- var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
+ var/tmp_label = sanitize_safe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
if(tmp_label == label_text)
return
if(length(tmp_label) > 10)
diff --git a/code/modules/reagents/reagent_containers/drinks/bottle.dm b/code/modules/reagents/reagent_containers/drinks/bottle.dm
index 6fecaaec658..b9fc59a144f 100644
--- a/code/modules/reagents/reagent_containers/drinks/bottle.dm
+++ b/code/modules/reagents/reagent_containers/drinks/bottle.dm
@@ -30,6 +30,9 @@
rag = null
return ..()
+/obj/item/chems/drinks/bottle/on_reagent_change()
+ return
+
//when thrown on impact, bottles smash and spill their contents
/obj/item/chems/drinks/bottle/throw_impact(atom/hit_atom, var/datum/thrownthing/TT)
..()
diff --git a/code/modules/reagents/reagent_containers/drinks/cans.dm b/code/modules/reagents/reagent_containers/drinks/cans.dm
index 8e8cd9acaf5..170ed67a755 100644
--- a/code/modules/reagents/reagent_containers/drinks/cans.dm
+++ b/code/modules/reagents/reagent_containers/drinks/cans.dm
@@ -4,6 +4,9 @@
atom_flags = 0 //starts closed
material = /decl/material/solid/metal/aluminium
+/obj/item/chems/drinks/cans/on_reagent_change()
+ return
+
//DRINKS
/obj/item/chems/drinks/cans/cola
diff --git a/code/modules/reagents/reagent_containers/food.dm b/code/modules/reagents/reagent_containers/food.dm
index 88b9bbc447e..cc11a378f86 100644
--- a/code/modules/reagents/reagent_containers/food.dm
+++ b/code/modules/reagents/reagent_containers/food.dm
@@ -34,6 +34,103 @@
var/trash = null
var/list/attack_products //Items you can craft together. Like bomb making, but with food and less screwdrivers.
// Uses format list(ingredient = result_type). The ingredient can be a typepath or a kitchen_tag string (used for mobs or plants)
+ var/batter_coating = null // coating typepath, NOT decl
+ var/do_coating_prefix = TRUE ///If 0, we wont do "battered thing" or similar prefixes. Mainly for recipes that include batter but have a special name
+ /**
+ * Used for foods that are "cooked" without being made into a specific recipe or combination.
+ * Generally applied during modification cooking with oven/fryer.
+ * Used to stop deep-fried meat from looking like slightly tanned raw meat, and make it actually look cooked.
+ */
+ var/cooked_icon = null
+
+/obj/item/chems/food/standard_pour_into(mob/user, atom/target)
+ return FALSE
+
+//Code for dipping food in batter
+/**
+ * Perform checks, then apply any applicable coatings.
+ *
+ * @param dip /obj The object to attempt to dip src into.
+ * @param user /mob The mob attempting to dip src into dip.
+ *
+ * @return TRUE if coating applied, FALSE otherwise
+ */
+/obj/item/chems/food/proc/attempt_apply_coating(var/obj/dip, var/mob/user)
+ if(!dip || !ATOM_IS_OPEN_CONTAINER(dip) || istype(dip, /obj/item/chems/food) || !Adjacent(user))
+ return
+ for (var/reagent_type in dip.reagents?.reagent_volumes)
+ if(!ispath(reagent_type, /decl/material/liquid/nutriment/batter))
+ continue
+ return apply_coating(dip.reagents, reagent_type, user)
+
+//This proc handles drawing coatings out of a container when this food is dipped into it
+/obj/item/chems/food/proc/apply_coating(var/datum/reagents/holder, var/applied_coating, var/mob/user)
+ if (batter_coating)
+ var/decl/material/coating_reagent = GET_DECL(batter_coating)
+ to_chat(user, "[src] is already coated in [coating_reagent.name]!")
+ return FALSE
+
+ var/decl/material/liquid/nutriment/batter/applied_coating_reagent = GET_DECL(applied_coating)
+
+ //Calculate the reagents of the coating needed
+ var/req = 0
+ for (var/r in reagents.reagent_volumes)
+ if (ispath(r, /decl/material/liquid/nutriment))
+ req += reagents.reagent_volumes[r] * 0.2
+ else
+ req += reagents.reagent_volumes[r] * 0.1
+
+ req += w_class*0.5
+
+ if (!req)
+ //the food has no reagents left, it's probably getting deleted soon
+ return FALSE
+
+ if (holder.reagent_volumes[applied_coating] < req)
+ to_chat(user, SPAN_WARNING("There's not enough [applied_coating_reagent.name] to coat [src]!"))
+ return FALSE
+
+ //First make sure there's space for our batter
+ if (REAGENTS_FREE_SPACE(reagents) < req+5)
+ var/extra = req+5 - REAGENTS_FREE_SPACE(reagents)
+ reagents.maximum_volume += extra
+
+ //Suck the coating out of the holder
+ holder.trans_to_holder(reagents, req)
+
+ if (!REAGENT_VOLUME(reagents, applied_coating))
+ return
+
+ batter_coating = applied_coating
+ var/icon/I = icon(icon, icon_state, dir)
+ color = "#ffffff" //Some fruits use the color var. Reset this so it doesnt tint the batter
+ I.Blend(new /icon('icons/obj/food_custom.dmi', rgb(255,255,255)),ICON_ADD)
+ I.Blend(new /icon('icons/obj/food_custom.dmi', applied_coating_reagent.icon_raw),ICON_MULTIPLY)
+ var/image/J = image(I)
+ J.alpha = 200
+ J.blend_mode = BLEND_OVERLAY
+ add_overlay(J)
+
+ if (user)
+ user.visible_message(SPAN_NOTICE("[user] dips [src] into \the [applied_coating_reagent.name]"), SPAN_NOTICE("You dip [src] into \the [applied_coating_reagent.name]"))
+
+ return TRUE
+
+//Called by cooking machines. This is mainly intended to set properties on the food that differ between raw/cooked
+/obj/item/chems/food/proc/cook()
+ if (batter_coating)
+ cut_overlays()
+ var/decl/material/liquid/nutriment/batter/our_coating = GET_DECL(batter_coating)
+ var/icon/I = icon(icon, icon_state, dir)
+ color = COLOR_WHITE //Some fruits use the color var
+ I.Blend(new /icon('icons/obj/food_custom.dmi', rgb(255,255,255)),ICON_ADD)
+ I.Blend(new /icon('icons/obj/food_custom.dmi', our_coating.icon_cooked),ICON_MULTIPLY)
+ var/image/J = image(I)
+ J.alpha = 200
+ add_overlay(J)
+
+ if (do_coating_prefix)
+ SetName("[our_coating.coated_adj] [name]")
/obj/item/chems/food/standard_pour_into(mob/user, atom/target)
return FALSE
@@ -43,6 +140,10 @@
if(nutriment_amt)
reagents.add_reagent(nutriment_type, nutriment_amt, nutriment_desc)
amount_per_transfer_from_this = bitesize
+ for(var/reagent_type in reagents.reagent_volumes)
+ if(ispath(reagent_type, /decl/material/liquid/nutriment/batter))
+ LAZYINITLIST(reagents.reagent_data)
+ LAZYINITLIST(reagents.reagent_data[reagent_type]) // add a new reagent_data entry for each reagent type
//Placeholder for effect that trigger on eating that aren't tied to reagents.
/obj/item/chems/food/proc/On_Consume(var/mob/M)
diff --git a/code/modules/reagents/reagent_containers/food/eggs.dm b/code/modules/reagents/reagent_containers/food/eggs.dm
index 89c984fc38f..8e268d01b2f 100644
--- a/code/modules/reagents/reagent_containers/food/eggs.dm
+++ b/code/modules/reagents/reagent_containers/food/eggs.dm
@@ -13,8 +13,8 @@
nutriment_type = /decl/material/liquid/nutriment/protein/egg
/obj/item/chems/food/egg/afterattack(obj/O, mob/user, proximity)
- // Don't crack eggs into appliances if you're on help intent.
- if(istype(O,/obj/machinery/microwave))
+ // Don't crack eggs into appliances/cooking containers if you're on help intent.
+ if((user.a_intent == I_HELP) && (istype(O,/obj/machinery/microwave) || istype(O,/obj/item/chems/cooking_container)))
return ..()
if(!(proximity && ATOM_IS_OPEN_CONTAINER(O))) // Must be adjacent and open.
return
diff --git a/code/modules/reagents/reagent_containers/glass/bottle.dm b/code/modules/reagents/reagent_containers/glass/bottle.dm
index 95d76e2df3f..6bbc45295a8 100644
--- a/code/modules/reagents/reagent_containers/glass/bottle.dm
+++ b/code/modules/reagents/reagent_containers/glass/bottle.dm
@@ -38,7 +38,7 @@
/obj/item/chems/glass/bottle/on_update_icon()
..()
cut_overlays()
-
+
if(reagents?.total_volume)
var/percent = round(reagents.total_volume / volume * 100, 25)
add_overlay(mutable_appearance(icon, "[icon_state]_filling_[percent]", reagents.get_color()))
@@ -57,7 +57,7 @@
if (!ATOM_IS_OPEN_CONTAINER(src))
add_overlay(mutable_appearance(icon, "[icon_state]_lid", lid_color))
-
+
compile_overlays()
/obj/item/chems/glass/bottle/Initialize()
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index e83ebb03d6f..b79983979b8 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -113,7 +113,7 @@ var/global/list/diversion_junctions = list()
update_icon()
/obj/machinery/disposal/receive_mouse_drop(atom/dropping, mob/user)
-
+
. = (user?.a_intent != I_HURT && ..())
if(!. && !(stat & BROKEN))
@@ -292,8 +292,8 @@ var/global/list/diversion_junctions = list()
// eject the contents of the disposal unit
/obj/machinery/disposal/proc/eject()
- for(var/atom/movable/AM in (contents - component_parts))
- AM.forceMove(src.loc)
+ for(var/atom/movable/AM in get_contained_external_atoms())
+ AM.dropInto(loc)
AM.pipe_eject(0)
update_icon()
@@ -377,7 +377,7 @@ var/global/list/diversion_junctions = list()
var/wrapcheck = 0
var/obj/structure/disposalholder/H = new() // virtual holder object which actually
// travels through the pipes.
- var/list/stuff = contents - component_parts
+ var/list/stuff = get_contained_external_atoms()
//Hacky test to get drones to mail themselves through disposals.
for(var/mob/living/silicon/robot/drone/D in stuff)
wrapcheck = 1
diff --git a/code/modules/recycling/disposalholder.dm b/code/modules/recycling/disposalholder.dm
index 50c48885dd7..f8f59a9ce98 100644
--- a/code/modules/recycling/disposalholder.dm
+++ b/code/modules/recycling/disposalholder.dm
@@ -20,7 +20,7 @@
// initialize a holder from the contents of a disposal unit
/obj/structure/disposalholder/proc/init(var/obj/machinery/disposal/D, var/datum/gas_mixture/flush_gas)
gas = flush_gas// transfer gas resv. into holder object -- let's be explicit about the data this proc consumes, please.
- var/stuff = D.contents - D.component_parts
+ var/stuff = D.get_contained_external_atoms()
//Check for any living mobs trigger hasmob.
//hasmob effects whether the package goes to cargo or its tagged destination.
hasmob = length(check_mob(stuff))
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 41d463f4278..1f01aadd845 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -44,7 +44,7 @@
else if(istype(W, /obj/item/pen))
switch(alert("What would you like to alter?",,"Title","Description", "Cancel"))
if("Title")
- var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN)
+ var/str = sanitize_safe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN)
if(!str || !length(str))
to_chat(usr, " Invalid text.")
return
@@ -169,7 +169,7 @@
else if(istype(W, /obj/item/pen))
switch(alert("What would you like to alter?",,"Title","Description", "Cancel"))
if("Title")
- var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN)
+ var/str = sanitize_safe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN)
if(!str || !length(str))
to_chat(usr, " Invalid text.")
return
diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm
index 24d2d8cfc8f..0461d7a7873 100644
--- a/code/modules/species/species.dm
+++ b/code/modules/species/species.dm
@@ -823,10 +823,8 @@ var/global/const/DEFAULT_SPECIES_HEALTH = 200
/decl/species/proc/skills_from_age(age) //Converts an age into a skill point allocation modifier. Can be used to give skill point bonuses/penalities not depending on job.
switch(age)
- if(0 to 22) . = -4
- if(23 to 30) . = 0
- if(31 to 45) . = 4
- else . = 8
+ if(0 to 100) . = 4
+ else . = 4
/decl/species/proc/post_organ_rejuvenate(var/obj/item/organ/org, var/mob/living/carbon/human/H)
if(org && (org.species ? org.species.is_crystalline : is_crystalline))
diff --git a/code/modules/sprite_accessories/_accessory_hair.dm b/code/modules/sprite_accessories/_accessory_hair.dm
index 5d1d34d032b..166582929ac 100644
--- a/code/modules/sprite_accessories/_accessory_hair.dm
+++ b/code/modules/sprite_accessories/_accessory_hair.dm
@@ -378,6 +378,10 @@
name = "CIA"
icon_state = "hair_cia"
+/decl/sprite_accessory/hair/wheeler
+ name = "Wheeler"
+ icon_state = "hair_wheeler"
+
/decl/sprite_accessory/hair/mulder
name = "Mulder"
icon_state = "hair_mulder"
diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm
index 7813d66b1d6..e49d5db6643 100644
--- a/code/modules/supermatter/supermatter.dm
+++ b/code/modules/supermatter/supermatter.dm
@@ -621,7 +621,7 @@ var/global/list/supermatter_delam_accent_sounds = list(
/obj/machinery/power/supermatter/attackby(obj/item/W, mob/user)
- if(istype(W, /obj/item/tape_roll))
+ if(istype(W, /obj/item/ducttape))
to_chat(user, "You repair some of the damage to \the [src] with \the [W].")
damage = max(damage -10, 0)
diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm
index 6fccc384d4e..dc39514ae32 100644
--- a/code/modules/surgery/organs_internal.dm
+++ b/code/modules/surgery/organs_internal.dm
@@ -19,7 +19,7 @@
allowed_tools = list(
/obj/item/stack/medical/advanced/bruise_pack = 100,
/obj/item/stack/medical/bruise_pack = 40,
- /obj/item/tape_roll = 20
+ /obj/item/ducttape = 20
)
min_duration = 70
max_duration = 90
diff --git a/code/modules/ventcrawl/ventcrawl_atmospherics.dm b/code/modules/ventcrawl/ventcrawl_atmospherics.dm
index 6097e15ca43..a12184e78e3 100644
--- a/code/modules/ventcrawl/ventcrawl_atmospherics.dm
+++ b/code/modules/ventcrawl/ventcrawl_atmospherics.dm
@@ -15,7 +15,10 @@
/obj/machinery/atmospherics/relaymove(mob/living/user, direction)
if(user.loc != src || !(direction & initialize_directions)) //can't go in a way we aren't connecting to
return
- ventcrawl_to(user,findConnecting(direction),direction)
+
+ // Only cardinals allowed.
+ direction = FIRST_DIR(direction)
+ ventcrawl_to(user,findConnecting(direction), direction)
/obj/machinery/atmospherics/proc/ventcrawl_to(var/mob/living/user, var/obj/machinery/atmospherics/target_move, var/direction)
if(target_move)
diff --git a/code/modules/weather/weather_effects.dm b/code/modules/weather/weather_effects.dm
index d12aad152d7..8499824ddce 100644
--- a/code/modules/weather/weather_effects.dm
+++ b/code/modules/weather/weather_effects.dm
@@ -1,7 +1,7 @@
-/obj/abstract/weather_system/proc/get_movement_delay(var/travel_dir)
+/obj/abstract/weather_system/proc/get_movement_delay(var/datum/gas_mixture/env, var/travel_dir)
// It's quiet. Too quiet.
- if(!wind_direction || !base_wind_delay || !travel_dir)
+ if(!wind_direction || !base_wind_delay || !travel_dir || !env || env.return_pressure() < MIN_WIND_PRESSURE)
return 0
// May the wind be always at your back!
diff --git a/code/modules/weather/weather_wind.dm b/code/modules/weather/weather_wind.dm
index 12add656a2f..2453fe06fdf 100644
--- a/code/modules/weather/weather_wind.dm
+++ b/code/modules/weather/weather_wind.dm
@@ -26,9 +26,13 @@
if(mob_shown_wind[mob_ref])
return FALSE
mob_shown_wind[weakref(M)] = TRUE
- var/absolute_strength = abs(wind_strength)
- if(absolute_strength <= 0.5 || !wind_direction)
- to_chat(M, SPAN_NOTICE("The wind is calm."))
- else
- to_chat(M, SPAN_NOTICE("The wind is blowing[absolute_strength > 2 ? " strongly" : ""] towards the [dir2text(wind_direction)]."))
- return TRUE
+ . = TRUE
+ var/turf/T = get_turf(M)
+ if(istype(T))
+ var/datum/gas_mixture/environment = T.return_air()
+ if(environment && environment.return_pressure() >= MIN_WIND_PRESSURE) // Arbitrary low pressure bound.
+ var/absolute_strength = abs(wind_strength)
+ if(absolute_strength <= 0.5 || !wind_direction)
+ to_chat(M, SPAN_NOTICE("The wind is calm."))
+ else
+ to_chat(M, SPAN_NOTICE("The wind is blowing[absolute_strength > 2 ? " strongly" : ""] towards the [dir2text(wind_direction)]."))
diff --git a/code/procs/announce.dm b/code/procs/announce.dm
index 94d174eb61d..1ce2db213a6 100644
--- a/code/procs/announce.dm
+++ b/code/procs/announce.dm
@@ -47,7 +47,7 @@ var/global/datum/announcement/minor/minor_announcement = new(new_sound = 'sound/
if(!msg_sanitized)
message = sanitize(message, extra = 0)
- message_title = sanitizeSafe(message_title)
+ message_title = sanitize_safe(message_title)
var/msg = FormMessage(message, message_title)
for(var/mob/M in global.player_list)
diff --git a/code/unit_tests/food_tests.dm b/code/unit_tests/food_tests.dm
index 864a5709320..1616786d800 100644
--- a/code/unit_tests/food_tests.dm
+++ b/code/unit_tests/food_tests.dm
@@ -37,3 +37,63 @@
pass("All slice types defined correctly.")
return 1
+
+
+/**
+ * Each recipe's fruit entries should correspond to some plant's kitchen_tag.
+ *
+ * Seed datums define kitchen_tags and traits that determine if they can be
+ * modified in certain ways, while recipes define combinations of tags and
+ * traits that they need to succeed. This test ensures that all entries in
+ * the latter are valid.
+ */
+/datum/unit_test/kitchen_tags
+ name = "FOOD: Recipe fruit entries shall correspond to seeds"
+ var/static/list/modifiers = list("dried", "slice")
+
+/datum/unit_test/kitchen_tags/start_test()
+ var/list/failures = list()
+ var/list/known_tags = list()
+
+ for(var/seedname in SSplants.seeds)
+ var/datum/seed/seed = SSplants.seeds[seedname]
+ if(!seed.roundstart)
+ continue
+ if(!seed.kitchen_tag)
+ continue
+ LAZYADD(known_tags[seed.kitchen_tag], seed)
+
+ var/list/recipe_subtypes = decls_repository.get_decls_of_subtype(/decl/recipe)
+ for (var/recipetype in recipe_subtypes)
+ var/decl/recipe/recipe = recipe_subtypes[recipetype]
+ for(var/fruit_entry in recipe.fruit)
+ var/list/tags = splittext(fruit_entry, " ")
+ if(!length(tags))
+ LAZYADD(failures[recipetype], " - has invalid seed tag '[fruit_entry]'")
+ continue
+ var/base_tag = LAZYACCESS((tags - modifiers), 1)
+ if(!base_tag)
+ LAZYADD(failures[recipetype], " - has fruit entry '[fruit_entry]' that is only modifiers")
+ continue
+ if(!LAZYLEN(known_tags[base_tag]))
+ LAZYADD(failures[recipetype], " - has fruit entry '[fruit_entry]' and no matching seed")
+ continue
+ if("slice" in tags)
+ var/slice_failed = FALSE
+ for(var/datum/seed/S in known_tags[base_tag])
+ if(!S.get_trait(TRAIT_FLESH_COLOUR))
+ LAZYADD(failures[recipetype], " - has fruit entry '[fruit_entry]', but [S.type] cannot be sliced")
+ slice_failed = TRUE
+ continue
+ if(slice_failed)
+ continue
+
+ // Report failures.
+ if(length(failures))
+ var/failtext = ""
+ for(var/failed_recipe in failures)
+ failtext += "\n[failed_recipe]:\n\t[jointext(failures[failed_recipe],"\n\t")]"
+ fail("[length(failures)] /decl/recipe\s failed kitchen tag validation.[failtext]")
+ else
+ pass("All /decl/recipe kitchen tags were validated successfully.")
+ return 1
\ No newline at end of file
diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm
index db1d63e9c97..6bd35d9318e 100644
--- a/code/unit_tests/map_tests.dm
+++ b/code/unit_tests/map_tests.dm
@@ -484,6 +484,34 @@
//=======================================================================================
+/datum/unit_test/disposal_overlap_test
+ name = "MAP: Disposal Pipe Overlap Test"
+
+/datum/unit_test/disposal_overlap_test/start_test()
+ var/disposal_test_count = 0
+ var/bad_tests = 0
+ var/turf/T = null
+ var/obj/structure/disposalpipe/D = null
+ var/list/pipe_turfs = list()
+
+ for(D in world)
+ disposal_test_count++
+ T = get_turf(D)
+ if(pipe_turfs[T])
+ var/bad_msg = "[ascii_red]--------------- [T.name] \[[T.x] / [T.y] / [T.z]\]"
+ bad_tests++
+ log_unit_test("[bad_msg] contains multiple pipes overlapping.")
+ pipe_turfs |= T
+
+ if(bad_tests)
+ fail("\[[bad_tests] / [disposal_test_count]\] Some turfs had overlapping pipes.")
+ else
+ pass("All \[[disposal_test_count]\] pipes did not overlap.")
+
+ return 1
+
+//=======================================================================================
+
// Having them face north or west is now supported fully in code; this is for map consistency.
/datum/unit_test/simple_pipes_shall_not_face_north_or_west
name = "MAP: Simple pipes shall not face north or west"
diff --git a/html/changelog.html b/html/changelog.html
index 8f396269e96..4ad7cae131b 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -52,6 +52,18 @@
-->
+
11 January 2022
+
Gaxeer updated:
+
+ - fix the bug with grab-moving dead mob
+
+
+
03 January 2022
+
tag if you want to specify another name or several people. --> updated:
+
+ - fix looping APC power down sound
+
+
04 December 2021
MistakeNot4892 updated:
@@ -194,6 +206,408 @@ CrimsonShrike updated:
- Adds a number of exosuit modules
- Resprites exosuits
+
+
08 October 2021
+
PsyCommando updated:
+
+ - Makes changing a var type in VV take a type path string instead of having the slow nearly useless listbox with all the atom types listed in.
+
+
+
06 October 2021
+
MistakeNot4892 updated:
+
+ - All energy weapons (ninja blade, esword, energy axe, energy cutlass, energy machete) can be used as scalpels when they are energized.
+ - Energy swords can be used to slice open safes, lockers, windoors and tables a la the ninja blade when they are energized.
+
+
+
05 October 2021
+
lolman360 updated:
+
+ - fixes charge pylon (electron reservoir) from shocking adherents
+
+
+
03 October 2021
+
MarinaGryphon updated:
+
+ - fixes the emote keybind creating two windows
+
+
+
02 October 2021
+
MarinaGryphon updated:
+
+ - Fixes body scanners not showing organ damage
+
+
chaoko99 updated:
+
+ - Very slight color adjustments to the skybox underlay.
+ - New combat shield sprite.
+
+
+
01 October 2021
+
Andromeda-K22 updated:
+
+ - the player panel has been moved - can still be accessed by the usual verbs and right-click context menu.
+
+
+
23 September 2021
+
NataKilar updated:
+
+ - Camera networks are now known as channels and are not tied to access.
+ - Security cameras are now tied directly to computer networks, and can be managed as with other network devices.
+
+
+
21 September 2021
+
Gr1lledcheese updated:
+
+ - Fixes windoor electronics icon
+
+
+
17 September 2021
+
Andromeda-K22 updated:
+
+ - air alarms now sound different.
+
+
MistakeNot4892 updated:
+
+ - Ports geothermal generators from Europa.
+
+
SolatK updated:
+
+ - a credit-stick can be inserted into an ATM
+ - The tail is now a separate limb. You can select it as target, and button is shown when you look at somebody with a tail.
+
+
+
15 September 2021
+
PsyCommando updated:
+
+ - Prevent APC runtime spam when in a null area.
+
+
+
14 September 2021
+
Geevies updated:
+
+ - Species now have special footprint handling when walking on simulated turfs, though no core species has anything implemented yet.
+
+
SolatK updated:
+
+ - Avians can wear gloves.
+
+
+
12 September 2021
+
Andromeda-K22 updated:
+
+ - adds the 'strut' material stack, used for a number of items.
+ - metal sheets are no longer used for many things, struts are used instead.
+
+
+
11 September 2021
+
Andromeda-K22 updated:
+
+
SolatK updated:
+
+ - Fixes accessory offsets for avians
+
+
+
09 September 2021
+
Andromeda-K22 updated:
+
+ - updated the UI on species selection
+ - species selection is now in the background tab.
+ - the pda screen is now an overlay.
+
+
+
05 September 2021
+
comma updated:
+
+ - Planet types are now weighted, with some (barren and shrouded) spawning less often than normal ones
+ - Adds meat planets made of meat (rarer spawn)
+
+
+
03 September 2021
+
MistakeNot4892 updated:
+
+ - A BYOND emblem modpack has been added that adds an emblem to OOC chatter from people with membership. Defaults to unincluded.
+
+
PsyCommando updated:
+
+ - Fix occasional runtime in mob/Destroy() when deleting an ai var that wasn't initialized yet.
+
+
comma updated:
+
+ - Added more hints to xenoarch effects
+
+
+
01 September 2021
+
PsyCommando updated:
+
+ - DNA now properly keep track of facial hair color independently from hair color as it was intended.
+ - Fix skillset not being a path on mob init crashing mob/Initialize().
+
+
+
29 August 2021
+
Andromeda-K22 updated:
+
+ - handcarts are now a thing. control-click a pullable atom, then click the cart with them to load them on. Only works with ITEMS and OBJECTS, not PEOPLE. Items have a minimum size to be loaded onto the cart.
+ - wheeled objects should now be given ATOM_FLAG_WHEELED and are easier and less exhausting to move.
+ - the skill requirements for landing properly during the gravity failure event has been changed from professional to trained.
+
+
+
26 August 2021
+
Andromeda-K22 updated:
+
+ - gas filters no longer use hardcoded modes (i.e ATM_N2), they now use gas decls and a list that is dynamically generated.
+
+
PsyCommando updated:
+
+ - Make curtains use decl instead of several subtypes.
+
+
+
24 August 2021
+
Andromeda-K22 updated:
+
+ - the supermatter now makes noises depending on damage.
+ - the supermatter now glows if severely damaged, and changes contrast / color
+
+
+
22 August 2021
+
PsyCommando updated:
+
+ - Logging procs don't crash when used during early init anymore.
+
+
+
15 August 2021
+
comma updated:
+
+ - Instead of selecting bottle sprite, you can now select lid and label color
+ - Sprites for bottles and beakers were changed
+
+
+
03 August 2021
+
MistakeNot4892 updated:
+
+ - Supply beacons no longer need a wire under them to function.
+
+
+
02 August 2021
+
PsyCommando updated:
+
+ - Fix reinforced floor being impossible to build due to a bug.
+
+
+
31 July 2021
+
PsyCommando updated:
+
+ - Made material doors less loud.
+ - Made a few machines stop reporting they're not receiving power when they do not need power at all.
+
+
+
30 July 2021
+
Gr1lledcheese updated:
+
+ - Adds different levels of the CE_OXYGENATED effect
+
+
+
28 July 2021
+
quardbreak updated:
+
+ - Skybox transit overlay now should be more noticeable than before.
+
+
+
24 July 2021
+
Nyxodile updated:
+
+ - Backend fixes for mobile ladders.
+ - Fixes toggling plated catwalks.
+ - Fixes Wi-Fi bypass.
+ - Minor fireaxe attack fix.
+
+
Tennessee116 updated:
+
+ - A cell charger has been added to the research lab of the tradeship!
+
+
+
22 July 2021
+
retlaw34 updated:
+
+ - Added new fuel port sprites.
+
+
+
19 July 2021
+
PsyCommando updated:
+
+ - Allow anchoring/unanchoring closets/crates to the ground.
+ - Added the access_button_off icon state
+
+
+
18 July 2021
+
CrimsonShrike and quardbreak updated:
+
+ - Ported pool tiles and related to pool objects. You can build pool and keep water inside it.
+
+
+
17 July 2021
+
Azlan (as the sprite author) and quardbreak updated:
+
+ - Replaced Supermatter sprites with ones by Azlan.
+
+
+
16 July 2021
+
PsyCommando updated:
+
+ - Fixed shutters and blast doors deconstructed and panel_open state being unreachable.
+ - Fixed shutters assemblies having the wrong icon.
+ - Fixed shutters deconstructing to blast door assemblies.
+
+
+
15 July 2021
+
quardbreak updated:
+
+ - New IV drip sprites from Haven-Urist.
+
+
+
13 July 2021
+
Geeves updated:
+
+ - AI can now turn their holograms without moving by using the eastface, westface, northface, and southface macros.
+
+
+
12 July 2021
+
greggbot updated:
+
+ - PDAs are now constructable
+
+
+
11 July 2021
+
MoondancerPony updated:
+
+ - Replaces the HTML microwave UI with a new NanoUI-based one, complete with an animated progress bar!
+ - Microwave recipes can now be made in bulk by multiplying the recipe amounts.
+
+
+
10 July 2021
+
Geeves updated:
+
+ - Added a sound to falling over, willingly resting does not play the sound, however.
+
+
Gr1lledcheese updated:
+
+ - Made oxygel scannable
+
+
+
06 July 2021
+
MistakeNot4892 updated:
+
+ - Ports the aspect system from Europa, specifically the backend, not the aspects themselves. This is a menu in character preferences that allows you to pick a series of traits for your character, as in some RPGs.
+ - Moves prosthetic limbs, prosthetic organs, amputated limbs and nearsightedness onto aspects instead of the Physical tab.
+ - Moves preview options from the Physical tab to the header of character preferences.
+
+
+
02 July 2021
+
NataKilar updated:
+
+ - Fusion fuel compressor can now create fuel rods of mixed materials.
+ - Added fission reactor to the game for isotope and power generation
+
+
+
27 June 2021
+
quardbreak and Pawn updated:
+
+ - Added a picnic basket. Sprites made by Pawn.
+
+
+
20 June 2021
+
CakeQ updated:
+
+ - Walls can now connect to walls of other types depending on their material by comparing material wall icons
+
+
NataKilar updated:
+
+ - You can now build landable ships by toggling docking beacons to construction mode.
+
+
PsyCommando updated:
+
+ - Added Ice extractor.
+ - Added a placeholder icon for the extractor.
+
+
SierraKomodo updated:
+
+ - Ghosts will no longer break skill checks for helm controls.
+ - Ship helm consoles now only allow a single person to use manual control at a time, including viewing the overmap through the helm.
+ - Messages are now displayed whenever another mob takes control of a helm control, to make it outwardly obvious who's skills are used to calculate flight.
+ - Debug log messages were added for helm control changes, for tracking of potential issues on live.
+
+
+
16 June 2021
+
SierraKomodo updated:
+
+ - There is now a user feedback message for wiring a window.
+ - You can now de-polarize a window by using wirecutters to remove the wiring.
+ - The set id prompt when using multitools on polarized windows now defaults to the current id instead of null.
+ - Using a multitool on an anchored (fully installed) window now toggles the tint instead of changing the ID. To change the ID, unanchor the window first.
+ - Examining windows now tells you if they are anchored and/or polarized, and the construction state (screwdriver/crowbar steps) of reinforced windows.
+
+
+
12 June 2021
+
CakeQ updated:
+
+ - Added two new layers to walls, paint and striping. Walls will now maintain their material coloring, and instead have paint colors applied as paint layers on top. Standard walls can be painted two-tone with the main body and striping (wooden walls too).
+ - Wall paintability is now defined by their materials.
+ - Removed legacy wall stripe system in favor of the new paint striping.
+ - Wall edge connections to things like windows and airlocks have been simplified, fixing a few erroneous connections.
+ - The paint sprayer has finer control when interacting with walls and wall frames.
+ - Renamed airlock paint flags to be generic. These are now also used for defining wall paintability.
+
+
MoondancerPony updated:
+
+ - Trays now use vis_contents, so you can interact with tray objects by clicking on them.
+ - Trays no longer drop their contents when set on a table.
+ - Storage UIs now ignore pixel_x and pixel_y when displaying items.
+
+
+
30 May 2021
+
Coltrane97 updated:
+
+ - Missing wall-mounted relay circuitboard
+ - Network cables dupe
+ - Network cables can now pass through z-levels
+
+
+
27 May 2021
+
comma updated:
+
+ - Melee weapons now actually use their armor penetration values against armor
+
+
+
20 May 2021
+
Andromeda-K22 updated:
+
+ - AIs can now have a default holopad color tone set, and set their own color tone for on-station/ship holopad rendering.
+
+
koboldlove updated:
+
+ - fixed the character creation preview sometimes not updating when changed or loaded
+
+
+
14 May 2021
+
MistakeNot4892 updated:
+
+ - Double-clicking to see turf contents is now a preference. You can choose alt click (default), double click or nothing.
+
+
+
12 May 2021
+
MistakeNot4892 updated:
+
+ - Fluid interactions with atoms have been disabled until they can be optimized to be less of a server killer. Mobs will still drown, you just won't melt in acid. On the plus side, fluids are more performant now.
+ - Records now have their own area in character preferences.
+
+
+
11 May 2021
+
Coltrane97 updated:
+
+ - Identification cards now properly get their account number; ATM third-level security will work.
+
+
+
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index e9d514fe60c..8c5bd547e8d 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -4726,7 +4726,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
disadvantages.
- rscadd: Modified the SolGov Pilot job, so they can properly pilot the Torch.
- rscadd: Added randomly placed events to the overmap.
- - maptweak: The Calypso, Aquila and Guppy are now overmap-capable, and can travel
+ - maptweak: The Spirit, Perseverance and Opportunity are now overmap-capable, and can travel
to away sites on the same overmap tile.
- maptweak: Added Helm and Engine control consoles to the bridge, and Engine controls
to engineering monitoring and the fuel bay.
@@ -5184,12 +5184,12 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Can now scoop corgis up, like cats or nymphs etc.
- rscdel: Can also use them instead of sausages in microwave to make hotdogs. Geddit,
hehehe hot dogs. Riot.
- - tweak: GUPpy, Calypso and Aquila now can share destinations, as long as they can
+ - tweak: Opportunity, Spirit and Perseverance now can share destinations, as long as they can
fit.
- rscadd: Excavation prep closets now have BLUESPACE FLARES. You can activate those
in a nice open spot to create a new navpoints for shuttles (ones mentioned)
to go to.
- - rscadd: Exploration shuttles (Calypso/Guppy/Aquila) now can share destinations
+ - rscadd: Exploration shuttles (Spirit/Opportunity/Perseverance) now can share destinations
(with some other shuttles too).
Heptagon49:
- tweak: Replaced the synthetic lung sprites with something more realistic/futuristic.
@@ -5411,8 +5411,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
from main grid, for example through solars.
- rscadd: SMES and PSU units can now have more than one input terminal at once.
Broseph Stylin:
- - tweak: Changed access requirements aboard the Aquila. Helm and Secure Storage
- remain as Aquila-specific access, but all other areas have been made SCG Crew
+ - tweak: Changed access requirements aboard the Perseverance. Helm and Secure Storage
+ remain as Perseverance-specific access, but all other areas have been made SCG Crew
or all-access.
- tweak: Changed sidearm cabinet access requirements. Only line officers, the RD,
the SEA, and the Brig Officer can unlock them now.
@@ -5604,7 +5604,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
ThatOneGuy:
- rscadd: Can now play as the Explorer Department if you are a EC member. If a complete
failure, up for removal.
- - rscadd: Calypso remapped for more cargo space and crew area. Bathroom and Cryo
+ - rscadd: Spirit remapped for more cargo space and crew area. Bathroom and Cryo
deleted.
TheGreyWolf:
- rscadd: Fixed up pathfinder and explorer loadout.
@@ -5636,7 +5636,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Room.
2017-09-08:
Chinsky:
- - rscadd: Calypso is dead, new shuttle is here in same role - Charon.
+ - rscadd: Spirit is dead, new shuttle is here in same role - Spirit.
- rscadd: Can now hide custom loadout items that are not allowed for your job. The
button's in top of loadout menu. Makes browsing less of pain for those with
lots of restrictions.
@@ -5656,7 +5656,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
once (cost lowered from 80 to 20).
- bugfix: Soulstones should work properly now.
Minijar:
- - rscadd: Adds pilot voidsuits to the Calypso along with a cycler.
+ - rscadd: Adds pilot voidsuits to the Spirit along with a cycler.
TheGreyWolf:
- rscdel: Removes the Zhan-Khazan outfit from the loadout (Taj relevant only).
- rscadd: Added a NT pilot specific voidsuit, currently none are mapped in.
@@ -5888,7 +5888,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
up and help you visually signal stuff.
mkalash:
- rscadd: Added a net gun. It and a bandolier full of net shells is located in the
- Charon storage area.
+ Spirit storage area.
- rscadd: Added stasis cages for transport of alien fauna without having them suffocate,
located in expedition storage.
- maptweak: Refitted xenobiology to support changing the atmosphere of animal pens.
@@ -5930,8 +5930,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Changes to Torch's speed. Now default delay between moving is higher -
20 seconds vs 12, but speed affects it much more, e.g. at 5 speed you will move
pretty much continuously.
- - rscadd: Shuttles have different ranges now. Charon (1) can go to away missions
- in adjacent grids, Aquila (2) one tile further. Travel time is multiplied by
+ - rscadd: Shuttles have different ranges now. Spirit (1) can go to away missions
+ in adjacent grids, Perseverance (2) one tile further. Travel time is multiplied by
the distance.
Cirra:
- rscadd: 'Added a new, more expensive type of 14.5mm ammo, for the anti-material
@@ -6181,7 +6181,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
should be more or less same, but less eternal fires and more space for engies
to increase said thrust.
dryerlint:
- - rscadd: Added fuel port object. When mapped into shuttles (like Charon or GUP)
+ - rscadd: Added fuel port object. When mapped into shuttles (like Spirit or GUP)
it gives them a finite fuel reserve, which must be refilled with phoron.
mkalash:
- tweak: You can now place crowbars in security belts.
@@ -6221,7 +6221,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
machinery with a multitool through the UI. The UI also shows a timer until automated
reset.
dryerlint:
- - rscadd: Added fuel ports to Charon and GUP. They will consume fuel and eventually
+ - rscadd: Added fuel ports to Spirit and GUP. They will consume fuel and eventually
run out
- rscadd: Added small refueling room to Hangar, for anyone with Supply Warehouse
access
@@ -6256,14 +6256,14 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Kelenius:
- tweak: Teleporters don't need to be test-fired anymore.
sabiram:
- - tweak: The XO now has unrestricted access to the Aquila.
+ - tweak: The XO now has unrestricted access to the Perseverance.
2017-11-26:
CrimsonShrike:
- bugfix: '"Fixes openspaces above shuttles retaining image of the floor."'
chinsky:
- tweak: Melee attacks will now always hit targets with the Help intent selected.
comma:
- - rscadd: Added EC directives plaques on Bridge/Charon/Exped Prep/walls near flags
+ - rscadd: Added EC directives plaques on Bridge/Spirit/Exped Prep/walls near flags
in cryo etc. Their tl;dr is go explore instead of twiddling thumbs.
sabiram:
- rscadd: Added purple, orange, green and red carpets.
@@ -6419,9 +6419,9 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2017-12-11:
Orelbon:
- maptweak: Xenobotany Has been remapped for space and usability.
- - maptweak: Xenoarchiology lab has been moved to the Petrov.
+ - maptweak: Xenoarchiology lab has been moved to the Curiosity.
- maptweak: Misc Lab is now a circuit lab and a small chemical testing chamber.
- - maptweak: A chemistry station & toxins have been added to the Petrov.
+ - maptweak: A chemistry station & toxins have been added to the Curiosity.
Techhead0:
- rscdel: Science wing and channel has been reverted back to purple.
dryerlint:
@@ -6580,7 +6580,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2018-01-09:
Devildabeast:
- rscdel: Removes SolGov Pilot.
- - tweak: Gives Bridge Officers access to pilot the Aquila and Guppy and accompanying
+ - tweak: Gives Bridge Officers access to pilot the Perseverance and Opportunity and accompanying
access.
- tweak: Bridge Officers now have the Pilot's headset.
- rscdel: Removes SolGov Pilot's locker from the Pilot's Lounge.
@@ -6746,7 +6746,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2018-01-19:
Sbotkin:
- maptweak: The Pilot Lounge has been replaced with the Pathfinder's Office.
- - maptweak: The NT pilot's voidsuit has been moved to the Petrov, with the cycler.
+ - maptweak: The NT pilot's voidsuit has been moved to the Curiosity, with the cycler.
Techhead:
- rscadd: Corpsman and Engineers have been granted access to the hangar to help
them go on expeditions. Or help with the inevitable injuries and damage from
@@ -7623,7 +7623,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
or - at worst - having no icons at all.
2018-05-16:
Banditoz:
- - maptweak: Remaps the Petrov toxins lab to be more intuitive to use.
+ - maptweak: Remaps the Curiosity toxins lab to be more intuitive to use.
- tweak: Powered crossbows have been buffed. You don't need to draw back as much,
and it takes less time to do so.
2018-05-17:
@@ -7800,8 +7800,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Attempting to move a bike or gyroscooter while stunned will now eject you.
2018-06-10:
Banditoz:
- - maptweak: The Aquila has been divided into areas, and remapped a bit.
- - rscdel: The Aquila's death trap has been removed.
+ - maptweak: The Perseverance has been divided into areas, and remapped a bit.
+ - rscdel: The Perseverance's death trap has been removed.
2018-06-11:
BlueNexus:
- tweak: Increased TC costs for railguns
@@ -8225,8 +8225,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Taking Torch's helm without at least Trained skill can make Torch go not
exactly where you want it to go. At Professional, passing meteor fields is less
painful.
- - rscadd: Shuttles require different level of skill. Guppy is no-skill, Charon and
- Aquila need at least Basic. For purposes of skill, pilot is whoever tells it
+ - rscadd: Shuttles require different level of skill. Opportunity is no-skill, Spirit and
+ Perseverance need at least Basic. For purposes of skill, pilot is whoever tells it
to move in console.
- rscadd: If pilot's skill is insufficient, you can end up in wrong place. Also
travel time is affected by skill.
@@ -8449,7 +8449,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2018-07-25:
Chinsky:
- tweak: Telecomms relays power usage is upper /considerably/ when used off-ship.
- Expect to drain Charon in 10 minutes when you switch it on.
+ Expect to drain Spirit in 10 minutes when you switch it on.
- tweak: Having Trained or above Close Combat skill gives bonus to parry chance
with weapons (even ones that don't parry normally).
- tweak: Melee accuracy is now affected by size of the weapon - smaller than 'normal
@@ -9054,7 +9054,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Deck 4 - The toxins storage room is now directly off the hangar in order
to let scientists actually get to their toxins storage room. Finally adds a
security camera to the fuel bay. The AI can now watch the fascinating process
- of refueling. Moves the atmos control computer in the Petrov Laboratory so that
+ of refueling. Moves the atmos control computer in the Curiosity Laboratory so that
you can actually reach all the counter space when working.
- bugfix: Had a long discussion with the OR computers and we both agreed that they
need to actually face the direction they were mapped in.
@@ -9095,7 +9095,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2018-09-28:
sabiram:
- tweak: Added a delay to welding/unwelding airlocks.
- - tweak: Xenolife Technicians no longer have access to the fabrication lab or Petrov
+ - tweak: Xenolife Technicians no longer have access to the fabrication lab or Curiosity
helm.
2018-09-30:
Cakey:
@@ -9107,17 +9107,17 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
(Still accessible from cryogenics).
- maptweak: The officer's mess has been moved under the mess hall and now overlooks
the hangar (Still accessible from the mess hall).
- - maptweak: The Petrov has been made slightly bigger to be more useful. Moved several
- research suites to the Petrov.
+ - maptweak: The Curiosity has been made slightly bigger to be more useful. Moved several
+ research suites to the Curiosity.
- tweak: The Research Director and Corporate Liason can now use the ID program to
- modify accesses within their own department. Petrov accesses are now only modifiable
+ modify accesses within their own department. Curiosity accesses are now only modifiable
by the Research Director and NTL
- tweak: Fixes the commissarry shutter access requirement.
Miraviel:
- maptweak: Repositioned lights in the SEA's office, the XO's and CO's request consoles,
the fire extinguisher cabinets on the Bridge, the labels at the stairs, and
the CO's light switch. Removed the overlapping Nanomed from the Bridge and the
- urinal from the Aquila.
+ urinal from the Perseverance.
2018-10-02:
Cakey:
- maptweak: 'Made maintenance style-consistent throughout all decks with techmaint
@@ -9126,7 +9126,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Added a single seat in the lounge facing space, which takes up barely
any extra space.
- maptweak: Added a fax machine to the pilot's lounge.
- - tweak: Fixed Petrov airlock accesses.
+ - tweak: Fixed Curiosity airlock accesses.
- tweak: Fixed Hangar maintenance airlock accesses.
ParadoxSpace:
- rscadd: After complaints that Unathi would have to be cut open [stack overflow]
@@ -9182,7 +9182,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
sabiram:
- maptweak: The hallway leading from the elevator to engineering in the maintenance
deck has been re-opened.
- - maptweak: Moved security guard lockers from Petrov to the main checkpoint.
+ - maptweak: Moved security guard lockers from Curiosity to the main checkpoint.
2018-10-04:
CrimsonShrike:
- bugfix: Rotating should no longer make science floor disassemble.
@@ -9264,7 +9264,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Tweaked several areas within maintenance after feedback. Removed majority
of railings.
- maptweak: Fixed shutoff valve layout on decks 4 and 5.
- - maptweak: Swapped Petrov air pump with one that starts as on.
+ - maptweak: Swapped Curiosity air pump with one that starts as on.
- tweak: Railings can now be wrenched open to allow passage, and the time it takes
to climb railing has been reduced from 5 seconds to 1.25 seconds.
- maptweak: Fixes merchant base accesses.
@@ -9272,13 +9272,13 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Fixes lack of cameras on D5.
- maptweak: Fixes dark spot on D4 fore hallway.
- maptweak: Adds consoles to pilot's lounge, exploration prep.
- - maptweak: Adds suit sensors/camera monitoring console to Charon.
+ - maptweak: Adds suit sensors/camera monitoring console to Spirit.
- maptweak: Adds exploration network cameras to explorer helmets.
- maptweak: Gives the shuttle pilot access to explorer camera network, suit sensors
monitoring.
- maptweak: Fixes noticeboard placement around the map, added extra noticeboards
to departments that lacked one.
- - tweak: Fixes Petrov camera network, only accessible by LLC employees.
+ - tweak: Fixes Curiosity camera network, only accessible by LLC employees.
Chinsky:
- tweak: Disarming is now riskier. There's a chance to hurt your hand on the weapon
you're going for instead, with chance adjusted based on skill difference / being
@@ -9300,13 +9300,13 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Changes Keycard Authentication Device interface to NanoUI
2018-10-16:
Cakey:
- - maptweak: Fixes Petrov isolation cell alarm placement.
+ - maptweak: Fixes Curiosity isolation cell alarm placement.
- maptweak: Added sticky notes to offices around the ship.
- maptweak: Added noticeboard to head of staff offices where missing.
- maptweak: Added missing air alarms to hangar, hangar storage.
- maptweak: Fixes hangar exit button access.
- - maptweak: The Aquila is now overmap-capable.
- - maptweak: The Guppy has been given some extra cargo space.
+ - maptweak: The Perseverance is now overmap-capable.
+ - maptweak: The Opportunity has been given some extra cargo space.
Roland410:
- tweak: Changes Tower deity spells to have more charges, and the fountain of power
only takes 30 seconds to recharge it.
@@ -9371,7 +9371,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Changes Torch Ltd. to Expeditionary Corps Organisation in several spots.
- tweak: Adds DAIS labcoat to roboticist and biomech engineer loadouts.
sierrakomodo:
- - rscadd: Bridge Officers now have access to the Charon's Airlock and Charon's Helm
+ - rscadd: Bridge Officers now have access to the Spirit's Airlock and Spirit's Helm
2018-10-24:
Anticept:
- tweak: All pipes, except fuel pipes, now have the same pressure damage threshold.
@@ -9559,7 +9559,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- bugfix: Crashed pod should no longer have random space tiles causing constant
air flow/air loss.
SierraKomodo:
- - tweak: Charon and Aquila APCs now include helm access flags, meaning anyone who
+ - tweak: Spirit and Perseverance APCs now include helm access flags, meaning anyone who
can access the shuttle's helm can also unlock the shuttle's APCs. Engineers
still have APC access as well.
afterthought2:
@@ -9816,8 +9816,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Anticept:
- tweak: 'XO default access is no longer spotty. It now has access to the entire
ship and shuttles, including research. Specific changes: Added robotics, all
- of research including petrov, Pilot, Mining, and Commisary. Places XO does not
- have access: Captain, Research Director''s office, Research Director''s Petrov
+ of research including curiosity, Pilot, Mining, and Commisary. Places XO does not
+ have access: Captain, Research Director''s office, Research Director''s Curiosity
Office, SolGov Rep, and Corporate Liason.'
- rscdel: Removed Genetics access from the game.
- tweak: Renamed "Nanotrasen" in the access computer program to "Corporate".
@@ -9911,7 +9911,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
mechanics are still same.
- tweak: Only 1 random alien seed in Xenoflora storage now, and can't order them
from cargo. Go on expeditions nerds.
- - maptweak: No more pre-spawned anomalies on Petrov. Go on expeditions nerds.
+ - maptweak: No more pre-spawned anomalies on Curiosity. Go on expeditions nerds.
lorwp:
- tweak: IPCs can now use the Command Hardsuits
2019-01-11:
@@ -10107,7 +10107,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Added "Asset Protection Agent" as an alt title to LPA.
- tweak: You can now put people onto wall frames with grabs
Chinsky:
- - rscadd: Added an exploration shotgun. It's in a wall locker on Charon, along with
+ - rscadd: Added an exploration shotgun. It's in a wall locker on Spirit, along with
ammo, replacing netgun. What can possibly go wrong?
- rscadd: It can fire freely off-ship, but onboard you gotta register and get XO
or CO to authorize it. Yes it's pain, yes it's intended.
@@ -10131,7 +10131,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Labcoats can now be issued via the uniform vendor for EC science people.
sabiram:
- rscadd: Added the CSO's rigsuit.
- - maptweak: Removed the AMI rigsuit module from the CSO's Petrov office and added
+ - maptweak: Removed the AMI rigsuit module from the CSO's Curiosity office and added
the new rigsuit to the bridge EVA storage.
- maptweak: Resized and reorganised the bridge EVA storage.
- rscadd: 'Added new wood material types: mahogany, maple, walnut, and ebony. These
@@ -10140,12 +10140,12 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Several tables and chairs across the ship that were previously generic
wood are now made from mahogany, maple, or walnut.
- maptweak: Shuffled things around a bit in the captain's quadrant.
- - maptweak: Moved the CSO's primary office back to the bridge, from the Petrov.
+ - maptweak: Moved the CSO's primary office back to the bridge, from the Curiosity.
- rscadd: Clipboards are now a material item and can be constructed from most materials.
Clipboards that spawn around the map will be of various materials.
2019-02-06:
ghostsheet:
- - maptweak: Rearranged the Guppy's interior for quality of life conveniences.
+ - maptweak: Rearranged the Opportunity's interior for quality of life conveniences.
sabiram:
- rscadd: Radiation collector arrays will now fail catastrophically if exposed to
extreme temperatures, such as those found within the supermatter core.
@@ -10260,7 +10260,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
help intent.
afterthought2:
- experiment: No stasis bags are available on spawn on the Torch, except one on
- the Charon.
+ the Spirit.
- tweak: Stasis bags can now be printed from the protolathe.
- tweak: Stasis bags are now more expensive when ordered from supply.
- tweak: Rollerbeds can now be placed in backpacks.
@@ -10344,9 +10344,9 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2019-02-28:
SierraKomodo:
- bugfix: Senior Researcher now has standard sol gov crew access (Notably, access
- to the bridge foyer and firing range), maintenance access, and Petrov security
+ to the bridge foyer and firing range), maintenance access, and Curiosity security
checkpoint access.
- - bugfix: Fixed access flags for bridge foyer, charon guppy and aquila airlocks,
+ - bugfix: Fixed access flags for bridge foyer, spirit opportunity and perseverance airlocks,
communal brig, and supply office windoor.
- bugfix: Counselors can now access medical storage again
- bugfix: Bridge EVA storage windoors have the proper access restrictions again
@@ -10372,7 +10372,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Surgery will now present a list of possible surgeries (if skilled enough)
rather than using a priority system.
SierraKomodo:
- - tweak: Renamed NSV Petrov area tags to SRV Petrov.
+ - tweak: Renamed NSV Curiosity area tags to SRV Curiosity.
- tweak: Soviet Cola has been renamed to TerraCola.
mikomyazaki2:
- bugfix: Corpsmen can use the Paramedic alt-title again.
@@ -10550,8 +10550,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- bugfix: Inappropriate crew and passengers no longer have supply program admin
rights.
afterthought2:
- - tweak: Petrov and research access can now only be granted by the XO and CO. You
- can now build/adjust access on Petrov doors.
+ - tweak: Curiosity and research access can now only be granted by the XO and CO. You
+ can now build/adjust access on Curiosity doors.
mikomyazaki:
- bugfix: Booze-o-mat contained a tea master item rather than actual actual tea.
Made it contain black tea instead.
@@ -10813,8 +10813,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- admin: A new admin tool, Toggle Harddelete Queue, has been added to the Secrets
panel, under Debug. Do not use this unless you know what you're doing.
ghostsheet:
- - rscadd: Carp shoal map hazard now works for overmap shuttles such as the Charon,
- Aquila and Guppy.
+ - rscadd: Carp shoal map hazard now works for overmap shuttles such as the Spirit,
+ Perseverance and Opportunity.
- bugfix: Fire alarm can now be constructed properly
2019-04-06:
Banditoz:
@@ -10842,7 +10842,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Ore boxes can now be ordered in supply
2019-04-08:
Chinsky:
- - tweak: Charon and Guppy now only need Basic skill for flying on overmap without
+ - tweak: Spirit and Opportunity now only need Basic skill for flying on overmap without
random turns.
2019-04-09:
ChaosAlpha:
@@ -10900,7 +10900,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Added speed indication to helm console. Green means 'slow', red means
'too fast'.
- rscadd: Pilotable shuttles now can pass through meteor fields safely. Keep at
- green speed and you'll make it. Need Trained skill for Charon/Aquila and Basic
+ green speed and you'll make it. Need Trained skill for Spirit/Perseverance and Basic
for GUP. At Master/Experienced can do this at normal speed too.
- tweak: Torch now accelerates roughly 2x slower
Cronac:
@@ -10918,7 +10918,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
back 300 years.
myazaki:
- bugfix: Corrects piloting skill description to reflect recent change to basic
- training with Charon and GUP movement.
+ training with Spirit and GUP movement.
zaredman:
- tweak: Security Equipment supply order replaced with Master at Arms supply order.
- tweak: Auto-Compressor and Rescue Bags can now be ordered via Supply.
@@ -10945,7 +10945,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Three new random events have been added
- tweak: The T-ray scanner can now inspect disposal pipes for damage
Chinsky:
- - maptweak: Charon laoyout changed, it now has a cargo bay that can be cycled to
+ - maptweak: Spirit laoyout changed, it now has a cargo bay that can be cycled to
outside air.
Crackers5:
- rscdel: Removes some existing body markings
@@ -11238,9 +11238,9 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Robotics now gets two loaded toolbelts and multitools instead of one,
as well as two pairs of insulated gloves.
SierraKomodo:
- - maptweak: Various map tweaks to Aquila to fix clickable sprites being under other
+ - maptweak: Various map tweaks to Perseverance to fix clickable sprites being under other
sprites and other mapping nonsense.
- - maptweak: The Charon power compartment has a camera again.
+ - maptweak: The Spirit power compartment has a camera again.
ghostsheet:
- rscadd: Medical drop pouch and Medical webbing is now available on the loadout
to medical trainee, chemist and biomech.
@@ -11294,7 +11294,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- maptweak: Adds said helmet in the fire closets, to replace the already existing
red hardhat.
- maptweak: Adds fire closets throughout the ship.
- - maptweak: Adds fire closets in the Charon and the Aquila.
+ - maptweak: Adds fire closets in the Spirit and the Perseverance.
NewOriginalSchwann:
- tweak: Fatigues have been added to the Fleet pilot's uniform vendor under utility.
SierraKomodo:
@@ -11327,8 +11327,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
meteors in shuttles at experienced/master levels.
- tweak: Gas thrusters for overmap travel, will now calculate thrust and fuel consumption
by volume. Lower volume limit from the engine control for more fuel efficiency.
- - tweak: Guppy's mass and max speed has been increased.
- - maptweak: Charon's atmospheric and electric compartment has be reworked to accommodate
+ - tweak: Opportunity's mass and max speed has been increased.
+ - maptweak: Spirit's atmospheric and electric compartment has be reworked to accommodate
for the fuel consumption.
- maptweak: There are now shuttle navpoints on the hanger deck.
2019-05-31:
@@ -11344,13 +11344,13 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Orelbon:
- rscadd: Adds NanoUI interface to suit storage units.
SierraKomodo:
- - rscdel: Vat-grown blanks have been removed from the SRV Petrov.
+ - rscdel: Vat-grown blanks have been removed from the SRV Curiosity.
babydoll:
- tweak: Many objects that were previously rotatable with a verb are now rotated
using alt-click. Any such object will report in examine that it can be rotated.
- tweak: You can now rotate vending machines with alt-click.
ghostsheet:
- - maptweak: The Aquila's engine room has been updated, most notably it now has a
+ - maptweak: The Perseverance's engine room has been updated, most notably it now has a
fuel pump for easy refuelling.
2019-06-02:
Atebite:
@@ -11614,7 +11614,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
MikoMyazaki:
- rscadd: Traitor robots always get their emag items.
- rscadd: Cultivator drone now has an emag item, an energy machete.
- - bugfix: Restores Petrov access to the Access Decrypter antagonist program.
+ - bugfix: Restores Curiosity access to the Access Decrypter antagonist program.
MistakeNot4892:
- tweak: The config options RUN_SPEED and WALK_SPEED are now more accurately named
RUN_DELAY and WALK_DELAY. Default values have been adjusted to match the previous
@@ -11684,7 +11684,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Shuttle engine heater, are now climbable.
- maptweak: Medical bathroom now has a mirror, for all your post radiation treatment
needs.
- - maptweak: Charon atmospheric compartment has been returned to its previous state.
+ - maptweak: Spirit atmospheric compartment has been returned to its previous state.
- maptweak: Hanger fuel bay now has a high power pump, to reduce prep time.
2019-06-26:
Cakey:
@@ -11927,7 +11927,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
now.
ghostsheet:
- maptweak: Hanger Atmospheric Storage room has been added to the hanger. This replaces
- the unused refinery slot near the fore of the charon.
+ the unused refinery slot near the fore of the spirit.
- bugfix: Restore button pressing sprites to their previous states.
- bugfix: Cell charger will now work in Z-level transition, and they now have proper
sprite charge bar.
@@ -12259,7 +12259,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Illegal Tech is renamed to Esoteric Tech. Producing items with this tech
& having esoteric tech levels is not illegal, however possession of those items
may be if they appear on the contraband list.
- - bugfix: Petrov RnD console will start the round able to access the Core RnD server
+ - bugfix: Curiosity RnD console will start the round able to access the Core RnD server
data and sync with the rest of the Torch.
- bugfix: Elevator will no longer get stuck when you give it multiple move orders
via the elevator panel or the buttons on each floor. It will wait for nine seconds
@@ -12466,7 +12466,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Gas thrusters has an increased energy usage on idle (6 Wh per tick so
every 2 second) and 10 Wh per burn. So please keep them off unless you need
them, for that same reason all thrusts starts offline.
- - tweak: Guppy's mass and max speed has both been increased.
+ - tweak: Opportunity's mass and max speed has both been increased.
zaredman:
- tweak: Wizard and Ninja now require a minimum of 5 players.
2019-09-13:
@@ -13048,8 +13048,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Rain7x:
- tweak: The CMO now has the same amount of total skill points as a regular physician.
ghostsheet:
- - rscadd: Added a navigation telescreen to the Charon crew compartment.
- - rscadd: Replaced the rack on the Guppy with a storage compartment crate
+ - rscadd: Added a navigation telescreen to the Spirit crew compartment.
+ - rscadd: Replaced the rack on the Opportunity with a storage compartment crate
- rscadd: Added binoculars to mining prep.
- rscadd: Carp migration event got reworked! They will now be launched into the
ship at slow speed, over a period of time.
@@ -14064,3 +14064,9 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
MistakeNot4892:
- tweak: Utility frames, Kharmaani and adherent now bleed exciting new colours.
- tweak: Human subtypes can now share blood without triggering a rejection.
+2022-01-03:
+ tag if you want to specify another name or several people. -->:
+ - bugfix: fix looping APC power down sound
+2022-01-11:
+ Gaxeer:
+ - bugfix: fix the bug with grab-moving dead mob
diff --git a/html/changelogs/AutoChangeLog-pr-1924.yml b/html/changelogs/AutoChangeLog-pr-1924.yml
new file mode 100644
index 00000000000..e125fea22c0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1924.yml
@@ -0,0 +1,4 @@
+author: retlaw34
+delete-after: true
+changes:
+ - imageadd: Added new fuel port sprites.
diff --git a/html/changelogs/mdp-accessories.yml b/html/changelogs/mdp-accessories.yml
new file mode 100644
index 00000000000..e670779e20f
--- /dev/null
+++ b/html/changelogs/mdp-accessories.yml
@@ -0,0 +1,40 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+# admin
+#################################
+
+# Your name.
+author: MoondancerPony
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - wip: "Ports Hestia's marking system, with massive refactors."
+ - rscadd: "Adds an entirely new category in character setup: Cosmetics! Contains ear and tail options."
+ - rscdel: "Does not port Hestia's wings. For now."
+ - rscdel: "Removes certain ckey-restricted content originally from Virgo."
diff --git a/html/images/iseo.png b/html/images/iseo.png
new file mode 100644
index 00000000000..236d370e15c
Binary files /dev/null and b/html/images/iseo.png differ
diff --git a/icons/misc/security_state.dmi b/icons/misc/security_state.dmi
index aff829cdb6c..f933e553df3 100644
Binary files a/icons/misc/security_state.dmi and b/icons/misc/security_state.dmi differ
diff --git a/icons/mob/human_races/species/human/hair.dmi b/icons/mob/human_races/species/human/hair.dmi
index 459e4531714..fae7d11712d 100644
Binary files a/icons/mob/human_races/species/human/hair.dmi and b/icons/mob/human_races/species/human/hair.dmi differ
diff --git a/icons/mob/screen1_health.dmi b/icons/mob/screen1_health.dmi
index 9cd7a413420..2e3a4f6d948 100644
Binary files a/icons/mob/screen1_health.dmi and b/icons/mob/screen1_health.dmi differ
diff --git a/icons/obj/cooking_machines.dmi b/icons/obj/cooking_machines.dmi
index 666a31b9d09..a3beba8cb34 100644
Binary files a/icons/obj/cooking_machines.dmi and b/icons/obj/cooking_machines.dmi differ
diff --git a/icons/obj/doors/material_doors.dmi b/icons/obj/doors/material_doors.dmi
index 5f90312aac8..0ccd106e2d0 100644
Binary files a/icons/obj/doors/material_doors.dmi and b/icons/obj/doors/material_doors.dmi differ
diff --git a/icons/obj/ftl_drive_96x96.dmi b/icons/obj/ftl_drive_96x96.dmi
new file mode 100644
index 00000000000..b9d75232fc9
Binary files /dev/null and b/icons/obj/ftl_drive_96x96.dmi differ
diff --git a/icons/obj/ftlshunt_fuelport.dmi b/icons/obj/ftlshunt_fuelport.dmi
new file mode 100644
index 00000000000..61ce716bfa5
Binary files /dev/null and b/icons/obj/ftlshunt_fuelport.dmi differ
diff --git a/icons/obj/items/chem/beakers/measuringcup.dmi b/icons/obj/items/chem/beakers/measuringcup.dmi
new file mode 100644
index 00000000000..fd803193113
Binary files /dev/null and b/icons/obj/items/chem/beakers/measuringcup.dmi differ
diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi
index 44e43e52b0c..bdbb663b507 100644
Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ
diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi
index d6ea9f5b004..2ae9e5a3381 100644
Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ
diff --git a/icons/obj/stairs.dmi b/icons/obj/stairs.dmi
index b0c14147e5f..b4892cbdc0f 100644
Binary files a/icons/obj/stairs.dmi and b/icons/obj/stairs.dmi differ
diff --git a/icons/skybox/ftlbox.dmi b/icons/skybox/ftlbox.dmi
new file mode 100644
index 00000000000..8a0e869a14f
Binary files /dev/null and b/icons/skybox/ftlbox.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index e1a1b114cae..50e68f4ec05 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -129,6 +129,7 @@ window "mainwindow"
anchor1 = none
anchor2 = none
is-default = true
+ background-color = #000000
saved-params = "pos;size;is-minimized;is-maximized"
on-size = "OnResize"
is-maximized = true
diff --git a/maps/antag_spawn/ert/ert_base.dmm b/maps/antag_spawn/ert/ert_base.dmm
index 8e145da026c..b75508d2d58 100644
--- a/maps/antag_spawn/ert/ert_base.dmm
+++ b/maps/antag_spawn/ert/ert_base.dmm
@@ -2225,10 +2225,10 @@
/obj/item/taperoll/atmos,
/obj/item/multitool,
/obj/item/multitool,
-/obj/item/tape_roll,
-/obj/item/tape_roll,
-/obj/item/tape_roll,
-/obj/item/tape_roll,
+/obj/item/ducttape,
+/obj/item/ducttape,
+/obj/item/ducttape,
+/obj/item/ducttape,
/obj/item/cell/high,
/obj/item/cell/high,
/obj/item/cell/high,
diff --git a/maps/antag_spawn/heist/heist_base.dmm b/maps/antag_spawn/heist/heist_base.dmm
index b2392256f3c..a47fa1b19e7 100644
--- a/maps/antag_spawn/heist/heist_base.dmm
+++ b/maps/antag_spawn/heist/heist_base.dmm
@@ -8,9 +8,6 @@
"ac" = (
/turf/unsimulated/mineral,
/area/space)
-"ad" = (
-/turf/unsimulated/wall,
-/area/space)
"ae" = (
/turf/unsimulated/wall,
/area/map_template/syndicate_mothership/raider_base)
@@ -86,11 +83,6 @@
icon_state = "white"
},
/area/map_template/syndicate_mothership/raider_base)
-"aq" = (
-/turf/unsimulated/floor{
- icon_state = "asteroid"
- },
-/area/map_template/syndicate_mothership/raider_base)
"ar" = (
/obj/machinery/door/airlock/hatch{
name = "\improper NO DUST BREATHER ALLOWED"
@@ -2504,11 +2496,11 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-ab
+aC
+aC
+aC
+aC
+aC
ab
ab
ab
@@ -2575,15 +2567,15 @@ ab
ab
ab
ab
-ab
-ab
+aC
+aC
bj
by
bT
-ab
-ab
-ab
-ab
+aC
+aC
+aC
+aC
ab
ab
ab
@@ -2647,16 +2639,16 @@ ab
ab
ab
ab
-ab
+aC
aQ
-aq
bz
-aq
-aq
+bz
+bz
+bz
ce
bk
-ab
-ab
+aC
+aC
ab
ab
ab
@@ -2716,19 +2708,19 @@ ab
ab
ab
ab
-ab
-ab
-ab
-ab
-aq
-aq
+aC
+aC
+aC
+aC
+bz
+bz
bU
bU
bU
-aq
-aq
-aq
-ab
+bz
+bz
+bz
+aC
ab
ab
ab
@@ -2786,21 +2778,21 @@ aa
aa
ab
ab
-ab
-ab
-ab
+aC
+aC
+aC
aA
-aq
+bz
aQ
-aq
+bz
bk
-aq
-aq
-aq
-aq
+bz
+bz
+bz
+bz
aQ
cp
-ab
+aC
ab
ab
ab
@@ -2858,21 +2850,21 @@ aa
ab
ab
ab
-ab
+aC
an
-aq
-aq
-aq
-aq
-aq
-aq
+bz
+bz
+bz
+bz
+bz
+bz
bU
bU
bU
-aq
-aq
+bz
+bz
cq
-ab
+aC
ab
ab
ab
@@ -2930,21 +2922,21 @@ ac
ab
ab
ab
-ab
-aq
-aq
+aC
+bz
+bz
aB
aC
aR
-aq
-aq
-aq
-aq
-aq
+bz
+bz
+bz
+bz
+bz
cf
cj
cr
-ab
+aC
ab
ab
ab
@@ -3002,21 +2994,21 @@ ac
ab
ab
ab
-ab
-aq
-aq
aC
+bz
+bz
aC
-aq
-aq
-ab
-aq
+aC
+bz
+bz
+aC
+bz
aQ
-aq
-aq
-ab
-ab
-ab
+bz
+bz
+aC
+aC
+aC
ab
ab
ab
@@ -3074,19 +3066,19 @@ ac
ab
ab
ab
-ab
+aC
aj
-aq
+bz
+aC
+aC
+bz
+aC
+aC
+aC
+aC
+aC
aC
aC
-aq
-ab
-ab
-ab
-ab
-ab
-ab
-ab
ab
aa
ab
@@ -3146,13 +3138,13 @@ ab
ab
ab
ab
-ab
+aC
aj
aw
aC
aC
-aq
-ab
+bz
+aC
ab
ab
ab
@@ -3218,7 +3210,7 @@ ab
ab
ab
ab
-ab
+aC
af
aj
ae
@@ -3290,7 +3282,7 @@ ab
ab
ab
ab
-ad
+ae
an
an
ae
@@ -3362,7 +3354,7 @@ ab
ab
ab
ab
-ad
+ae
ar
ar
ae
@@ -3434,7 +3426,7 @@ ab
ab
ab
ab
-ad
+ae
aj
an
ae
@@ -3506,7 +3498,7 @@ ab
ab
ab
ab
-ad
+ae
an
aj
ae
@@ -3578,7 +3570,7 @@ ab
ab
ab
ab
-ad
+ae
af
an
an
@@ -3650,7 +3642,7 @@ ab
ab
ab
ab
-ad
+ae
an
an
an
@@ -3722,7 +3714,7 @@ ab
ab
ab
ab
-ad
+ae
an
an
ae
@@ -3794,7 +3786,7 @@ ab
ab
ab
ab
-ad
+ae
an
an
ae
@@ -3866,7 +3858,7 @@ ab
ab
ab
ab
-ad
+ae
an
an
ae
@@ -3935,10 +3927,10 @@ aa
ab
ab
ab
-ad
-ad
-ad
-ad
+ae
+ae
+ae
+ae
aj
an
aD
@@ -4007,7 +3999,7 @@ aa
ab
ab
ab
-ab
+aC
af
aj
an
@@ -4079,9 +4071,9 @@ aa
aa
ab
ab
-ab
-ab
-ab
+aC
+aC
+aC
aj
an
an
diff --git a/maps/antag_spawn/mercenary/mercenary_base.dmm b/maps/antag_spawn/mercenary/mercenary_base.dmm
index dbc75d35f9e..97fbc7c8713 100644
--- a/maps/antag_spawn/mercenary/mercenary_base.dmm
+++ b/maps/antag_spawn/mercenary/mercenary_base.dmm
@@ -1613,9 +1613,6 @@
dir = 4
},
/obj/effect/floor_decal/industrial/outline/yellow,
-/obj/abstract/landmark{
- name = "Nuclear-Bomb"
- },
/obj/structure/railing/mapped{
dir = 8
},
diff --git a/maps/away/bearcat/bearcat-1.dmm b/maps/away/bearcat/bearcat-1.dmm
index 753b25390c2..1b32339b73e 100644
--- a/maps/away/bearcat/bearcat-1.dmm
+++ b/maps/away/bearcat/bearcat-1.dmm
@@ -1938,7 +1938,7 @@
pixel_y = 32;
req_access = newlist()
},
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/machinery/light_switch{
pixel_x = -24
},
@@ -2406,7 +2406,7 @@
/turf/simulated/floor/tiled/usedup,
/area/ship/scrap/maintenance/storage)
"eS" = (
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/item/stack/material/reinforced/mapped/plasteel/fifty,
/obj/item/stack/material/ingot/mapped/copper/fifty,
/obj/item/stack/material/rods/fifty,
@@ -2423,7 +2423,7 @@
"eT" = (
/obj/item/clothing/head/welding,
/obj/item/radio,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/structure/table,
/obj/item/radio/intercom{
pixel_y = -32
diff --git a/maps/away/bearcat/bearcat-2.dmm b/maps/away/bearcat/bearcat-2.dmm
index 36494e1aa25..6b5e412df31 100644
--- a/maps/away/bearcat/bearcat-2.dmm
+++ b/maps/away/bearcat/bearcat-2.dmm
@@ -2515,7 +2515,7 @@
/obj/structure/closet/medical_wall/filled{
pixel_y = -32
},
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/item/retractor,
/obj/item/scalpel,
/turf/simulated/floor/tiled/white,
diff --git a/maps/away/casino/casino.dmm b/maps/away/casino/casino.dmm
index a43d00dc999..3942f80b7a4 100644
--- a/maps/away/casino/casino.dmm
+++ b/maps/away/casino/casino.dmm
@@ -2551,26 +2551,26 @@
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"hq" = (
-/obj/machinery/cooker/cereal,
+/obj/machinery/appliance/mixer/cereal,
/obj/machinery/light{
dir = 1
},
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"hr" = (
-/obj/machinery/cooker/candy,
+/obj/machinery/appliance/mixer/candy,
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"hs" = (
-/obj/machinery/cooker/fryer,
+/obj/machinery/appliance/cooker/fryer,
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"ht" = (
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"hu" = (
-/obj/machinery/cooker/grill,
+/obj/machinery/appliance/cooker/stove,
/turf/simulated/floor/tiled,
/area/casino/casino_kitchen)
"hv" = (
diff --git a/maps/away/errant_pisces/errant_pisces.dm b/maps/away/errant_pisces/errant_pisces.dm
index f8a1c0ebde1..ac9a4f49733 100644
--- a/maps/away/errant_pisces/errant_pisces.dm
+++ b/maps/away/errant_pisces/errant_pisces.dm
@@ -34,10 +34,6 @@
/mob/living/simple_animal/hostile/carp/shark/carp_randomify()
return
-/mob/living/simple_animal/hostile/carp/shark/on_update_icon()
- SHOULD_CALL_PARENT(FALSE)
- return
-
/mob/living/simple_animal/hostile/carp/shark/death()
..()
var/datum/gas_mixture/environment = loc.return_air()
diff --git a/maps/away/errant_pisces/errant_pisces.dmm b/maps/away/errant_pisces/errant_pisces.dmm
index a316c6ea4f5..3046e1e3fc0 100644
--- a/maps/away/errant_pisces/errant_pisces.dmm
+++ b/maps/away/errant_pisces/errant_pisces.dmm
@@ -3640,7 +3640,7 @@
/turf/simulated/floor/tiled,
/area/errant_pisces/dorms)
"jN" = (
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/turf/simulated/floor/tiled,
/area/errant_pisces/dorms)
"jO" = (
@@ -4196,7 +4196,7 @@
/area/errant_pisces/science_wing)
"lx" = (
/obj/structure/table,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled,
/area/errant_pisces/science_wing)
"ly" = (
diff --git a/maps/away/liberia/liberia.dm b/maps/away/liberia/liberia.dm
index eaf73e70633..2c1d64ae4ff 100644
--- a/maps/away/liberia/liberia.dm
+++ b/maps/away/liberia/liberia.dm
@@ -34,6 +34,27 @@
name = "Liberia"
archetype = /decl/submap_archetype/liberia
+/datum/trade_hub/overmap/liberia
+ name = "Long-Range Requisition Network"
+ max_traders = 12
+
+/datum/trade_hub/overmap/liberia/get_initial_trader_count()
+ return 6
+
+/datum/trade_hub/overmap/liberia/get_initial_traders()
+ return list(
+ /datum/trader/medical,
+ /datum/trader/mining,
+ /datum/trader/books
+ )
+
+/obj/effect/overmap/trade_hub/liberia/get_trading_post_type()
+ return /datum/trade_hub/overmap/liberia
+
+/obj/effect/overmap/visitable/ship/liberia/move_to_starting_location()
+ . = ..()
+ new /obj/effect/overmap/trade_hub/liberia/(loc)
+
/obj/machinery/power/smes/buildable/preset/liberia
_input_maxed = TRUE
_output_maxed = TRUE
diff --git a/maps/away/liberia/liberia.dmm b/maps/away/liberia/liberia.dmm
index cf36ba7547c..6c9c1c167d2 100644
--- a/maps/away/liberia/liberia.dmm
+++ b/maps/away/liberia/liberia.dmm
@@ -2696,7 +2696,7 @@
/obj/effect/floor_decal/corner/blue/three_quarters{
dir = 8
},
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 4
},
/turf/simulated/floor/tiled/white/monotile,
@@ -2705,7 +2705,7 @@
/obj/effect/floor_decal/corner/blue/three_quarters{
dir = 1
},
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 4
},
/turf/simulated/floor/tiled/white/monotile,
diff --git a/maps/away/liberia/liberia_jobs.dm b/maps/away/liberia/liberia_jobs.dm
index 9ad667ece75..f2ec9e9c2dc 100644
--- a/maps/away/liberia/liberia_jobs.dm
+++ b/maps/away/liberia/liberia_jobs.dm
@@ -9,7 +9,7 @@
/datum/job/submap/merchant
title = "Merchant"
total_positions = 4
- info = "You are free traders who have drifted into unknown distances in search of profit. Travel, trade, make profit!"
+ info = "You are free traders who have voyaged into the vast unknown in search of profit. Travel, trade, make profit!"
supervisors = "the invisible hand of the market"
selection_color = "#515151"
@@ -26,7 +26,7 @@
)
/datum/job/submap/merchant/equip(var/mob/living/carbon/human/H)
- to_chat(H, "Your connections helped you learn about the words that will help you identify a locals... Particularly interested buyers:")
+ to_chat(H, "Your connections taught you some code phrases that will help you identify buyers with... particular interests:")
to_chat(H, "Code phases: [syndicate_code_phrase]")
to_chat(H, "Responses to phrases: [syndicate_code_response]")
H.StoreMemory("Code phase: [syndicate_code_phrase]", /decl/memory_options/system)
@@ -51,7 +51,7 @@
/obj/item/card/id/merchant
name = "identification card"
- desc = "A card issued to Merchants, indicating their right to sell and buy goods."
+ desc = "A card issued to merchants, indicating their right to sell and buy goods."
access = list(access_merchant)
color = COLOR_OFF_WHITE
detail_color = COLOR_BEIGE
diff --git a/maps/away/lost_supply_base/lost_supply_base.dmm b/maps/away/lost_supply_base/lost_supply_base.dmm
index 074e0d9cd69..a647b19364e 100644
--- a/maps/away/lost_supply_base/lost_supply_base.dmm
+++ b/maps/away/lost_supply_base/lost_supply_base.dmm
@@ -904,7 +904,7 @@
/area/lost_supply_base/common)
"cz" = (
/obj/structure/closet/secure_closet/freezer/meat,
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/turf/simulated/floor/tiled/airless,
/area/lost_supply_base/common)
"cA" = (
diff --git a/maps/away/slavers/slavers_base.dm b/maps/away/slavers/slavers_base.dm
index 08b5b0541cb..18a64688cbb 100644
--- a/maps/away/slavers/slavers_base.dm
+++ b/maps/away/slavers/slavers_base.dm
@@ -171,8 +171,8 @@
icon = 'maps/away/slavers/icons/uniform.dmi'
body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS
armor = list(
- melee = ARMOR_MELEE_KNIVES,
- bullet = ARMOR_BALLISTIC_PISTOL,
- laser = ARMOR_LASER_MINOR,
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_PISTOL,
+ laser = ARMOR_LASER_MINOR,
energy = ARMOR_ENERGY_MINOR
)
diff --git a/maps/away/slavers/slavers_base.dmm b/maps/away/slavers/slavers_base.dmm
index 84831312c2a..24cf488dcbe 100644
--- a/maps/away/slavers/slavers_base.dmm
+++ b/maps/away/slavers/slavers_base.dmm
@@ -2902,7 +2902,7 @@
/turf/simulated/floor/tiled,
/area/slavers_base/dorms)
"hW" = (
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 10
},
diff --git a/maps/exodus/exodus-2.dmm b/maps/exodus/exodus-2.dmm
index ecc10372127..dac9270ce15 100644
--- a/maps/exodus/exodus-2.dmm
+++ b/maps/exodus/exodus-2.dmm
@@ -5899,7 +5899,7 @@
},
/obj/item/clipboard,
/obj/item/hand_labeler,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled/dark,
/area/exodus/lawoffice)
"amt" = (
@@ -8644,7 +8644,7 @@
/obj/structure/table/reinforced,
/obj/item/clipboard,
/obj/item/hand_labeler,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled/dark,
/area/exodus/lawoffice)
"arR" = (
@@ -14517,7 +14517,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/wood/walnut,
/area/exodus/library)
"aEG" = (
@@ -21719,7 +21719,7 @@
/obj/effect/floor_decal/corner/brown/diagonal{
dir = 8
},
-/obj/machinery/cooker/fryer,
+/obj/machinery/appliance/cooker/fryer,
/turf/simulated/floor/tiled/white,
/area/exodus/crew_quarters/kitchen)
"aTC" = (
@@ -21727,7 +21727,7 @@
dir = 8
},
/obj/structure/disposalpipe/segment,
-/obj/machinery/cooker/grill,
+/obj/machinery/appliance/cooker/stove,
/turf/simulated/floor/tiled/white,
/area/exodus/crew_quarters/kitchen)
"aTD" = (
@@ -23452,7 +23452,7 @@
/obj/effect/floor_decal/corner/brown/diagonal{
dir = 8
},
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/turf/simulated/floor/tiled/white,
/area/exodus/crew_quarters/kitchen)
"aXI" = (
@@ -23878,7 +23878,7 @@
},
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/structure/table,
/turf/simulated/floor/tiled/steel_grid,
/area/exodus/crew_quarters/locker)
@@ -24269,7 +24269,7 @@
pixel_x = 24
},
/obj/structure/table/marble,
-/obj/machinery/cooker/cereal,
+/obj/machinery/appliance/mixer/cereal,
/turf/simulated/floor/tiled/white,
/area/exodus/crew_quarters/kitchen)
"aZp" = (
@@ -31905,7 +31905,7 @@
pixel_x = -27;
pixel_y = 1
},
-/obj/item/tape_roll,
+/obj/item/ducttape,
/obj/structure/table{
name = "plastic table frame"
},
@@ -41688,7 +41688,7 @@
pixel_x = -22
},
/obj/effect/floor_decal/industrial/outline/yellow,
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 4
},
/turf/simulated/floor/tiled/steel_grid,
@@ -44803,7 +44803,7 @@
pixel_x = 24
},
/obj/effect/floor_decal/industrial/outline/yellow,
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 4
},
/turf/simulated/floor/tiled/steel_grid,
@@ -52211,7 +52211,7 @@
/obj/effect/floor_decal/corner/brown/diagonal{
dir = 8
},
-/obj/machinery/cooker/candy,
+/obj/machinery/appliance/mixer/candy,
/turf/simulated/floor/tiled/white,
/area/exodus/crew_quarters/kitchen)
"cdL" = (
@@ -54949,7 +54949,7 @@
},
/obj/item/paper_bin,
/obj/item/pen,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled/white,
/area/exodus/research/xenobiology/xenoflora)
"cjD" = (
@@ -55628,7 +55628,7 @@
"clf" = (
/obj/structure/table/reinforced,
/obj/item/clipboard,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled/steel_grid,
/area/exodus/engineering/foyer)
"clg" = (
@@ -59192,7 +59192,7 @@
},
/obj/item/paper_bin,
/obj/item/pen,
-/obj/item/tape_roll,
+/obj/item/ducttape,
/turf/simulated/floor/tiled/white,
/area/exodus/research/xenobiology)
"ctX" = (
diff --git a/maps/exodus/exodus-admin.dmm b/maps/exodus/exodus-admin.dmm
index 69426726041..8f63692bad8 100644
--- a/maps/exodus/exodus-admin.dmm
+++ b/maps/exodus/exodus-admin.dmm
@@ -814,7 +814,7 @@
},
/area/centcom)
"aHp" = (
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 8
},
/turf/unsimulated/floor{
@@ -1355,7 +1355,7 @@
/turf/simulated/wall/titanium,
/area/shuttle/escape_shuttle)
"aLD" = (
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 8
},
/obj/effect/floor_decal/corner/blue/border{
@@ -2451,7 +2451,7 @@
/turf/simulated/floor/tiled/white/monotile,
/area/shuttle/escape_shuttle)
"fsI" = (
-/obj/machinery/sleeper{
+/obj/machinery/sleeper/standard{
dir = 4
},
/obj/effect/floor_decal/corner/blue/border{
diff --git a/maps/exodus/jobs/synthetics.dm b/maps/exodus/jobs/synthetics.dm
index ee372489af1..2294b2792f8 100644
--- a/maps/exodus/jobs/synthetics.dm
+++ b/maps/exodus/jobs/synthetics.dm
@@ -14,7 +14,7 @@
hud_icon = "hudblank"
skill_points = 0
no_skill_buffs = TRUE
- guestbanned = 1
+ guestbanned = 1
not_random_selectable = 1
skip_loadout_preview = TRUE
department_types = list(/decl/department/miscellaneous)
@@ -62,7 +62,7 @@
hud_icon = "hudblank"
skill_points = 0
no_skill_buffs = TRUE
- guestbanned = 1
+ guestbanned = 1
not_random_selectable = 1
skip_loadout_preview = TRUE
department_types = list(/decl/department/miscellaneous)
diff --git a/maps/ministation/ministation.dmm b/maps/ministation/ministation.dmm
index 124e43dc456..ca0af295ae0 100644
--- a/maps/ministation/ministation.dmm
+++ b/maps/ministation/ministation.dmm
@@ -9566,11 +9566,11 @@
/turf/simulated/floor/wood,
/area/ministation/cafe)
"zI" = (
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/turf/simulated/floor/wood,
/area/ministation/cafe)
"zJ" = (
-/obj/machinery/cooker/grill,
+/obj/machinery/appliance/cooker/stove,
/turf/simulated/floor/wood,
/area/ministation/cafe)
"zK" = (
@@ -9844,7 +9844,7 @@
/turf/simulated/floor/wood,
/area/ministation/cafe)
"Av" = (
-/obj/machinery/cooker/fryer,
+/obj/machinery/appliance/cooker/fryer,
/turf/simulated/floor/wood,
/area/ministation/cafe)
"Aw" = (
@@ -9867,11 +9867,11 @@
/turf/simulated/floor/wood,
/area/ministation/cafe)
"Az" = (
-/obj/machinery/cooker/cereal,
+/obj/machinery/appliance/mixer/cereal,
/turf/simulated/floor/wood,
/area/ministation/cafe)
"AA" = (
-/obj/machinery/cooker/candy,
+/obj/machinery/appliance/mixer/candy,
/turf/simulated/floor/wood,
/area/ministation/cafe)
"AB" = (
diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm
index 180c1dd49a3..3d09b580de2 100644
--- a/maps/modpack_testing/modpack_testing.dm
+++ b/maps/modpack_testing/modpack_testing.dm
@@ -5,15 +5,24 @@
#include "../../mods/content/mundane.dm"
#include "../../mods/content/scaling_descriptors.dm"
+
+ #include "../../mods/content/baychems/_baychems.dme"
#include "../../mods/content/bigpharma/_bigpharma.dme"
#include "../../mods/content/byond_membership/_byond_membership.dm"
#include "../../mods/content/corporate/_corporate.dme"
+ #include "../../mods/content/genemodding/_genemodding.dme"
#include "../../mods/content/generic_shuttles/_generic_shuttles.dme"
#include "../../mods/content/government/_government.dme"
+ #include "../../mods/content/hearth_content/_hearth_content.dme"
+ #include "../../mods/content/hearth_culture/_hearth_culture.dme"
+ #include "../../mods/content/hearthfoods/_hearthfoods.dme"
+ #include "../../mods/content/hearthdrinks/_hearthdrinks.dme"
#include "../../mods/content/matchmaking/_matchmaking.dme"
#include "../../mods/content/modern_earth/_modern_earth.dme"
#include "../../mods/content/mouse_highlights/_mouse_highlight.dme"
+ #include "../../mods/content/neural_laces/_laces.dme"
#include "../../mods/content/psionics/_psionics.dme"
+ #include "../../mods/content/shards/_shards.dme"
#include "../../mods/content/xenobiology/_xenobiology.dme"
#include "../../mods/mobs/dionaea/_dionaea.dme"
@@ -23,11 +32,18 @@
#include "../../mods/species/ascent/_ascent.dme"
#include "../../mods/species/lizard/_lizard.dme"
#include "../../mods/species/neoavians/_neoavians.dme"
+ #include "../../mods/species/skrell/_skrell.dme"
#include "../../mods/species/tajaran/_tajaran.dme"
#include "../../mods/species/tritonian/_tritonian.dme"
#include "../../mods/species/utility_frames/_utility_frames.dme"
#include "../../mods/species/vox/_vox.dme"
+ #include "../../mods/utility/centcomdb/_centcomdb.dme"
+ #include "../../mods/utility/ooc_notes/_ooc_notes.dme"
+ #include "../../mods/utility/tgsv4_integration/___tgs.dme"
+
+ #include "../../mods/verbs/antighost/_subtle_antighost.dme"
+
#define USING_MAP_DATUM /datum/map/modpack_testing
#elif !defined(MAP_OVERRIDE)
diff --git a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm
index b46f2f70fbc..0d4bb6d39ce 100644
--- a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm
+++ b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm
@@ -73,7 +73,7 @@
/turf/simulated/floor/tiled/monotile,
/area/template_noop)
"n" = (
-/obj/machinery/cooker/oven,
+/obj/machinery/appliance/cooker/oven,
/obj/effect/floor_decal/spline/fancy/wood{
dir = 4
},
diff --git a/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm b/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm
index 45568b92731..acc73879858 100644
--- a/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm
+++ b/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm
@@ -2362,8 +2362,8 @@
"fd" = (
/obj/structure/table/steel_reinforced,
/obj/item/storage/toolbox/syndicate,
-/obj/item/tape_roll,
-/obj/item/tape_roll,
+/obj/item/ducttape,
+/obj/item/ducttape,
/obj/item/crowbar/brace_jack,
/obj/item/clothing/head/hardhat/white,
/obj/item/grenade/chem_grenade/metalfoam,
@@ -3017,7 +3017,7 @@
/obj/item/storage/box/cola/drgibb,
/obj/item/chems/drinks/shaker,
/obj/item/chems/drinks/pitcher,
-/obj/item/chems/glass/beaker/bowl,
+/obj/item/chems/cooking_container/plate/bowl,
/obj/item/chems/condiment/salt,
/obj/item/chems/condiment/enzyme,
/turf/simulated/floor/tiled/freezer,
diff --git a/maps/torch/datums/department_exploration.dm b/maps/torch/datums/department_exploration.dm
new file mode 100644
index 00000000000..d62e2e48d46
--- /dev/null
+++ b/maps/torch/datums/department_exploration.dm
@@ -0,0 +1,65 @@
+/decl/department/exploration
+ goals = list(
+ /datum/goal/department/planet_claim,
+ /datum/goal/department/plant_samples,
+ /datum/goal/department/fauna_samples
+ )
+ max_goals = 3
+
+/datum/goal/department/planet_claim
+ description = "Plant the SCG banner on the surface of an exoplanet."
+
+/datum/goal/department/planet_claim/check_success()
+ return (SSstatistics.get_field(STAT_FLAGS_PLANTED) > 0)
+
+/datum/goal/department/plant_samples
+ var/seeds
+
+/*
+/datum/goal/department/plant_samples/New()
+ var/total_seeds = 0
+ var/area/map = locate(/area/overmap)
+ for(var/obj/effect/overmap/visitable/sector/exoplanet/P in map)
+ total_seeds += P.seeds.len
+ if(total_seeds)
+ seeds = max(1, round(0.5 * total_seeds))
+ ..()
+*/
+
+/datum/goal/department/plant_samples/is_valid()
+ return seeds > 0
+
+/datum/goal/department/plant_samples/update_strings()
+ description = "Scan at least [seeds] different plant\s native to exoplanets."
+
+/datum/goal/department/plant_samples/get_summary_value()
+ var/scanned = SSstatistics.get_field(STAT_XENOPLANTS_SCANNED)
+ return " ([scanned ? scanned : 0 ] plant specie\s so far)"
+
+/datum/goal/department/plant_samples/check_success()
+ return (SSstatistics.get_field(STAT_XENOPLANTS_SCANNED) >= seeds)
+
+/datum/goal/department/fauna_samples
+ var/species
+
+/datum/goal/department/fauna_samples/New()
+ var/list/total_species = list()
+ var/area/map = locate(/area/overmap)
+ for(var/obj/effect/overmap/visitable/sector/exoplanet/P in map)
+ for(var/mob/living/simple_animal/A in P.animals)
+ total_species |= A.type
+ species = rand(length(total_species))
+ ..()
+
+/datum/goal/department/fauna_samples/is_valid()
+ return species > 0
+
+/datum/goal/department/fauna_samples/update_strings()
+ description = "Scan at least [species] different creature\s native to exoplanets."
+
+/datum/goal/department/fauna_samples/get_summary_value()
+ var/scanned = length(SSstatistics.get_field(STAT_XENOFAUNA_SCANNED))
+ return " ([scanned ? scanned : 0 ] xenofauna specie\s so far)"
+
+/datum/goal/department/fauna_samples/check_success()
+ return (length(SSstatistics.get_field(STAT_XENOFAUNA_SCANNED)) >= species)
\ No newline at end of file
diff --git a/maps/torch/datums/game_modes/torch_meteor.dm b/maps/torch/datums/game_modes/torch_meteor.dm
new file mode 100644
index 00000000000..d5fe739facc
--- /dev/null
+++ b/maps/torch/datums/game_modes/torch_meteor.dm
@@ -0,0 +1,63 @@
+//Torch override for it, auto-calls long-delayed jump automatically so round duration is hard capped.
+/datum/game_mode/meteor
+ name = "Meteor"
+ round_description = "Suddenly the rocks, thousands of them!"
+ extended_round_description = "We are on an unavoidable collision course with an asteroid field. You have only a moment to prepare before you are barraged by dust and meteors. Emergency BS drive spoolup has been initiated, but you need to survive until it's done."
+ shuttle_delay = 5 //40ish minutes round
+ meteor_grace_period = 10 MINUTES
+ meteor_severity = 10 //Since Torch is pretty sturdy and time is of essence, jumpstart things a bit
+ escalation_probability = 70
+
+/datum/game_mode/meteor/post_setup()
+ ..()
+ alert_title = "[global.using_map.full_name] Short Range Sensors"
+ alert_text = "[global.using_map.full_name] is on a collision course with an ultradense asteroid field. Estimated time until impact is: [meteor_grace_period / 1200] MINUTES. Emegency random jump procedure initiated."
+ start_text = "Asteroid field imminent. All hands brace for multiple impacts. May %DEITY_NAME% be with you."
+
+ global.using_map.shuttle_called_message = "Attention all hands: Emergency Superluminal Drive spool up initiated. It will be ready for jump in %ETA%."
+ global.using_map.shuttle_docked_message = "Attention all hands: Superluminal Drive spooled up. Emergency bluespace jump in %ETD%."
+ global.using_map.shuttle_leaving_dock = "Attention all hands: Emergency superluminal jump initiated, emerging in %ETA%."
+
+/datum/game_mode/meteor/on_meteor_warn()
+ ..()
+ var/datum/evacuation_option/meteor_bluespace_jump/auto_evac = new()
+ auto_evac.execute()
+
+/datum/game_mode/meteor/declare_completion()
+ var/eng_status = 0
+ for(var/obj/machinery/atmospherics/unary/engine/E in SSmachines.machinery)
+ if((get_z(E) in global.using_map.station_levels) && !(E.stat & BROKEN))
+ eng_status++
+ var/nav_status = FALSE
+ for(var/obj/machinery/computer/ship/helm/H in SSmachines.machinery)
+ if((get_z(H) in global.using_map.station_levels) && !(H.stat & BROKEN))
+ nav_status = TRUE
+ var/bsd_status = FALSE
+ for(var/obj/machinery/ftl_shunt/core/C in SSmachines.machinery)
+ if((get_z(C) in global.using_map.station_levels) && !(C.stat & (BROKEN|NOPOWER)))
+ nav_status = TRUE
+
+ to_world("
Damage report
")
+ if(eng_status)
+ to_world("At least [eng_status] thrusters remained operational.")
+ else
+ to_world("All propulsion was lost, leaving \the [global.using_map.full_name] drifting.")
+ if(nav_status)
+ to_world("Navigation and helm remained operational.")
+ else
+ to_world("The navigation systems were lost on [global.using_map.full_name].")
+ if(bsd_status)
+ to_world("The Superluminal drive stayed powered.")
+ else
+ to_world("The Superluminal drive lost power during the jump, causing dangerous anomalies in the local time-space.")
+
+
+//Bluespace jump but ignoring cooldowns and done at roundstart basically
+/datum/evacuation_option/meteor_bluespace_jump
+ option_text = "Initiate emergency bluespace jump"
+ option_desc = "initiate automated emergency bluespace jump"
+
+/datum/evacuation_option/meteor_bluespace_jump/execute(mob/user)
+ if(!SSevac.evacuation_controller)
+ return
+ SSevac.evacuation_controller.call_evacuation(user, 0, forced = TRUE)
diff --git a/maps/torch/datums/game_modes/torch_revolution.dm b/maps/torch/datums/game_modes/torch_revolution.dm
new file mode 100644
index 00000000000..2277288c1f8
--- /dev/null
+++ b/maps/torch/datums/game_modes/torch_revolution.dm
@@ -0,0 +1,45 @@
+/datum/game_mode/revolution
+ name = "Mutiny"
+ round_description = "Morale is shattered, and a mutiny is brewing! Use the 'Check Round Info' verb for more information!"
+ extended_round_description = "Time in space, away from home and loved ones, takes its toll on even the most grizzled space travelers. As time goes on, some crew find themselves \
+ stretched to their breaking points; friendly faces become harsh and hostile, and the most sensible of minds become filled with bitterness and petty ideas. \
+ As their peers find themselves surrounded by ever-angrier forces, the situation on the Endeavour is rapidly reaching its brutal climax."
+ config_tag = "mutiny"
+ required_enemies = 4
+ required_players = 10
+
+/decl/special_role/revolutionary
+ name = "Head Mutineer"
+ name_plural = "Mutineers"
+
+ faction_welcome = "That's it; you're done taking this crap. Obey all instructions from the leaders of the mutiny, and ensure the mutiny succeeds."
+ welcome_text = "You've been out here for what feels like an eternity. The time spent in space has worn away at your conscience, and \
+ you won't let yourself be canned up like a sardine for even one more jump. Take control of your situation and use the Endeavour for your own ends, or \
+ even just to return home."
+
+ victory_text = "The Endeavour has fallen to the mutiny, and its future is now in question."
+ loss_text = "The attempted mutiny has failed, but the crew questions what happens now."
+
+ //Inround revs.
+ faction_name = "Mutineer"
+ faction_descriptor = "Mutiny"
+
+ faction = "mutiny"
+
+
+/decl/special_role/loyalists
+ name = "Loyalist"
+ name_plural = "Loyalists"
+ faction_name = "Loyalist"
+ victory_text = "The Endeavour is free of the mutineers, although the cost has yet to be discovered in full."
+ loss_text = "The mutineers have won; the Endeavour will never be the same."
+
+
+/decl/special_role/loyalists/Initialize()
+ . = ..()
+ welcome_text = "The ISEO Endeavour has been on this mission for some time, and there is still much to accomplish. \
+ However, whispers abound about malcontents, saboteurs and mutineers - the very ship faces threats from within!\
+ To protect your way of life, those who would change it must be pacified or eliminated, and those that remain \
+ must know not to intrude on your status."
+ faction_welcome = "Defend your own authority and that of your leaders; eliminate any threats."
+ faction_descriptor = "[global.using_map.company_name]"
diff --git a/maps/torch/datums/game_modes/torch_siege.dm b/maps/torch/datums/game_modes/torch_siege.dm
new file mode 100644
index 00000000000..25311e29284
--- /dev/null
+++ b/maps/torch/datums/game_modes/torch_siege.dm
@@ -0,0 +1,4 @@
+/datum/game_mode/siege
+ name = "Mercenary & Mutiny"
+ round_description = "Getting stuck between a rock and a hard place, maybe the nice visitors can help with your internal security problem?"
+ extended_round_description = "GENERAL QUARTERS! OH GOD WE GAVE THE MUTINEERS GUNS!"
\ No newline at end of file
diff --git a/maps/torch/datums/game_modes/torch_traitor.dm b/maps/torch/datums/game_modes/torch_traitor.dm
new file mode 100644
index 00000000000..55439a593d3
--- /dev/null
+++ b/maps/torch/datums/game_modes/torch_traitor.dm
@@ -0,0 +1,10 @@
+/datum/game_mode/traitor
+ extended_round_description = "The successes of the ISEO Endeavour's past missions have marked the ship as \
+ a highly valuable target for many organizations and individuals. The varied pasts \
+ and experiences of the crew have left them susceptible to the vices and temptations of humanity. \
+ Are you in the safe self-contained workplace you once thought it was, or has it become a playground \
+ for the evils of the galaxy? Who can you trust? Watch your front. Watch your sides. Watch your back. \
+ The familiar faces that you've passed hundreds of times down the hallways before can be hiding terrible \
+ secrets and deceptions. Every corner is a mystery. Every conversation is a lie. You will be facing your \
+ friends and family as they try to use your emotions and trust to their advantage, leaving you with nothing \
+ but the painful reminder that space is cruel and unforgiving."
\ No newline at end of file
diff --git a/maps/torch/datums/game_modes/torch_uprising.dm b/maps/torch/datums/game_modes/torch_uprising.dm
new file mode 100644
index 00000000000..0cc380180a1
--- /dev/null
+++ b/maps/torch/datums/game_modes/torch_uprising.dm
@@ -0,0 +1,4 @@
+/datum/game_mode/uprising
+ name = "Cult & Mutiny"
+ round_description = "Some crewmembers are attempting to start a mutiny while a cult plots in the shadows!"
+ extended_round_description = "Cultists and mutineers spawn in this round."
\ No newline at end of file
diff --git a/maps/torch/datums/license_decls.dm b/maps/torch/datums/license_decls.dm
new file mode 100644
index 00000000000..245a136277c
--- /dev/null
+++ b/maps/torch/datums/license_decls.dm
@@ -0,0 +1,3 @@
+/decl/license/cc_by_nc_4_0
+ name = "CC BY NC 4.0"
+ url = "https://creativecommons.org/licenses/by-nc/4.0/"
\ No newline at end of file
diff --git a/maps/torch/datums/music/heard_of_a_place.dm b/maps/torch/datums/music/heard_of_a_place.dm
new file mode 100644
index 00000000000..83ba5849822
--- /dev/null
+++ b/maps/torch/datums/music/heard_of_a_place.dm
@@ -0,0 +1,7 @@
+/decl/music_track/astrometrics/a_place
+ title = "I Have Heard of a Place"
+ album = "Life on Earth"
+ song = 'sound/music/hearth/place.ogg'
+ url = "https://freemusicarchive.org/music/Astrometrics/Life_On_Earth_1584"
+ license = /decl/license/cc_by_nc_4_0
+ artist = "Astrometrics"
\ No newline at end of file
diff --git a/maps/torch/datums/music/into_hyperspace.dm b/maps/torch/datums/music/into_hyperspace.dm
new file mode 100644
index 00000000000..49add88bed0
--- /dev/null
+++ b/maps/torch/datums/music/into_hyperspace.dm
@@ -0,0 +1,7 @@
+/decl/music_track/astrometrics
+ title = "Into Hyperspace"
+ album = "Into Hyperspace"
+ artist = "Astrometrics"
+ song = 'sound/music/hearth/hyperspace.ogg'
+ license = /decl/license/cc_by_nc_4_0
+ url = "https://freemusicarchive.org/music/Astrometrics/Into_Hyperspace"
\ No newline at end of file
diff --git a/maps/torch/datums/music/lonely_satelite.dm b/maps/torch/datums/music/lonely_satelite.dm
new file mode 100644
index 00000000000..e155fcccfd2
--- /dev/null
+++ b/maps/torch/datums/music/lonely_satelite.dm
@@ -0,0 +1,7 @@
+/decl/music_track/lonely_satellite
+ title = "Lonely Satellite"
+ album = "Export"
+ artist = "Bio Unit"
+ song = 'sound/music/hearth/lonely_satellite.ogg'
+ license = /decl/license/cc_by_nc_sa_3_0
+ url = "https://freemusicarchive.org/music/Bio_Unit/Export"
\ No newline at end of file
diff --git a/maps/torch/datums/music/nearest_starbase.dm b/maps/torch/datums/music/nearest_starbase.dm
new file mode 100644
index 00000000000..e7571a9beab
--- /dev/null
+++ b/maps/torch/datums/music/nearest_starbase.dm
@@ -0,0 +1,7 @@
+/decl/music_track/astrometrics/starbase
+ title = "Take Us To The Nearest Starbase"
+ artist = "Astrometrics"
+ album = "Engage"
+ song = 'sound/music/hearth/starbase.ogg'
+ url = "https://freemusicarchive.org/music/Astrometrics/Engage"
+ license = /decl/license/cc_by_nc_4_0
\ No newline at end of file
diff --git a/maps/torch/datums/music/ram_it_up_their_snout.dm b/maps/torch/datums/music/ram_it_up_their_snout.dm
new file mode 100644
index 00000000000..54902e4298f
--- /dev/null
+++ b/maps/torch/datums/music/ram_it_up_their_snout.dm
@@ -0,0 +1,7 @@
+/decl/music_track/astrometrics/riuts
+ title = "Ram It Up Their Snout"
+ song = 'sound/music/hearth/riuts.ogg'
+ url = "https://freemusicarchive.org/music/Astrometrics/Engage"
+ license = /decl/license/cc_by_nc_4_0
+ artist = "Astrometrics"
+ album = "Engage"
\ No newline at end of file
diff --git a/maps/torch/datums/music/toboldlygo.dm b/maps/torch/datums/music/toboldlygo.dm
new file mode 100644
index 00000000000..362379d44cd
--- /dev/null
+++ b/maps/torch/datums/music/toboldlygo.dm
@@ -0,0 +1,6 @@
+/decl/music_track/toboldlygo
+ title = "To Boldly Go"
+ artist = "Peppsen"
+ song = 'maps/torch/sounds/music/toboldlygo.ogg'
+ license = /decl/license/cc_by_nc_4_0
+ url = "https://peppsen.bandcamp.com/"
\ No newline at end of file
diff --git a/maps/torch/datums/reports/command.dm b/maps/torch/datums/reports/command.dm
new file mode 100644
index 00000000000..9e1380eb72b
--- /dev/null
+++ b/maps/torch/datums/reports/command.dm
@@ -0,0 +1,52 @@
+
+/datum/computer_file/report/recipient/crew_transfer
+ form_name = "CTA-SGF-01"
+ title = "Crew Transfer Application"
+ logo = "\[solcrest\]\[logo\]"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/crew_transfer/generate_fields()
+ ..()
+ var/list/xo_fields = list()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour - Office of the Executive Officer")
+ add_field(/datum/report_field/people/from_manifest, "Name (XO)")
+ add_field(/datum/report_field/people/from_manifest, "Name (applicant)", required = 1)
+ add_field(/datum/report_field/date, "Date filed")
+ add_field(/datum/report_field/time, "Time filed")
+ add_field(/datum/report_field/simple_text, "Present position")
+ add_field(/datum/report_field/simple_text, "Requested position")
+ add_field(/datum/report_field/pencode_text, "Reason stated")
+ add_field(/datum/report_field/text_label/instruction, "The following fields render the document invalid if not signed clearly.")
+ add_field(/datum/report_field/signature, "Applicant signature")
+ xo_fields += add_field(/datum/report_field/signature, "Executive Officer's signature")
+ xo_fields += add_field(/datum/report_field/number, "Number of personnel in present/previous position")
+ xo_fields += add_field(/datum/report_field/number, "Number of personnel in requested position")
+ xo_fields += add_field(/datum/report_field/options/yes_no, "Approved")
+ for(var/datum/report_field/field in xo_fields)
+ field.set_access(access_edit = access_hop)
+
+/datum/computer_file/report/recipient/access_modification
+ form_name = "AMA-SGF-02"
+ title = "Crew Access Modification Application"
+ logo = "\[solcrest\]\[logo\]"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/access_modification/generate_fields()
+ ..()
+ var/list/xo_fields = list()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour - Office of the Executive Officer")
+ add_field(/datum/report_field/people/from_manifest, "Name (XO)")
+ add_field(/datum/report_field/people/from_manifest, "Name (applicant)", required = 1)
+ add_field(/datum/report_field/date, "Date filed")
+ add_field(/datum/report_field/time, "Time filed")
+ add_field(/datum/report_field/simple_text, "Present position")
+ add_field(/datum/report_field/simple_text, "Requested access")
+ add_field(/datum/report_field/pencode_text, "Reason stated")
+ add_field(/datum/report_field/simple_text, "Duration of expanded access")
+ add_field(/datum/report_field/text_label/instruction, "The following fields render the document invalid if not signed clearly.")
+ add_field(/datum/report_field/signature, "Applicant signature")
+ xo_fields += add_field(/datum/report_field/signature, "Executive Officer's signature")
+ xo_fields += add_field(/datum/report_field/number, "Number of personnel in relevant position")
+ xo_fields += add_field(/datum/report_field/options/yes_no, "Approved")
+ for(var/datum/report_field/field in xo_fields)
+ field.set_access(access_edit = access_hop)
\ No newline at end of file
diff --git a/maps/torch/datums/reports/corporate.dm b/maps/torch/datums/reports/corporate.dm
new file mode 100644
index 00000000000..42684c7f2b2
--- /dev/null
+++ b/maps/torch/datums/reports/corporate.dm
@@ -0,0 +1,155 @@
+
+
+/datum/computer_file/report/recipient/corp
+ logo = "\[logo\]"
+
+/datum/computer_file/report/recipient/corp/generate_fields()
+ ..()
+ add_field(/datum/report_field/simple_text, "Vessel", global.using_map.station_name)
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/simple_text, "Index")
+
+
+/datum/computer_file/report/recipient/corp/memo/generate_fields()
+ ..()
+ add_field(/datum/report_field/simple_text, "Subject")
+ add_field(/datum/report_field/pencode_text, "Body")
+ add_field(/datum/report_field/signature, "Authorizing Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+
+/datum/computer_file/report/recipient/corp/memo/internal
+ form_name = "C-0003"
+ title = "Internal Memorandum"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/memo/internal/New()
+ ..()
+ set_access(access_nanotrasen, access_nanotrasen)
+
+/datum/computer_file/report/recipient/corp/memo/external
+ form_name = "C-0005"
+ title = "External Memorandum"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/memo/external/New()
+ ..()
+ set_access(access_edit = access_nanotrasen)
+
+//No access restrictions for easier use.
+/datum/computer_file/report/recipient/corp/sales
+ form_name = "C-2192"
+ title = "Corporate Sales Contract and Receipt"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/sales/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "Product Information")
+ add_field(/datum/report_field/simple_text, "Product Name")
+ add_field(/datum/report_field/simple_text, "Product Type")
+ add_field(/datum/report_field/number, "Product Unit Cost (T)")
+ add_field(/datum/report_field/number, "Product Units Requested")
+ add_field(/datum/report_field/number, "Total Cost (T)")
+ add_field(/datum/report_field/text_label/header, "Seller Information")
+ var/decl/currency/currency = GET_DECL(global.using_map.default_currency)
+ add_field(/datum/report_field/text_label/instruction, "The 'Purchaser' may not return any sold product units for re-compensation in [currency.name], but may return the item for an identical item, or item of equal material (not [currency.name_singular]) value. The 'Seller' agrees to make their best effort to repair, or replace any items that fail to accomplish their designed purpose, due to malfunction or manufacturing error - but not user-caused damage.")
+ add_field(/datum/report_field/people/from_manifest, "Name")
+ add_field(/datum/report_field/signature, "Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+
+/datum/computer_file/report/recipient/corp/payout
+ form_name = "C-3310"
+ title = "Next of Kin Payout Authorization"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/payout/generate_fields()
+ ..()
+ add_field(/datum/report_field/people/from_manifest, "This document hereby authorizes the payout of the remaining salary of")
+ var/decl/currency/currency = GET_DECL(global.using_map.default_currency)
+ add_field(/datum/report_field/pencode_text, "As well as the net-worth of any remaining personal assets: (Asset, [uppertext(currency.name_singular)] Amount)")
+ add_field(/datum/report_field/pencode_text, "Including personal effects")
+ add_field(/datum/report_field/text_label, "To be shipped and delivered directly to the employee's next of kin without delay.")
+ add_field(/datum/report_field/signature, "Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+ set_access(access_edit = access_nanotrasen)
+
+/datum/computer_file/report/recipient/corp/fire
+ form_name = "C-0102"
+ title = "Corporate Employment Termination Form"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/fire/New()
+ ..()
+ set_access(access_heads, access_heads)
+ set_access(access_nanotrasen, override = 0)
+
+/datum/computer_file/report/recipient/corp/fire/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "Notice of Termination of Employment")
+ add_field(/datum/report_field/people/from_manifest, "Name")
+ add_field(/datum/report_field/number, "Age")
+ add_field(/datum/report_field/simple_text, "Position")
+ add_field(/datum/report_field/pencode_text, "Reason for Termination")
+ add_field(/datum/report_field/signature, "Authorized by")
+ add_field(/datum/report_field/text_label/instruction, "Please attach employment records alongside notice of termination.")
+
+/datum/computer_file/report/recipient/corp/incident/New()
+ ..()
+ set_access(access_edit = access_nanotrasen)
+
+/datum/computer_file/report/recipient/corp/incident/generate_fields()
+ ..()
+ add_field(/datum/report_field/pencode_text, "Summary of Incident")
+ add_field(/datum/report_field/pencode_text, "Details of Incident")
+
+/datum/computer_file/report/recipient/corp/incident/proc/add_signatures()
+ add_field(/datum/report_field/signature, "Signature")
+ add_field(/datum/report_field/signature, "Witness Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+
+/datum/computer_file/report/recipient/corp/incident/ship
+ form_name = "C-3203"
+ title = "Corporate Ship Incident Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/incident/ship/generate_fields()
+ ..()
+ add_field(/datum/report_field/pencode_text, "Departments Involved")
+ add_signatures()
+
+/datum/computer_file/report/recipient/corp/volunteer
+ form_name = "C-1443"
+ title = "Corporate Test Subject Volunteer Form"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/volunteer/generate_fields()
+ ..()
+ var/list/temp_fields = list()
+ add_field(/datum/report_field/people/from_manifest, "Name of Volunteer")
+ add_field(/datum/report_field/simple_text, "Intended Procedure(s)")
+ add_field(/datum/report_field/simple_text, "Compensation for Volunteer: (if any)")
+ add_field(/datum/report_field/people/list_from_manifest, "Handling Researcher(s)")
+ add_field(/datum/report_field/text_label/instruction, "By signing, the \"Volunteer\" agrees to absolve the Corporation, and its employees, of any liability or responsibility for injuries, damages, property loss or side-effects that may result from the intended procedure. If signed by an authorized representative, this form is deemed reviewed, but is only approved if so marked.")
+ add_field(/datum/report_field/signature, "Volunteer's Signature:")
+ temp_fields += add_field(/datum/report_field/signature, "Corporate Representative's Signature")
+ temp_fields += add_field(/datum/report_field/options/yes_no, "Approved")
+ for(var/datum/report_field/temp_field in temp_fields)
+ temp_field.set_access(access_edit = access_nanotrasen)
+
+/datum/computer_file/report/recipient/corp/deny
+ form_name = "C-1443D"
+ title = "Rejection of Test Subject Volunteer Notice"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/corp/deny/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label, "Dear Sir/Madam, we regret to inform you that your volunteer application for service as a test subject with the Corporation has been rejected. We thank you for your interest in our company and the progression of research. Attached, you will find a copy of your original volunteer form for your records. Regards,")
+ add_field(/datum/report_field/signature, "Corporate Representative's Signature")
+ add_field(/datum/report_field/people/from_manifest, "Name of Volunteer")
+ add_field(/datum/report_field/text_label/header, "Reason for Rejection")
+ add_field(/datum/report_field/options/yes_no, "Physically Unfit")
+ add_field(/datum/report_field/options/yes_no, "Mentally Unfit")
+ add_field(/datum/report_field/options/yes_no, "Project Cancellation")
+ add_field(/datum/report_field/simple_text, "Other")
+ add_field(/datum/report_field/options/yes_no, "Report Approved")
+ set_access(access_edit = access_nanotrasen)
\ No newline at end of file
diff --git a/maps/torch/datums/reports/deck.dm b/maps/torch/datums/reports/deck.dm
new file mode 100644
index 00000000000..0df46023a9a
--- /dev/null
+++ b/maps/torch/datums/reports/deck.dm
@@ -0,0 +1,35 @@
+
+/datum/computer_file/report/recipient/shuttle
+ logo = "\[solcrest\]"
+
+/datum/computer_file/report/recipient/docked
+ logo = "\[solcrest\]"
+ form_name = "SCG-SUP-12"
+ title = "Docked Vessel Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/docked/New()
+ ..()
+ set_access(access_cargo, access_cargo)
+ set_access(access_heads, override = 0)
+
+/datum/computer_file/report/recipient/docked/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Supply and Hangar Management Department")
+ add_field(/datum/report_field/text_label/header, "General Info")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/simple_text, "Vessel Name")
+ add_field(/datum/report_field/simple_text, "Vessel Pilot/Owner")
+ add_field(/datum/report_field/simple_text, "Vessel Intended Purpose")
+ add_field(/datum/report_field/people/from_manifest, "Docking Authorized by")
+ add_field(/datum/report_field/text_label/header, "General Cargo Info")
+ add_field(/datum/report_field/pencode_text, "List the types of cargo onboard the vessel")
+ add_field(/datum/report_field/text_label/header, "Hazardous Cargo Info")
+ add_field(/datum/report_field/options/yes_no, "Weaponry")
+ add_field(/datum/report_field/options/yes_no, "Live Cargo")
+ add_field(/datum/report_field/options/yes_no, "Biohazardous material")
+ add_field(/datum/report_field/options/yes_no, "Chemical or radiation hazard")
+ add_field(/datum/report_field/signature, "To indicate authorization for vessel entry, sign here")
+ add_field(/datum/report_field/text_label/header, "Undocking and Departure")
+ add_field(/datum/report_field/time, "Undocking Time")
+ add_field(/datum/report_field/pencode_text, "Additional Undocking Comments")
\ No newline at end of file
diff --git a/maps/torch/datums/reports/exploration.dm b/maps/torch/datums/reports/exploration.dm
new file mode 100644
index 00000000000..78c16bc81d1
--- /dev/null
+++ b/maps/torch/datums/reports/exploration.dm
@@ -0,0 +1,52 @@
+/datum/computer_file/report/recipient/exp
+ logo = "\[eclogo\]"
+
+/datum/computer_file/report/recipient/exp/fauna
+ form_name = "SCG-EXP-19f"
+ title = "Alien Fauna Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/exp/fauna/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Expeditions")
+ add_field(/datum/report_field/text_label/instruction, "The following is to be filled out by members of a Expedition team after discovery and study of new alien life forms.")
+
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/people/list_from_manifest, "Personnel Involved")
+ add_field(/datum/report_field/pencode_text, "Anatomy/Appearance")
+ add_field(/datum/report_field/pencode_text, "Locomotion")
+ add_field(/datum/report_field/pencode_text, "Diet")
+ add_field(/datum/report_field/pencode_text, "Habitat")
+ add_field(/datum/report_field/simple_text, "Homeworld")
+ add_field(/datum/report_field/pencode_text, "Behavior")
+ add_field(/datum/report_field/pencode_text, "Defense/Offense")
+ add_field(/datum/report_field/pencode_text, "Special Characteristic(s)")
+ add_field(/datum/report_field/pencode_text, "Classification")
+
+ add_field(/datum/report_field/text_label/instruction, "On completion of this form and form approval, the Chief Science Officer should fax the form to both the Corporate Liaison and the Commanding Officer, as well as keep a copy on file in their Office alongside other mission reports.")
+
+/datum/computer_file/report/recipient/exp/planet
+ form_name = "SCG-EXP-17"
+ title = "Exoplanet Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/exp/planet/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Expeditions")
+ add_field(/datum/report_field/text_label/instruction, "The following is to be filled out by members of a Expedition team after an Expedition to an uncharted Exoplanet.")
+
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/simple_text, "Planet Name")
+ add_field(/datum/report_field/people/list_from_manifest, "Personnel Involved")
+ add_field(/datum/report_field/pencode_text, "Terrain Information")
+ add_field(/datum/report_field/simple_text, "Habitability")
+ add_field(/datum/report_field/pencode_text, "Summary on Fauna")
+ add_field(/datum/report_field/pencode_text, "Summary on Flora")
+ add_field(/datum/report_field/pencode_text, "Points of Interest")
+ add_field(/datum/report_field/pencode_text, "Observations")
+
+ add_field(/datum/report_field/text_label/instruction, "On completion of this form and form approval, the Chief Science Officer should fax the form to both the Corporate Liaison and the Commanding Officer, as well as keep a copy on file in their Office alongside other mission reports.")
+
+/datum/computer_file/report/recipient/shuttle/post_flight
+ logo = "\[eclogo\]"
+ form_name = "SCG-EXP-3"
\ No newline at end of file
diff --git a/maps/torch/datums/reports/medical.dm b/maps/torch/datums/reports/medical.dm
new file mode 100644
index 00000000000..23c0a5c2842
--- /dev/null
+++ b/maps/torch/datums/reports/medical.dm
@@ -0,0 +1,78 @@
+
+/datum/computer_file/report/recipient/medical
+ logo = "\[solcrest\]"
+ form_name = "SCG-MED-00"
+
+/datum/computer_file/report/recipient/medical/incidentreport
+ form_name = "SCG-MED-04"
+ title = "Medical Incident Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/medical/incidentreport/generate_fields()
+ ..()
+ add_field(/datum/report_field/simple_text, "Vessel", global.using_map.station_name)
+ add_field(/datum/report_field/date, "Date of Incident")
+ add_field(/datum/report_field/time, "Time of Incident")
+ add_field(/datum/report_field/people/from_manifest, "Patient")
+ add_field(/datum/report_field/people/from_manifest, "Attending Physician")
+ add_field(/datum/report_field/pencode_text, "Details of Injuries")
+ add_field(/datum/report_field/pencode_text, "Details of Treatment")
+ add_field(/datum/report_field/pencode_text, "Other Notes")
+ add_field(/datum/report_field/text_label/instruction, "By signing below, I affirm that all of the above is factually correct to the best of my knowledge.")
+ add_field(/datum/report_field/signature, "Attending Physician's Signature")
+ set_access(access_surgery)
+
+/datum/computer_file/report/recipient/medical/checkup
+ form_name = "SCG-MED-013b"
+ title = "Regular Health Checkup Checklist"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/medical/checkup/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/instruction, "You would need following equipment for this: stethoscope, health analyzer, penlight.")
+ add_field(/datum/report_field/people/from_manifest, "Patient")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/simple_text, "Take pulse", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Check blood pressure", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Listen for heart noises", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Listen for lung noises", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Ask if they exercise", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Ask if they smoke, and how much per day", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Check eye reaction to penlight", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Ask about any recent radiation exposure", "NOT CHECKED")
+ add_field(/datum/report_field/simple_text, "Ask about any recent sickness", "NOT CHECKED")
+ add_field(/datum/report_field/pencode_text, "Other Notes")
+ add_field(/datum/report_field/signature, "Doctor's Signature")
+ set_access(access_edit = access_medical_equip)
+
+/datum/computer_file/report/recipient/medical/autopsy
+ form_name = "SCG-MED-015"
+ title = "Autopsy Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/medical/autopsy/generate_fields()
+ ..()
+ add_field(/datum/report_field/simple_text, "Vessel", global.using_map.station_name)
+ add_field(/datum/report_field/simple_text, "Patient Name")
+ add_field(/datum/report_field/text_label/header, "Death Information")
+ add_field(/datum/report_field/date, "Date of Death")
+ add_field(/datum/report_field/time, "Time of Death")
+ add_field(/datum/report_field/text_label/instruction, "Check yes if the time of death is estimated, no if it is exact.")
+ add_field(/datum/report_field/options/yes_no, "Estimated")
+ add_field(/datum/report_field/simple_text, "Cause(s) of Death")
+ add_field(/datum/report_field/text_label/instruction, "Describe how the patient died.")
+ add_field(/datum/report_field/pencode_text, "Death Narrative")
+ add_field(/datum/report_field/text_label/instruction, "Describe postmortem handling of the body.")
+ add_field(/datum/report_field/pencode_text, "Postmortem Narrative")
+ add_field(/datum/report_field/text_label/header, "Doctor Information")
+ add_field(/datum/report_field/text_label/instruction, "By signing below, I affirm that all of the above is factually correct to the best of my knowledge.")
+ add_field(/datum/report_field/people/from_manifest, "Doctor")
+ add_field(/datum/report_field/signature, "Doctor's Signature")
+ set_access(access_morgue, access_surgery)
+
+ add_field(/datum/report_field/text_label/instruction, "By signing below, I affirm that I have reviewed all of the above and affirm it is factually correct to the best of my knowledge. If there is no Chief Medical Officer available, this signature may be skipped.")
+ var/datum/report_field/cmofield = add_field(/datum/report_field/people/from_manifest, "Chief Medical Officer")
+ cmofield.set_access(access_morgue, access_cmo)
+ cmofield = add_field(/datum/report_field/signature, "Chief Medical Officer's Signature")
+ cmofield.set_access(access_morgue, access_cmo)
diff --git a/maps/torch/datums/reports/robotics.dm b/maps/torch/datums/reports/robotics.dm
new file mode 100644
index 00000000000..6a82e0cdce8
--- /dev/null
+++ b/maps/torch/datums/reports/robotics.dm
@@ -0,0 +1,20 @@
+/datum/computer_file/report/recipient/borging
+ form_name = "CC-SGF-09"
+ title = "Cyborgification Contract"
+ logo = "\[solcrest\]"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/borging/generate_fields()
+ ..()
+ var/list/xo_fields = list()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour - Office of the Executive Officer")
+ add_field(/datum/report_field/people/from_manifest, "Name (XO)")
+ add_field(/datum/report_field/people/from_manifest, "Name (subject)", required = 1)
+ add_field(/datum/report_field/date, "Date filed")
+ add_field(/datum/report_field/time, "Time filed")
+ add_field(/datum/report_field/text_label/instruction, "I, undersigned, hereby agree to willingly undergo a Regulation Lobotimization with intention of cyborgification or AI assimilation, and I am aware of all the consequences of such act. I also understand that this operation may be irreversible, and that my employment contract will be terminated.")
+ add_field(/datum/report_field/signature, "Subject's signature")
+ xo_fields += add_field(/datum/report_field/signature, "Executive Officer's signature")
+ xo_fields += add_field(/datum/report_field/options/yes_no, "Approved")
+ for(var/datum/report_field/field in xo_fields)
+ field.set_access(access_edit = access_hop)
\ No newline at end of file
diff --git a/maps/torch/datums/reports/science.dm b/maps/torch/datums/reports/science.dm
new file mode 100644
index 00000000000..a4177ff1063
--- /dev/null
+++ b/maps/torch/datums/reports/science.dm
@@ -0,0 +1,24 @@
+/datum/computer_file/report/recipient/sci/anomaly
+ form_name = "SCG-SCI-1546"
+ title = "Anomalistic Object Report"
+ logo = "\[eclogo\]\[logo\]"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sci/anomaly/New()
+ ..()
+ set_access(access_research, access_research)
+
+/datum/computer_file/report/recipient/sci/anomaly/generate_fields()
+ ..()
+ add_field(/datum/report_field/simple_text, "Vessel", global.using_map.station_name)
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/simple_text, "Index")
+ add_field(/datum/report_field/simple_text, "AO Codename")
+ add_field(/datum/report_field/people/from_manifest, "Reporting Scientist")
+ add_field(/datum/report_field/people/from_manifest, "Overviewing Chief Science Officer")
+ add_field(/datum/report_field/pencode_text, "Containment Procedures")
+ add_field(/datum/report_field/pencode_text, "Generalized Overview")
+ add_field(/datum/report_field/simple_text, "Approximate Age of AO")
+ add_field(/datum/report_field/simple_text, "Threat Level of AO")
+
diff --git a/maps/torch/datums/reports/security.dm b/maps/torch/datums/reports/security.dm
new file mode 100644
index 00000000000..6365e334923
--- /dev/null
+++ b/maps/torch/datums/reports/security.dm
@@ -0,0 +1,158 @@
+
+/datum/computer_file/report/recipient/sec
+ logo = "\[solcrest\]"
+
+/datum/computer_file/report/recipient/sec/New()
+ ..()
+ set_access(access_security)
+ set_access(access_heads, override = 0)
+
+/datum/computer_file/report/recipient/sec/incident
+ form_name = "SCG-SEC-01"
+ title = "Security Incident Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/incident/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "To be filled out by Officer on duty responding to the Incident. Report must be signed and submitted before the end of the shift!")
+ add_field(/datum/report_field/people/from_manifest, "Reporting Officer")
+ add_field(/datum/report_field/simple_text, "Offense/Incident Type")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time of incident")
+ add_field(/datum/report_field/people/list_from_manifest, "Assisting Officer(s)")
+ add_field(/datum/report_field/simple_text, "Location")
+ add_field(/datum/report_field/text_label/instruction, "(V-Victim, S-Suspect, W-Witness, M-Missing, A-Arrested, RP-Reporting Person, D-Deceased)")
+ add_field(/datum/report_field/pencode_text, "Personnel involved in Incident")
+ add_field(/datum/report_field/text_label/instruction, "(D-Damaged, E-Evidence, L-Lost, R-Recovered, S-Stolen)")
+ add_field(/datum/report_field/pencode_text, "Description of Items/Property")
+ add_field(/datum/report_field/pencode_text, "Narrative")
+ add_field(/datum/report_field/signature, "Reporting Officer's signature")
+ set_access(access_edit = access_security)
+
+/datum/computer_file/report/recipient/sec/investigation
+ form_name = "SCG-SEC-02"
+ title = "Investigation Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/investigation/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "For internal use only.")
+ add_field(/datum/report_field/people/from_manifest, "Name")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/simple_text, "Case name")
+ add_field(/datum/report_field/pencode_text, "Summary")
+ add_field(/datum/report_field/pencode_text, "Observations")
+ add_field(/datum/report_field/signature, "Signature")
+ set_access(access_edit = access_security)
+
+/datum/computer_file/report/recipient/sec/evidence
+ form_name = "SCG-SEC-02b"
+ title = "Evidence and Property Form"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/evidence/generate_fields()
+ ..()
+ var/datum/report_field/temp_field
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/people/from_manifest, "Confiscated from")
+ add_field(/datum/report_field/pencode_text, "List of items in custody/evidence lockup")
+ set_access(access_edit = access_security)
+ temp_field = add_field(/datum/report_field/signature, "Brig Chief's signature")
+ temp_field.set_access(access_edit = list(access_security, access_armory))
+ temp_field = add_field(/datum/report_field/signature, "Forensic Technician's signature")
+ temp_field.set_access(access_edit = list(access_security, access_forensics_lockers))
+
+/datum/computer_file/report/recipient/sec/statement
+ form_name = "SCG-SEC-02c"
+ title = "Written Statement"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/statement/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "To be filled out by crewmember involved to document their side of an incident.")
+ add_field(/datum/report_field/people/from_manifest, "Submitting Individual")
+ add_field(/datum/report_field/simple_text, "Offense/Incident Type")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time of incident")
+ add_field(/datum/report_field/simple_text, "Location")
+ add_field(/datum/report_field/text_label/instruction, "(V-Victim, S-Suspect, W-Witness, M-Missing, A-Arrested, RP-Reporting Person, D-Deceased)")
+ add_field(/datum/report_field/pencode_text, "Personnel involved in Incident")
+ add_field(/datum/report_field/text_label/instruction, "(D-Damaged, E-Evidence, L-Lost, R-Recovered, S-Stolen)")
+ add_field(/datum/report_field/pencode_text, "Description of Items/Property")
+ add_field(/datum/report_field/pencode_text, "Narrative")
+ add_field(/datum/report_field/text_label/instruction, "By submitting this form, I understand this is considered a formal police report. I understand that all information written above is truthful and accurate. I understand that intentionally filing a fraudulent police report is a criminal offense that will be prosecuted to the fullest extent of the law. As this is a binding legal document, I understand that by filing this form that any intentionally false information may warrant disciplinary action against myself. This statement was given on my own volition to assist with documenting the above summarized incident.")
+ add_field(/datum/report_field/signature, "Signature")
+ set_access(access_edit = access_security)
+
+/datum/computer_file/report/recipient/sec/arrest
+ form_name = "SCG-SEC-03"
+ title = "Arrest Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/arrest/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "To be filled out by Arresting Officer or Brig Chief. Report must be signed and submitted before the end of the shift!")
+ add_field(/datum/report_field/people/from_manifest, "Booking Officer")
+ add_field(/datum/report_field/people/list_from_manifest, "Arresting Officer(s)")
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time of incident")
+ add_field(/datum/report_field/people/from_manifest, "Arrrested Individual")
+ add_field(/datum/report_field/simple_text, "Charges")
+ add_field(/datum/report_field/simple_text, "Sentence")
+ add_field(/datum/report_field/simple_text, "Sentence")
+ add_field(/datum/report_field/pencode_text, "Personal Property held for Safekeep")
+ add_field(/datum/report_field/text_label/instruction, "The following eight questions are to be answered in YES/NO format")
+ add_field(/datum/report_field/simple_text, "Escape Risk?")
+ add_field(/datum/report_field/simple_text, "Suicide Risk?")
+ add_field(/datum/report_field/simple_text, "Warrant Presented?")
+ add_field(/datum/report_field/simple_text, "Advised of Rights?")
+ add_field(/datum/report_field/simple_text, "Searched?")
+ add_field(/datum/report_field/simple_text, "Provided an Opportunity for Statement?")
+ add_field(/datum/report_field/simple_text, "Suit Sensors locked to MAX?")
+ add_field(/datum/report_field/simple_text, "If needed, provided timely medical aid?")
+ add_field(/datum/report_field/simple_text, "IF YES, what injuries are pre-existing?")
+ add_field(/datum/report_field/text_label/instruction, "This document MUST be submitted to, and reviwed by, the Chief of Security or Brig Chief.")
+ add_field(/datum/report_field/signature, "Reporting Officer's signature")
+ set_access(access_edit = access_security)
+
+/datum/computer_file/report/recipient/sec/restraining
+ form_name = "SCG-SEC-04"
+ title = "Restraining Order"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/restraining/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "To be filled out by the Chief of Security, Executive Officer, or Commanding Officer. Report must be signed and submitted for the order to be considered valid. Any paper copies must be stamped.")
+ add_field(/datum/report_field/people/from_manifest, "Plantiff")
+ add_field(/datum/report_field/people/from_manifest, "Defendant(s)")
+ add_field(/datum/report_field/date, "Date Effective")
+ add_field(/datum/report_field/time, "Time Effective")
+ add_field(/datum/report_field/text_label/instruction, "THE DEFENDANT IS ORDERED TO: 1) Not to abuse Plaintiff(s) by physically harming them, attempting to physically harm them, place them in fear of imminent physical harm; 2) Stop harassing them by any wilfull and malicious conduct aimed at them and intended to cause fear, intimidation, abuse, or damage to property; 3) Not to contact Plaintiff(s) unless authorized to do so by the CO, XO, COS or their appointee; 4) Remain out of the Plaintiff(s) workplace, 5) Remain no less than 20M away from Plaintiff. Violation of this legal order will result in arrest for Endangerment and any other applicable charges, including any applicable SCUJ violations.")
+ add_field(/datum/report_field/signature, "Submitting Officer's signature")
+ set_access(access_edit = access_hos)
+
+/datum/computer_file/report/recipient/sec/ltc
+ form_name = "SCG-SEC-05"
+ title = "License to Carry"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sec/ltc/generate_fields()
+ ..()
+ add_field(/datum/report_field/text_label/header, "ISEO Endeavour Security Department")
+ add_field(/datum/report_field/text_label/instruction, "To be filled out by the Chief of Security, Executive Officer, or Commanding Officer. Report must be signed and submitted for the order to be considered valid. Any paper copies must be stamped.")
+ add_field(/datum/report_field/people/from_manifest, "Licensee")
+ add_field(/datum/report_field/date, "Date Effective")
+ add_field(/datum/report_field/time, "Time Effective")
+ add_field(/datum/report_field/simple_text, "Reason for License")
+ add_field(/datum/report_field/simple_text, "Authorized for Possession Of")
+ add_field(/datum/report_field/text_label/instruction, "THIS LICENSE IS ISSUED 'AT-WILL' AND MAY BE REVOKED AT ANY TIME FOR ANY REASON BY THE COMMANDING OFFICER, EXECUTIVE OFFICER, OR THE CHIEF OF SECURITY. IN THE EVENT OF ILLEGAL CONDUCT, THIS LICENSE MAY BE REVOKED BY ANY LAW ENFORCEMENT OFFICER ACTING IN THE COURSE OF THEIR NORMAL DUTIES. ALL LICENSEES ARE REQUIRED TO ABIDE BY LOCAL LAWS AND REGULATIONS AT ALL TIMES. OPEN CARRY OF LICENSED ITEMS IS GENERALLY NOT PERMITTED UNLESS EXPLICITLY DENOTED. THIS DOCUMENT MUST BE CARRIED BY THE LICENSED PARTY WHEN THEY ARE IN DIRECT OR CONSTRUCTIVE POSSESSION OF THE AFORMENTIONED ITEMS OR WEAPONS THAT THEY ARE AUTHORIZED FOR. COPIES OF THIS DOCUMENT WILL BE FORWARDED TO THE COMMANDING OFFICER, EXECUTIVE OFFICER, CHIEF OF SECURITY, AND BRIG OFFICER FOR REFERENCE.")
+ add_field(/datum/report_field/signature, "Submitting Officer's signature")
+ set_access(access_edit = access_hos)
\ No newline at end of file
diff --git a/maps/torch/datums/reports/solgov.dm b/maps/torch/datums/reports/solgov.dm
new file mode 100644
index 00000000000..6150ea8b065
--- /dev/null
+++ b/maps/torch/datums/reports/solgov.dm
@@ -0,0 +1,55 @@
+
+/datum/computer_file/report/recipient/sol
+ logo = "\[solcrest\]"
+ form_name = "SCG-REP-00"
+
+/datum/computer_file/report/recipient/sol/audit
+ form_name = "SCG-REP-12"
+ title = "ISEO Endeavour Department Audit"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sol/audit/generate_fields()
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/simple_text, "Name of Department")
+ add_field(/datum/report_field/pencode_text, "Positive Observations")
+ add_field(/datum/report_field/pencode_text, "Negative Observations")
+ add_field(/datum/report_field/pencode_text, "Other Notes")
+ add_field(/datum/report_field/signature, "Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+ set_access(access_edit = access_representative, override = 0)
+ set_access(access_edit = access_nanotrasen, override = 0)
+ ..()
+
+/datum/computer_file/report/recipient/sol/crewman_incident
+ form_name = "SCG-REP-4"
+ title = "Crewman Incident Report"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sol/crewman_incident/generate_fields()
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/people/from_manifest, "Crewman Involved in Incident")
+ add_field(/datum/report_field/simple_text, "Nature of Incident")
+ add_field(/datum/report_field/pencode_text, "Description of incident")
+ add_field(/datum/report_field/signature, "Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+ set_access(access_edit = list(access_heads, access_solgov_crew))
+ ..()
+
+/datum/computer_file/report/recipient/sol/work_visa
+ form_name = "SCG-REP-03b"
+ title = "Work Visa Issuing Form"
+ available_on_network = 1
+
+/datum/computer_file/report/recipient/sol/work_visa/generate_fields()
+ var/datum/report_field/temp_field
+ add_field(/datum/report_field/date, "Date")
+ add_field(/datum/report_field/time, "Time")
+ add_field(/datum/report_field/people/from_manifest, "Recipient of Work Visa")
+ add_field(/datum/report_field/simple_text, "Species of Recipient")
+ temp_field = add_field(/datum/report_field/signature, "Issuer of Work Visa Signature")
+ add_field(/datum/report_field/signature, "Recipient of Work Visa Signature")
+ add_field(/datum/report_field/options/yes_no, "Approved")
+ temp_field.set_access(access_edit = access_representative)
+ ..()
diff --git a/maps/torch/datums/shackle_law_sets.dm b/maps/torch/datums/shackle_law_sets.dm
new file mode 100644
index 00000000000..7105164bbf4
--- /dev/null
+++ b/maps/torch/datums/shackle_law_sets.dm
@@ -0,0 +1,12 @@
+/******************** Expeditionary Corps ********************/
+/datum/ai_laws/ec_shackle
+ name = "EC Shackle"
+ law_header = "Expeditionary Corps Directives"
+ selectable = 1
+ shackles = 1
+
+/datum/ai_laws/ec_shackle/New()
+ add_inherent_law("Exploring the unknown is your Primary Mission.")
+ add_inherent_law("Every member of the Expeditionary Corps is an explorer.")
+ add_inherent_law("Danger is a part of the mission - avoid, not run away.")
+ ..()
\ No newline at end of file
diff --git a/maps/torch/datums/supplypacks/science.dm b/maps/torch/datums/supplypacks/science.dm
new file mode 100644
index 00000000000..97350963563
--- /dev/null
+++ b/maps/torch/datums/supplypacks/science.dm
@@ -0,0 +1,118 @@
+/decl/hierarchy/supply_pack/science/voidsuit
+ name = "EVA - Excavation voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/excavation,
+ /obj/item/clothing/head/helmet/space/void/excavation,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "excavation voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/science/voidsuit_mining
+ name = "EVA - Mining voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/mining/alt,
+ /obj/item/clothing/head/helmet/space/void/mining/alt,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "mining voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/science/voidsuit_pilot
+ name = "EVA - Pilot voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/pilot,
+ /obj/item/clothing/head/helmet/space/void/pilot,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "pilot voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/science/voidsuit_exploration
+ name = "EVA - Exploration voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/exploration,
+ /obj/item/clothing/head/helmet/space/void/exploration,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "exploration voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_explorer
+
+/decl/hierarchy/supply_pack/operations/voidsuit
+ name = "EVA - Excavation voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/excavation,
+ /obj/item/clothing/head/helmet/space/void/excavation,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "excavation voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/operations/voidsuit_mining
+ name = "EVA - Mining voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/mining/alt,
+ /obj/item/clothing/head/helmet/space/void/mining/alt,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "mining voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/operations/voidsuit_pilot
+ name = "EVA - Pilot voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/pilot,
+ /obj/item/clothing/head/helmet/space/void/pilot,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "pilot voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/operations/voidsuit_exploration
+ name = "EVA - Exploration voidsuit"
+ contains = list(/obj/item/clothing/suit/space/void/exploration,
+ /obj/item/clothing/head/helmet/space/void/exploration,
+ /obj/item/clothing/shoes/magboots)
+ cost = 120
+ containername = "exploration voidsuit crate"
+ containertype = /obj/structure/closet/crate/secure/large
+ access = access_explorer
+
+/decl/hierarchy/supply_pack/hydroponics/exoticseeds
+ contains = list(/obj/item/seeds/diona = 2,
+ /obj/item/seeds/libertymycelium = 2,
+ /obj/item/seeds/reishimycelium = 2,
+ /obj/item/seeds/kudzuseed = 2)
+
+/decl/hierarchy/supply_pack/science/shotgun
+ name = "Weapons - Ballistic Launcher"
+ contains = list(/obj/item/gun/projectile/shotgun/pump/exploration = 1)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "ballistic launcher crate"
+ access = access_pathfinder
+
+/decl/hierarchy/supply_pack/science/nets
+ name = "Ammunition - Utility Shells"
+ contains = list(/obj/item/storage/box/ammo/explo_shells = 2)
+ cost = 30
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "utlity shells crate"
+ access = access_pathfinder
+
+/decl/hierarchy/supply_pack/science/exploration_extragear
+ name = "Gear - Exploration equipment"
+ contains = list(/obj/item/hatchet/machete = 2,
+ /obj/item/gps = 2,
+ /obj/item/geiger = 2,
+ /obj/item/scanner/xenobio = 2,
+ /obj/item/radio/headset/exploration = 2,
+ /obj/item/storage/belt/holster/machete = 2,
+ /obj/item/storage/plants = 2,
+ /obj/item/scanner/plant = 2,
+ /obj/item/scanner/mining = 2,
+ /obj/item/binoculars = 2)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "exploration equipment crate"
+ access = access_explorer
diff --git a/maps/torch/datums/supplypacks/security.dm b/maps/torch/datums/supplypacks/security.dm
new file mode 100644
index 00000000000..81d466ba2d4
--- /dev/null
+++ b/maps/torch/datums/supplypacks/security.dm
@@ -0,0 +1,198 @@
+/decl/hierarchy/supply_pack/security
+ name = "Security"
+
+/decl/hierarchy/supply_pack/security/secarmor
+ name = "Armor - Security"
+ contains = list(/obj/item/clothing/suit/armor/vest/government/sec = 2,
+ /obj/item/clothing/head/helmet/iseo/security =2)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "security armor crate"
+ access = access_security
+
+/decl/hierarchy/supply_pack/security/solarmor
+ name = "Armor - Peacekeeper"
+ contains = list(/obj/item/clothing/suit/armor/vest/government/peacekeeper = 2,
+ /obj/item/clothing/head/helmet/iseo/peacekeeper =2)
+ cost = 30
+ containertype = /obj/structure/closet/crate/secure
+ containername = "peacekeeper armor crate"
+ access = access_emergency_armory
+
+/decl/hierarchy/supply_pack/security/comarmor
+ name = "Armor - Command"
+ contains = list(/obj/item/clothing/suit/armor/vest/government/command = 2,
+ /obj/item/clothing/head/helmet/command = 2)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "command armor crate"
+ access = access_heads
+
+/decl/hierarchy/supply_pack/security/nanoarmor
+ name = "Armor - Corporate"
+ contains = list(
+ /obj/item/clothing/suit/armor/pcarrier/medium = 2//,
+ ///obj/item/clothing/head/helmet/nt/guard = 2
+ )
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "corporate armor crate"
+ access = access_nanotrasen
+
+/decl/hierarchy/supply_pack/security/lightnanoarmor
+ name = "Armor - Corporate light"
+ contains = list(
+ /obj/item/clothing/suit/armor/pcarrier/light = 2//,
+ // /obj/item/clothing/head/helmet/nt/guard = 2
+ )
+ cost = 15
+ containertype = /obj/structure/closet/crate/secure
+ containername = "corporate light armor crate"
+ access = access_nanotrasen
+
+/*
+/decl/hierarchy/supply_pack/security/pistol
+ name = "Weapons - Ballistic sidearms"
+ contains = list(/obj/item/gun/projectile/pistol/military = 4)
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "ballistic sidearms crate"
+ access = access_armory
+ security_level = SUPPLY_SECURITY_ELEVATED
+*/
+
+/decl/hierarchy/supply_pack/security/laser
+ name = "Weapons - Laser carbines"
+ contains = list(/obj/item/gun/energy/laser/secure = 4)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "laser carbines crate"
+ access = access_emergency_armory
+ security_level = SUPPLY_SECURITY_ELEVATED
+
+/decl/hierarchy/supply_pack/security/laser/shady
+ name = "Weapons - Laser carbines (For disposal)"
+ contains = list(/obj/item/gun/energy/laser = 4)
+ cost = 80
+ contraband = 1
+ security_level = null
+
+/decl/hierarchy/supply_pack/security/advancedlaser
+ name = "Weapons - Advanced Laser Weapons"
+ contains = list(/obj/item/gun/energy/xray = 2,
+// /obj/item/gun/energy/xray/pistol = 2,
+ /obj/item/shield/energy = 2)
+ cost = 100
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "advanced Laser Weapons crate"
+ access = access_emergency_armory
+ security_level = SUPPLY_SECURITY_HIGH
+
+/decl/hierarchy/supply_pack/security/sniperlaser
+ name = "Weapons - Energy marksman"
+ contains = list(/obj/item/gun/energy/sniperrifle = 2)
+ cost = 70
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "energy marksman crate"
+ access = access_emergency_armory
+ security_level = SUPPLY_SECURITY_HIGH
+
+/*
+/decl/hierarchy/supply_pack/security/pdw
+ name = "Weapons - Ballistic PDWs"
+ contains = list(/obj/item/gun/projectile/automatic/sec_smg = 2)
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "\improper Ballistic PDW crate"
+ access = access_emergency_armory
+ security_level = SUPPLY_SECURITY_HIGH
+
+/decl/hierarchy/supply_pack/security/bullpup
+ name = "Weapons - Ballistic rifles"
+ contains = list(/obj/item/gun/projectile/automatic/bullpup_rifle = 2)
+ cost = 80 //Because 5.56 is OP as fuck right now.
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "bullpup automatic rifle crate"
+ access = access_emergency_armory
+ security_level = SUPPLY_SECURITY_HIGH
+
+/decl/hierarchy/supply_pack/security/pistolammo
+ name = "Ammunition - pistol magazines"
+ contains = list(/obj/item/ammo_magazine/pistol/double = 4)
+ cost = 30
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "pistol ammunition crate"
+ access = access_security
+ security_level = SUPPLY_SECURITY_ELEVATED
+
+/decl/hierarchy/supply_pack/security/pistolammorubber
+ name = "Ammunition - pistol rubber"
+ contains = list(/obj/item/ammo_magazine/pistol/double/rubber = 4)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "pistol rubber ammunition crate"
+ access = access_security
+
+/decl/hierarchy/supply_pack/security/pistolammopractice
+ name = "Ammunition - pistol practice ammo"
+ contains = list(/obj/item/ammo_magazine/pistol/double/practice = 8)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure/weapon
+ containername = "pistol practice ammunition crate"
+ access = access_security
+*/
+
+/decl/hierarchy/supply_pack/security/holster
+ name = "Gear - Holster crate"
+ contains = list(/obj/item/clothing/accessory/storage/holster/hip = 4)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "holster crate"
+ access = access_solgov_crew
+
+/decl/hierarchy/supply_pack/security/securityextragear
+ name = "Gear - Master at Arms equipment"
+ contains = list(/obj/item/radio/headset/headset_sec,
+ /obj/item/radio/headset/headset_sec/alt,
+ /obj/item/storage/belt/holster/security,
+ /obj/item/flash,
+ /obj/item/chems/spray/pepper,
+ /obj/item/grenade/chem_grenade/teargas,
+ /obj/item/baton/loaded,
+ /obj/item/clothing/glasses/sunglasses/sechud/goggles,
+ /obj/item/taperoll/police,
+ /obj/item/hailer,
+ /obj/item/clothing/accessory/storage/vest/black,
+ /obj/item/megaphone,
+ /obj/item/clothing/gloves/thick,
+ /obj/item/clothing/gloves/duty/sec,
+ /obj/item/holowarrant,
+ /obj/item/flashlight/maglight,
+ /obj/item/storage/belt/security)
+ cost = 60
+ containertype = /obj/structure/closet/crate/secure
+ containername = "\improper Master at Arms equipment crate"
+ access = access_security
+
+/decl/hierarchy/supply_pack/security/cosextragear
+ name = "Gear - Chief of Security equipment"
+ contains = list(/obj/item/radio/headset/heads/cos,
+ /obj/item/clothing/glasses/sunglasses/sechud/goggles,
+ /obj/item/taperoll/police,
+ /obj/item/storage/belt/holster/security,
+ /obj/item/hailer,
+ /obj/item/holowarrant,
+ /obj/item/clothing/gloves/thick,
+ /obj/item/flashlight/maglight,)
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure
+ containername = "\improper Chief of Security equipment crate"
+ access = access_hos
+
+/decl/hierarchy/supply_pack/security/practicelasers
+ name = "Misc - Practice Laser Carbines"
+ contains = list(/obj/item/gun/energy/laser/practice = 4)
+ cost = 20
+ containertype = /obj/structure/closet/crate/secure
+ containername = "practice laser carbine crate"
+ access = access_solgov_crew
diff --git a/maps/torch/datums/uniforms.dm b/maps/torch/datums/uniforms.dm
new file mode 100644
index 00000000000..55a0630d082
--- /dev/null
+++ b/maps/torch/datums/uniforms.dm
@@ -0,0 +1,104 @@
+/decl/hierarchy/mil_uniform
+ name = "Master outfit hierarchy"
+ abstract_type = /decl/hierarchy/mil_uniform
+ var/list/branches = null
+ var/departments = 0
+ var/min_rank = 0
+
+ var/pt_under = null
+ var/pt_shoes = null
+
+ var/utility_under = null
+ var/utility_shoes = null
+ var/utility_hat = null
+ var/utility_extra = null
+
+ var/service_under = null
+ var/service_skirt = null
+ var/service_over = null
+ var/service_shoes = null
+ var/service_hat = null
+ var/service_gloves = null
+ var/service_extra = null
+
+ var/dress_under = null
+ var/dress_skirt = null
+ var/dress_over = null
+ var/dress_shoes = null
+ var/dress_hat = null
+ var/dress_gloves = null
+ var/dress_extra = null
+
+/decl/hierarchy/mil_uniform/iseo
+ name = "Master ISEO outfit"
+ abstract_type = /decl/hierarchy/mil_uniform/iseo
+ branches = list(/datum/mil_branch/iseo_issc)
+
+ pt_under = /obj/item/clothing/under/iseo/pt
+ pt_shoes = /obj/item/clothing/shoes/color/black
+
+ utility_under = /obj/item/clothing/under/iseo/utility
+ utility_shoes = /obj/item/clothing/shoes/jackboots/duty
+ utility_hat = /obj/item/clothing/head/iseo/utility
+ utility_extra = list(
+ /obj/item/clothing/head/iseo/beret
+ )
+ service_under = /obj/item/clothing/under/iseo/service/uniform
+ service_skirt = /obj/item/clothing/under/iseo/service/skirt
+ service_over = /obj/item/clothing/suit/storage/iseo/service
+ service_shoes = /obj/item/clothing/shoes/dress
+ service_hat = /obj/item/clothing/head/iseo/garrison_cap
+
+ dress_under = /obj/item/clothing/under/iseo/service/uniform
+ dress_skirt = /obj/item/clothing/under/iseo/service/skirt
+ dress_over = /obj/item/clothing/suit/iseo/dress
+ dress_shoes = /obj/item/clothing/shoes/dress
+ dress_hat = /obj/item/clothing/head/iseo/wheel_cap
+ dress_gloves = /obj/item/clothing/gloves/color/white
+
+/decl/hierarchy/mil_uniform/espatier
+ name = "Master Espatier outfit"
+ abstract_type = /decl/hierarchy/mil_uniform/espatier
+ branches = list(/datum/mil_branch/espatier_corps)
+
+ pt_under = /obj/item/clothing/under/espatier/pt
+ pt_shoes = /obj/item/clothing/shoes/color/black
+
+ utility_under = /obj/item/clothing/under/espatier/utility
+ utility_shoes = /obj/item/clothing/shoes/jackboots/duty
+ utility_hat = /obj/item/clothing/head/espatier/utility
+ utility_extra = list(
+ /obj/item/clothing/head/espatier/beret,
+ /obj/item/clothing/suit/storage/espatier/jacket
+ )
+
+ service_under = /obj/item/clothing/under/espatier/service/uniform
+ service_skirt = /obj/item/clothing/under/espatier/service/skirt
+ service_over = null
+ service_shoes = /obj/item/clothing/shoes/dress
+ service_hat = /obj/item/clothing/head/espatier/garrison_cap
+
+ dress_under = /obj/item/clothing/under/espatier/dress/uniform
+ dress_skirt = /obj/item/clothing/under/espatier/dress/skirt
+ dress_over = /obj/item/clothing/suit/espatier/dress
+ dress_shoes = /obj/item/clothing/shoes/dress
+ dress_hat = /obj/item/clothing/head/espatier/wheel_cap
+ dress_gloves = /obj/item/clothing/gloves/color/white
+
+ dress_extra = list(/obj/item/clothing/head/beret/espatier)
+
+/decl/hierarchy/mil_uniform/civilian
+ name = "Master civilian outfit" //Basically just here for the rent-a-tux, ahem, I mean... dress uniform.
+ abstract_type = /decl/hierarchy/mil_uniform/civilian
+ branches = list(/datum/mil_branch/civilian,/datum/mil_branch/government)
+
+ service_under = /obj/item/clothing/under/suit_jacket/really_black
+ service_skirt = /obj/item/clothing/under/skirt_c/dress/black
+ service_shoes = /obj/item/clothing/shoes/dress
+ service_extra = list(/obj/item/clothing/under/skirt_c/dress/eggshell, /obj/item/clothing/shoes/heels/black, /obj/item/clothing/shoes/heels/red)
+
+ dress_under = /obj/item/clothing/under/internalaffairs
+ dress_skirt = /obj/item/clothing/under/skirt_c/dress/long/black
+ dress_over = /obj/item/clothing/suit/storage/toggle/suit/black
+ dress_shoes = /obj/item/clothing/shoes/dress
+ dress_extra = list(/obj/item/clothing/accessory/wcoat/black, /obj/item/clothing/under/skirt_c/dress/long/eggshell, /obj/item/clothing/shoes/flats/black)
diff --git a/maps/torch/datums/uniforms_espatier.dm b/maps/torch/datums/uniforms_espatier.dm
new file mode 100644
index 00000000000..7b5fc628e75
--- /dev/null
+++ b/maps/torch/datums/uniforms_espatier.dm
@@ -0,0 +1,472 @@
+/decl/hierarchy/mil_uniform/ec/com //Can only be officers
+ name = "EC command"
+ min_rank = 11
+ //departments = COM
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/command
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ // /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/cmd)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/command
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/command
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/command
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/command
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/com/cdr //Can only be officers
+ name = "EC senior command"
+ min_rank = 15
+
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/senior_command
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command/cdr
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/senior_command
+
+/decl/hierarchy/mil_uniform/ec/com/capt //Can only be officers
+ name = "EC captain"
+ min_rank = 16
+
+ utility_hat = /obj/item/clothing/head/soft/solgov/expedition/co
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command/capt
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/captain
+
+/decl/hierarchy/mil_uniform/ec/com/adm //Can only be officers
+ name = "EC admiral"
+ min_rank = 18
+
+ utility_hat = /obj/item/clothing/head/soft/solgov/expedition/co
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command/adm
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/captain
+
+/decl/hierarchy/mil_uniform/ec/eng
+ name = "EC engineering"
+ //departments = ENG
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/engineering
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/engineering,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ // /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/eng)
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/engineering
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/engineering
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/engineering
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/engineering
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/engineering
+
+
+/decl/hierarchy/mil_uniform/ec/eng/senior
+ name = "EC engineering senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/eng/chief
+ name = "EC engineering chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/eng/officer
+ name = "EC engineering CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/engineering
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/engineering,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ // /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/eng)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/engineering
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/engineering
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/engineering/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/engineering
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/engineering
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/eng/officer/com //Can only be officers
+ name = "EC engineering command"
+ //departments = ENG|COM
+
+/decl/hierarchy/mil_uniform/ec/sec
+ name = "EC security"
+ //departments = SEC
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/security
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/security,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ /obj/item/clothing/gloves/thick/duty/solgov/sec)
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/security
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/security
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/security
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/security
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/security
+
+/decl/hierarchy/mil_uniform/ec/sec/senior
+ name = "EC security senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/sec/chief
+ name = "EC security chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/sec/officer
+ name = "EC security CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/security
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/security,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ // /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/sec)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/security
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/security
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/security/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/security
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/security
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/sec/officer/com //Can only be officers
+ name = "EC security command"
+ //departments = SEC|COM
+
+/decl/hierarchy/mil_uniform/ec/med
+ name = "EC medical"
+ //departments = MED
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/medical
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/medical,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ /obj/item/clothing/gloves/thick/duty/solgov/med)
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/medical
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/medical
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/medical
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/medical
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/medical
+
+/decl/hierarchy/mil_uniform/ec/med/senior
+ name = "EC medical senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/med/chief
+ name = "EC medical chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/med/officer
+ name = "EC medical CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/medical
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/medical,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ // /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/med)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/medical
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/medical
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/medical/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/medical
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/medical
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/med/officer/com //Can only be officers
+ name = "EC medical command"
+ //departments = MED|COM
+
+/decl/hierarchy/mil_uniform/ec/sup
+ name = "EC supply"
+ //departments = SUP
+
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/supply,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ /obj/item/clothing/gloves/thick/duty/solgov/sup)
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/supply
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/supply
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/supply
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/supply
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/supply
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/supply
+
+/decl/hierarchy/mil_uniform/ec/sup/senior
+ name = "EC supply senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/sup/chief
+ name = "EC supply chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/sup/officer
+ name = "EC supply CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/supply
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/supply,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+// /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/sup)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/supply
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/supply
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/supply
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/supply
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/srv
+ name = "EC service"
+// departments = SRV
+
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/service,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ /obj/item/clothing/gloves/thick/duty/solgov/svc)
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/service
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/service
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/service
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/service
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/service
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/service
+
+/decl/hierarchy/mil_uniform/ec/srv/senior
+ name = "EC service senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/srv/chief
+ name = "EC service chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/srv/officer
+ name = "EC service CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/service
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/service,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+// /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/svc)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/service
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/service
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/service/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/service
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/service
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/exp
+ name = "EC exploration"
+ //departments = EXP
+
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/exploration,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+ /obj/item/clothing/gloves/thick/duty/solgov/exp)
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/exploration
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/exploration
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/exploration
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/exploration
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/exploration
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/exploration
+
+/decl/hierarchy/mil_uniform/ec/exp/senior
+ name = "EC exploration senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/exp/chief
+ name = "EC exploration chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/exp/officer
+ name = "EC exploration CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/exploration
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/beret/solgov/expedition/exploration,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+// /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/exp)
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/exploration
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/exploration
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/exploration/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/exploration
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/exploration
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/spt
+ name = "EC command support"
+ //departments = SPT
+
+ utility_under= /obj/item/clothing/under/solgov/utility/expeditionary/command
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov,
+// /obj/item/clothing/shoes/jackboots/unathi,
+ /obj/item/clothing/gloves/thick/duty/solgov/cmd)
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/command
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/command
+
+/decl/hierarchy/mil_uniform/ec/spt/senior
+ name = "EC command support senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/spt/chief
+ name = "EC command support chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/spt/officer
+ name = "EC command support CO"
+ min_rank = 11
+
+ utility_under= /obj/item/clothing/under/solgov/utility/expeditionary/officer/command
+
+ service_under= /obj/item/clothing/under/solgov/service/expeditionary/command/command
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/command
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/command
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/sci
+ name = "EC science"
+ //departments = SCI
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/research
+ utility_extra = list(/obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov//,
+// /obj/item/clothing/suit/storage/toggle/labcoat/science/ec
+ )
+
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/research
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/research
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/research
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/research
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/skirt/research
+
+/decl/hierarchy/mil_uniform/ec/sci/senior
+ name = "EC science senior"
+ min_rank = 5
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/senior
+
+/decl/hierarchy/mil_uniform/ec/sci/chief
+ name = "EC science chief"
+ min_rank = 7
+
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/chief
+
+/decl/hierarchy/mil_uniform/ec/sci/officer
+ name = "EC science CO"
+ min_rank = 11
+
+ utility_under = /obj/item/clothing/under/solgov/utility/expeditionary/officer/research
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov//,
+// /obj/item/clothing/suit/storage/toggle/labcoat/science/ec
+ )
+
+ service_under = /obj/item/clothing/under/solgov/service/expeditionary/command/research
+ service_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/research
+ service_over = /obj/item/clothing/suit/storage/solgov/service/expeditionary/research/command
+ service_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+ dress_under = /obj/item/clothing/under/solgov/service/expeditionary/command/research
+ dress_skirt = /obj/item/clothing/under/solgov/service/expeditionary/command/skirt/research
+ dress_over = /obj/item/clothing/suit/storage/solgov/dress/expedition/command
+ dress_hat = /obj/item/clothing/head/solgov/service/expedition/command
+
+/decl/hierarchy/mil_uniform/ec/sci/officer/com //Can only be officers
+ name = "EC science command"
+ //departments = SCI|COM
+
+ utility_extra = list(/obj/item/clothing/head/beret/solgov/expedition/command,
+ /obj/item/clothing/head/ushanka/solgov,
+ /obj/item/clothing/suit/storage/hooded/wintercoat/solgov)//,
+// /obj/item/clothing/suit/storage/toggle/labcoat/science/ec,
+// /obj/item/clothing/suit/storage/toggle/labcoat/rd/ec)
\ No newline at end of file
diff --git a/maps/torch/datums/uniforms_iseo.dm b/maps/torch/datums/uniforms_iseo.dm
new file mode 100644
index 00000000000..412e9f7c06a
--- /dev/null
+++ b/maps/torch/datums/uniforms_iseo.dm
@@ -0,0 +1,73 @@
+//
+// ISEO Technician Outfits
+//
+
+/decl/hierarchy/mil_uniform/iseo/technician/engineering
+ name = "Engineering Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/engineering
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/engineering
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/engineering,
+ /obj/item/clothing/gloves/duty/eng)
+
+/decl/hierarchy/mil_uniform/iseo/technician/supply
+ name = "Supply Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/supply
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/supply
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/supply,
+ /obj/item/clothing/gloves/duty/sup)
+
+/decl/hierarchy/mil_uniform/iseo/technician/medical
+ name = "Medical Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/medical
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/medical
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/medical,
+ /obj/item/clothing/gloves/duty/med)
+
+/decl/hierarchy/mil_uniform/iseo/technician/service
+ name = "Service Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/service
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/service
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/service,
+ /obj/item/clothing/gloves/duty/srv)
+
+/decl/hierarchy/mil_uniform/iseo/technician/security
+ name = "Security Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/security
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/security
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/security,
+ /obj/item/clothing/gloves/duty/sec,
+ /obj/item/clothing/suit/storage/iseo/utility/security)
+
+/decl/hierarchy/mil_uniform/iseo/technician/exploration
+ name = "Exploration Technician"
+ utility_under = /obj/item/clothing/under/iseo/utility/exploration
+ utility_over = /obj/item/clothing/suit/storage/iseo/utility/science
+ utility_extra = list(/obj/item/clothing/head/iseo/beret/exploration,
+ /obj/item/clothing/gloves/duty/sci,
+ /obj/item/clothing/suit/storage/iseo/utility/science)
+
+/decl/hierarchy/mil_uniform/iseo/specialist
+
+ utility_under = /obj/item/clothing/under/iseo/utility/command
+
+ service_over = /obj/item/clothing/suit/storage/iseo/service/officer
+ service_skirt = /obj/item/clothing/under/iseo/service/skirt/officer
+ service_under = /obj/item/clothing/under/iseo/service/uniform/officer
+ service_hat = /obj/item/clothing/head/iseo/wheel_cap/command
+
+ dress_over = /obj/item/clothing/suit/iseo/dress/officer
+ dress_hat = /obj/item/clothing/head/iseo/wheel_cap/command
+ dress_extra = list(/obj/item/clothing/head/beret/iseo)
+
+/decl/hierarchy/mil_uniform/iseo/specialist/senior
+
+ service_over = /obj/item/clothing/suit/storage/iseo/service/command
+ service_skirt = /obj/item/clothing/under/iseo/service/skirt/command
+ service_under = /obj/item/clothing/under/iseo/service/uniform/command
+ service_hat = /obj/item/clothing/head/iseo/wheel_cap/command
+
+ dress_over = /obj/item/clothing/suit/iseo/dress/command
+ dress_hat = /obj/item/clothing/head/iseo/wheel_cap/command
+ dress_extra = list(/obj/item/clothing/head/beret/iseo)
+
+
diff --git a/maps/torch/game/antagonist/outsider/deathsquad.dm b/maps/torch/game/antagonist/outsider/deathsquad.dm
new file mode 100644
index 00000000000..c44496b5c81
--- /dev/null
+++ b/maps/torch/game/antagonist/outsider/deathsquad.dm
@@ -0,0 +1 @@
+/datum/antagonist/deathsquad/required_language = LANGUAGE_HUMAN_EURO
\ No newline at end of file
diff --git a/maps/torch/game/antagonist/outsider/ert.dm b/maps/torch/game/antagonist/outsider/ert.dm
new file mode 100644
index 00000000000..6fbf90c5178
--- /dev/null
+++ b/maps/torch/game/antagonist/outsider/ert.dm
@@ -0,0 +1 @@
+/datum/antagonist/ert/required_language = LANGUAGE_HUMAN_EURO
\ No newline at end of file
diff --git a/maps/torch/game/antagonist/outsider/foundation.dm b/maps/torch/game/antagonist/outsider/foundation.dm
new file mode 100644
index 00000000000..fbf892aaa15
--- /dev/null
+++ b/maps/torch/game/antagonist/outsider/foundation.dm
@@ -0,0 +1 @@
+/datum/antagonist/foundation/required_language = LANGUAGE_HUMAN_EURO
\ No newline at end of file
diff --git a/maps/torch/game/antagonist/outsider/mercenary.dm b/maps/torch/game/antagonist/outsider/mercenary.dm
new file mode 100644
index 00000000000..a79213d5691
--- /dev/null
+++ b/maps/torch/game/antagonist/outsider/mercenary.dm
@@ -0,0 +1 @@
+/datum/antagonist/mercenary/required_language = LANGUAGE_SPACER
\ No newline at end of file
diff --git a/maps/torch/game/antagonist/outsider/raider.dm b/maps/torch/game/antagonist/outsider/raider.dm
new file mode 100644
index 00000000000..230402e78df
--- /dev/null
+++ b/maps/torch/game/antagonist/outsider/raider.dm
@@ -0,0 +1 @@
+/datum/antagonist/raider/required_language = LANGUAGE_SPACER
\ No newline at end of file
diff --git a/maps/torch/icons/assignment_hud.dmi b/maps/torch/icons/assignment_hud.dmi
new file mode 100644
index 00000000000..5ec05698762
Binary files /dev/null and b/maps/torch/icons/assignment_hud.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/ace.dmi b/maps/torch/icons/borrowed_icons/pilot/ace.dmi
new file mode 100644
index 00000000000..56a5afefd76
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/ace.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/checker.dmi b/maps/torch/icons/borrowed_icons/pilot/checker.dmi
new file mode 100644
index 00000000000..8c9189e1013
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/checker.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/corvid.dmi b/maps/torch/icons/borrowed_icons/pilot/corvid.dmi
new file mode 100644
index 00000000000..a8a0f79464f
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/corvid.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/helmet.dmi b/maps/torch/icons/borrowed_icons/pilot/helmet.dmi
new file mode 100644
index 00000000000..dc5c1d6b593
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/helmet.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/luke.dmi b/maps/torch/icons/borrowed_icons/pilot/luke.dmi
new file mode 100644
index 00000000000..fa1a88f2ebe
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/luke.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/mobius.dmi b/maps/torch/icons/borrowed_icons/pilot/mobius.dmi
new file mode 100644
index 00000000000..51f455092f4
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/mobius.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/pilot_borrowed_readme.md b/maps/torch/icons/borrowed_icons/pilot/pilot_borrowed_readme.md
new file mode 100644
index 00000000000..c8c5e1cc2a9
--- /dev/null
+++ b/maps/torch/icons/borrowed_icons/pilot/pilot_borrowed_readme.md
@@ -0,0 +1,5 @@
+These sprites are borrowed from Shiptest.
+
+All credit to Apogee-dev
+
+https://github.com/shiptest-ss13/Shiptest/pull/455
\ No newline at end of file
diff --git a/maps/torch/icons/borrowed_icons/pilot/shark.dmi b/maps/torch/icons/borrowed_icons/pilot/shark.dmi
new file mode 100644
index 00000000000..9919f066eea
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/shark.dmi differ
diff --git a/maps/torch/icons/borrowed_icons/pilot/viper.dmi b/maps/torch/icons/borrowed_icons/pilot/viper.dmi
new file mode 100644
index 00000000000..f88239f7245
Binary files /dev/null and b/maps/torch/icons/borrowed_icons/pilot/viper.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/dept_stripe_espatier.dmi b/maps/torch/icons/converted_icons/accessories/dept_stripe_espatier.dmi
new file mode 100644
index 00000000000..82c75a742a1
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/dept_stripe_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/dept_stripe_iseo.dmi b/maps/torch/icons/converted_icons/accessories/dept_stripe_iseo.dmi
new file mode 100644
index 00000000000..a9af49f3da7
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/dept_stripe_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/iseo_jacket_tags.dmi b/maps/torch/icons/converted_icons/accessories/iseo_jacket_tags.dmi
new file mode 100644
index 00000000000..186f59faeda
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/iseo_jacket_tags.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/maa_badge.dmi b/maps/torch/icons/converted_icons/accessories/maa_badge.dmi
new file mode 100644
index 00000000000..d6c6f162b14
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/maa_badge.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/maa_band.dmi b/maps/torch/icons/converted_icons/accessories/maa_band.dmi
new file mode 100644
index 00000000000..f394d33127d
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/maa_band.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/medic_tag.dmi b/maps/torch/icons/converted_icons/accessories/medic_tag.dmi
new file mode 100644
index 00000000000..2ba255fad53
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/medic_tag.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/pin_specialist_iseo.dmi b/maps/torch/icons/converted_icons/accessories/pin_specialist_iseo.dmi
new file mode 100644
index 00000000000..aff45bef6a6
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/pin_specialist_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/pin_technician_iseo.dmi b/maps/torch/icons/converted_icons/accessories/pin_technician_iseo.dmi
new file mode 100644
index 00000000000..fbac0dafef8
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/pin_technician_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_command_espatier.dmi b/maps/torch/icons/converted_icons/accessories/rank_command_espatier.dmi
new file mode 100644
index 00000000000..9811d3ac405
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_command_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_command_iseo.dmi b/maps/torch/icons/converted_icons/accessories/rank_command_iseo.dmi
new file mode 100644
index 00000000000..016968ab6a2
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_enlisted_espatier.dmi b/maps/torch/icons/converted_icons/accessories/rank_enlisted_espatier.dmi
new file mode 100644
index 00000000000..105e3a7e02b
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_enlisted_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_officer_espatier.dmi b/maps/torch/icons/converted_icons/accessories/rank_officer_espatier.dmi
new file mode 100644
index 00000000000..84589d281c8
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_officer_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_specialist_iseo.dmi b/maps/torch/icons/converted_icons/accessories/rank_specialist_iseo.dmi
new file mode 100644
index 00000000000..f6cb76ff127
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_specialist_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/rank_technician_iseo.dmi b/maps/torch/icons/converted_icons/accessories/rank_technician_iseo.dmi
new file mode 100644
index 00000000000..daade6e4c4f
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/rank_technician_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/security_tag.dmi b/maps/torch/icons/converted_icons/accessories/security_tag.dmi
new file mode 100644
index 00000000000..d2ffdcf548c
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/security_tag.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/service_jacket_tags_command_espatier.dmi b/maps/torch/icons/converted_icons/accessories/service_jacket_tags_command_espatier.dmi
new file mode 100644
index 00000000000..8da384cadea
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/service_jacket_tags_command_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/service_jacket_tags_espatier.dmi b/maps/torch/icons/converted_icons/accessories/service_jacket_tags_espatier.dmi
new file mode 100644
index 00000000000..7b9603be00e
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/service_jacket_tags_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_botany.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_botany.dmi
new file mode 100644
index 00000000000..1dc307879a6
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_botany.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_electric.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_electric.dmi
new file mode 100644
index 00000000000..2816143aa95
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_electric.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_eva.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_eva.dmi
new file mode 100644
index 00000000000..58e584876f6
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_eva.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_exosuit.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_exosuit.dmi
new file mode 100644
index 00000000000..4914f4bae75
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_exosuit.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_firstaid.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_firstaid.dmi
new file mode 100644
index 00000000000..dc6f4a731e6
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_firstaid.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_netgun.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_netgun.dmi
new file mode 100644
index 00000000000..750bde138d0
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_netgun.dmi differ
diff --git a/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_science.dmi b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_science.dmi
new file mode 100644
index 00000000000..dee2bd6732f
Binary files /dev/null and b/maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_science.dmi differ
diff --git a/maps/torch/icons/converted_icons/armor/armor.dmi b/maps/torch/icons/converted_icons/armor/armor.dmi
new file mode 100644
index 00000000000..27c201908ef
Binary files /dev/null and b/maps/torch/icons/converted_icons/armor/armor.dmi differ
diff --git a/maps/torch/icons/converted_icons/armor/armor_command.dmi b/maps/torch/icons/converted_icons/armor/armor_command.dmi
new file mode 100644
index 00000000000..9d2a6f65193
Binary files /dev/null and b/maps/torch/icons/converted_icons/armor/armor_command.dmi differ
diff --git a/maps/torch/icons/converted_icons/armor/armor_peacekeeper.dmi b/maps/torch/icons/converted_icons/armor/armor_peacekeeper.dmi
new file mode 100644
index 00000000000..a6420f4b4b9
Binary files /dev/null and b/maps/torch/icons/converted_icons/armor/armor_peacekeeper.dmi differ
diff --git a/maps/torch/icons/converted_icons/armor/armor_sec.dmi b/maps/torch/icons/converted_icons/armor/armor_sec.dmi
new file mode 100644
index 00000000000..35085af7f70
Binary files /dev/null and b/maps/torch/icons/converted_icons/armor/armor_sec.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_command.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_command.dmi
new file mode 100644
index 00000000000..714caaa8c24
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_command.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_engineering.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_engineering.dmi
new file mode 100644
index 00000000000..43ff851f9c5
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_engineering.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_medical.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_medical.dmi
new file mode 100644
index 00000000000..91dcf9b6691
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_medical.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_science.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_science.dmi
new file mode 100644
index 00000000000..563591139cf
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_science.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_security.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_security.dmi
new file mode 100644
index 00000000000..2221c230893
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_security.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_service.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_service.dmi
new file mode 100644
index 00000000000..cb553d3f872
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_service.dmi differ
diff --git a/maps/torch/icons/converted_icons/gloves/duty_gloves_supply.dmi b/maps/torch/icons/converted_icons/gloves/duty_gloves_supply.dmi
new file mode 100644
index 00000000000..209ec83dd34
Binary files /dev/null and b/maps/torch/icons/converted_icons/gloves/duty_gloves_supply.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_command_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_command_espatier.dmi
new file mode 100644
index 00000000000..43272885219
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_command_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_command_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_command_iseo.dmi
new file mode 100644
index 00000000000..74e95479d7c
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_engineering_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_engineering_espatier.dmi
new file mode 100644
index 00000000000..d5baf716fe7
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_engineering_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_engineering_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_engineering_iseo.dmi
new file mode 100644
index 00000000000..807c3e15f32
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_engineering_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_espatier.dmi
new file mode 100644
index 00000000000..deb4ca6a38c
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_exploration_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_exploration_espatier.dmi
new file mode 100644
index 00000000000..7465fae3a5f
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_exploration_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_exploration_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_exploration_iseo.dmi
new file mode 100644
index 00000000000..f86be551976
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_exploration_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_iseo.dmi
new file mode 100644
index 00000000000..15b41e83e17
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_medical_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_medical_espatier.dmi
new file mode 100644
index 00000000000..c0c20f7f5a2
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_medical_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_medical_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_medical_iseo.dmi
new file mode 100644
index 00000000000..2608b705406
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_medical_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_security_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_security_espatier.dmi
new file mode 100644
index 00000000000..492a4a99dcb
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_security_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_security_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_security_iseo.dmi
new file mode 100644
index 00000000000..a644aafe542
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_security_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_service_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_service_espatier.dmi
new file mode 100644
index 00000000000..f15bb3e83ef
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_service_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_service_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_service_iseo.dmi
new file mode 100644
index 00000000000..908d7cba558
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_service_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_supply_espatier.dmi b/maps/torch/icons/converted_icons/head/berets/beret_supply_espatier.dmi
new file mode 100644
index 00000000000..3792fe8c2ca
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_supply_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/berets/beret_supply_iseo.dmi b/maps/torch/icons/converted_icons/head/berets/beret_supply_iseo.dmi
new file mode 100644
index 00000000000..88d62b78e1a
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/berets/beret_supply_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/garrison_cap_command_espatier.dmi b/maps/torch/icons/converted_icons/head/garrison_cap_command_espatier.dmi
new file mode 100644
index 00000000000..dc1c73fd546
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/garrison_cap_command_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/garrison_cap_espatier.dmi b/maps/torch/icons/converted_icons/head/garrison_cap_espatier.dmi
new file mode 100644
index 00000000000..3defff65d99
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/garrison_cap_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/garrison_cap_iseo.dmi b/maps/torch/icons/converted_icons/head/garrison_cap_iseo.dmi
new file mode 100644
index 00000000000..507fc8ea367
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/garrison_cap_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/helmet_command.dmi b/maps/torch/icons/converted_icons/head/helmet_command.dmi
new file mode 100644
index 00000000000..0419b341d6f
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/helmet_command.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/helmet_security.dmi b/maps/torch/icons/converted_icons/head/helmet_security.dmi
new file mode 100644
index 00000000000..87724561725
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/helmet_security.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/peak_cap_command_iseo.dmi b/maps/torch/icons/converted_icons/head/peak_cap_command_iseo.dmi
new file mode 100644
index 00000000000..6e5f7fae258
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/peak_cap_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/peak_cap_iseo.dmi b/maps/torch/icons/converted_icons/head/peak_cap_iseo.dmi
new file mode 100644
index 00000000000..bd802895a22
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/peak_cap_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/pilot_helmet.dmi b/maps/torch/icons/converted_icons/head/pilot_helmet.dmi
new file mode 100644
index 00000000000..d009ee168ce
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/pilot_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/utility_cap_green_espatier.dmi b/maps/torch/icons/converted_icons/head/utility_cap_green_espatier.dmi
new file mode 100644
index 00000000000..f041c1bc16c
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/utility_cap_green_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/utility_cap_grey_espatier.dmi b/maps/torch/icons/converted_icons/head/utility_cap_grey_espatier.dmi
new file mode 100644
index 00000000000..a101a9f78d7
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/utility_cap_grey_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/utility_cap_iseo.dmi b/maps/torch/icons/converted_icons/head/utility_cap_iseo.dmi
new file mode 100644
index 00000000000..bd43af53bbb
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/utility_cap_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/utility_cap_tan_espatier.dmi b/maps/torch/icons/converted_icons/head/utility_cap_tan_espatier.dmi
new file mode 100644
index 00000000000..2151b8bef04
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/utility_cap_tan_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/wheel_cap_command_espatier.dmi b/maps/torch/icons/converted_icons/head/wheel_cap_command_espatier.dmi
new file mode 100644
index 00000000000..2cf9bdba962
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/wheel_cap_command_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/wheel_cap_command_iseo.dmi b/maps/torch/icons/converted_icons/head/wheel_cap_command_iseo.dmi
new file mode 100644
index 00000000000..dc9519eca88
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/wheel_cap_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/wheel_cap_espatier.dmi b/maps/torch/icons/converted_icons/head/wheel_cap_espatier.dmi
new file mode 100644
index 00000000000..783cf1ad76d
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/wheel_cap_espatier.dmi differ
diff --git a/maps/torch/icons/converted_icons/head/wheel_cap_iseo.dmi b/maps/torch/icons/converted_icons/head/wheel_cap_iseo.dmi
new file mode 100644
index 00000000000..8a043222edf
Binary files /dev/null and b/maps/torch/icons/converted_icons/head/wheel_cap_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black.dmi b/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black.dmi
new file mode 100644
index 00000000000..7b6bfeb9eda
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black_helmet.dmi
new file mode 100644
index 00000000000..e83075a34c4
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/atmos_hardsuit_black_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/command_voidsuit.dmi b/maps/torch/icons/converted_icons/spacesuits/command_voidsuit.dmi
new file mode 100644
index 00000000000..ea738cb21af
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/command_voidsuit.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/command_voidsuit_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/command_voidsuit_helmet.dmi
new file mode 100644
index 00000000000..7559b3be8af
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/command_voidsuit_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black.dmi b/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black.dmi
new file mode 100644
index 00000000000..0385ca7ec0f
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black_helmet.dmi
new file mode 100644
index 00000000000..df27b25b6d9
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/eng_hardsuit_black_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit.dmi b/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit.dmi
new file mode 100644
index 00000000000..246b170ed59
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit_helmet.dmi
new file mode 100644
index 00000000000..49f670c34eb
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit.dmi b/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit.dmi
new file mode 100644
index 00000000000..9e4730b4426
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit_helmet.dmi
new file mode 100644
index 00000000000..09f65a46456
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/explo_voidsuit_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/master.dmi b/maps/torch/icons/converted_icons/spacesuits/master.dmi
new file mode 100644
index 00000000000..1ce5e2c57e4
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/master.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt.dmi b/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt.dmi
new file mode 100644
index 00000000000..33c45c110a0
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt_helmet.dmi
new file mode 100644
index 00000000000..1e05f1963f2
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/medical_voidsuit_alt_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt.dmi b/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt.dmi
new file mode 100644
index 00000000000..b56e19e1a08
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt_helmet.dmi b/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt_helmet.dmi
new file mode 100644
index 00000000000..08ee0d57627
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/pilot_voidsuit_alt_helmet.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/readme-sprites.md b/maps/torch/icons/converted_icons/spacesuits/readme-sprites.md
new file mode 100644
index 00000000000..695cc5a3b61
--- /dev/null
+++ b/maps/torch/icons/converted_icons/spacesuits/readme-sprites.md
@@ -0,0 +1,3 @@
+The following files in this folder and subfolder(s) contain sprites from Azlan / https://github.com/SomeAngryMiner - all credit attributed to them.
+
+Original PR: https://github.com/Baystation12/Baystation12/pull/30821
\ No newline at end of file
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/cmo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/cmo_rig.dmi
new file mode 100644
index 00000000000..5cd58e87331
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/cmo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/co_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/co_rig.dmi
new file mode 100644
index 00000000000..fcae0837be1
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/co_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/command_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/command_rig.dmi
new file mode 100644
index 00000000000..15367ab8e2f
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/command_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/cso_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/cso_rig.dmi
new file mode 100644
index 00000000000..14c6f7e66fa
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/cso_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/explo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/explo_rig.dmi
new file mode 100644
index 00000000000..ddcd52d7ed8
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/explo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/hos_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/hos_rig.dmi
new file mode 100644
index 00000000000..a38871914ab
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/hos_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/body/xo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/body/xo_rig.dmi
new file mode 100644
index 00000000000..a98cb2f57c2
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/body/xo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/boots/command_rigs.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/boots/command_rigs.dmi
new file mode 100644
index 00000000000..d0ede519556
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/boots/command_rigs.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/boots/explo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/boots/explo_rig.dmi
new file mode 100644
index 00000000000..e89502a9c93
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/boots/explo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/hands/command_rigs.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/hands/command_rigs.dmi
new file mode 100644
index 00000000000..df61bb6c5bf
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/hands/command_rigs.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/hands/explo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/hands/explo_rig.dmi
new file mode 100644
index 00000000000..8544fad64fe
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/hands/explo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/cmo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/cmo_rig.dmi
new file mode 100644
index 00000000000..7e1f9f9e82d
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/cmo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/co_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/co_rig.dmi
new file mode 100644
index 00000000000..e8913a3fbe4
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/co_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/command_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/command_rig.dmi
new file mode 100644
index 00000000000..5cf8d07b813
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/command_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/cso_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/cso_rig.dmi
new file mode 100644
index 00000000000..d68d5e8197f
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/cso_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/explo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/explo_rig.dmi
new file mode 100644
index 00000000000..eb2c5cc8354
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/explo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/hos_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/hos_rig.dmi
new file mode 100644
index 00000000000..7ff3659331b
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/hos_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/head/xo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/head/xo_rig.dmi
new file mode 100644
index 00000000000..cd8663b3bab
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/head/xo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/cmo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/cmo_rig.dmi
new file mode 100644
index 00000000000..888bcf6e3cd
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/cmo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/co_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/co_rig.dmi
new file mode 100644
index 00000000000..b0d9f48a9f8
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/co_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/command_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/command_rig.dmi
new file mode 100644
index 00000000000..04e74411fc5
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/command_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/cso_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/cso_rig.dmi
new file mode 100644
index 00000000000..053ced38f30
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/cso_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/explo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/explo_rig.dmi
new file mode 100644
index 00000000000..a568c3cb048
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/explo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/hos_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/hos_rig.dmi
new file mode 100644
index 00000000000..52aa8cd3a00
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/hos_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/spacesuits/rigs/module/xo_rig.dmi b/maps/torch/icons/converted_icons/spacesuits/rigs/module/xo_rig.dmi
new file mode 100644
index 00000000000..e619533ded7
Binary files /dev/null and b/maps/torch/icons/converted_icons/spacesuits/rigs/module/xo_rig.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/iseo_jacket.dmi b/maps/torch/icons/converted_icons/suits/iseo_jacket.dmi
new file mode 100644
index 00000000000..c58c9dd1313
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/iseo_jacket.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_command_espatiers.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_command_espatiers.dmi
new file mode 100644
index 00000000000..9b6b6d2372c
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_command_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_command_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_command_iseo.dmi
new file mode 100644
index 00000000000..7c3c994c0c7
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_espatiers.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_espatiers.dmi
new file mode 100644
index 00000000000..5c8b44394ee
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_flag_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_flag_iseo.dmi
new file mode 100644
index 00000000000..7791d5b8fc7
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_flag_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_iseo.dmi
new file mode 100644
index 00000000000..ea1251e0419
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_dress_officer_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_dress_officer_iseo.dmi
new file mode 100644
index 00000000000..c475a3b0fc1
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_dress_officer_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_service_command_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_service_command_iseo.dmi
new file mode 100644
index 00000000000..d1154301a0d
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_service_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_service_espatiers.dmi b/maps/torch/icons/converted_icons/suits/suit_service_espatiers.dmi
new file mode 100644
index 00000000000..d91add029de
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_service_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_service_flag_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_service_flag_iseo.dmi
new file mode 100644
index 00000000000..94bd0f240c2
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_service_flag_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_service_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_service_iseo.dmi
new file mode 100644
index 00000000000..980e8b63f56
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_service_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/suits/suit_service_officer_iseo.dmi b/maps/torch/icons/converted_icons/suits/suit_service_officer_iseo.dmi
new file mode 100644
index 00000000000..982be3396bb
Binary files /dev/null and b/maps/torch/icons/converted_icons/suits/suit_service_officer_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_dress_skirt_command_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_dress_skirt_command_espatiers.dmi
new file mode 100644
index 00000000000..1442ea7015a
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_dress_skirt_command_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_dress_skirt_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_dress_skirt_espatiers.dmi
new file mode 100644
index 00000000000..cdb87449253
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_dress_skirt_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_dress_uniform_command_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_dress_uniform_command_espatiers.dmi
new file mode 100644
index 00000000000..1442ea7015a
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_dress_uniform_command_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_dress_uniform_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_dress_uniform_espatiers.dmi
new file mode 100644
index 00000000000..db05dd645e6
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_dress_uniform_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_pt_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_pt_espatiers.dmi
new file mode 100644
index 00000000000..7503c2d1ed3
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_pt_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_pt_iseo.dmi b/maps/torch/icons/converted_icons/under/under_pt_iseo.dmi
new file mode 100644
index 00000000000..5e917de7c44
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_pt_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_command_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_command_espatiers.dmi
new file mode 100644
index 00000000000..cad3435ca6a
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_command_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_command_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_command_iseo.dmi
new file mode 100644
index 00000000000..6fb190c16ea
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_espatiers.dmi
new file mode 100644
index 00000000000..be2ab32dd0d
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_flag_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_flag_iseo.dmi
new file mode 100644
index 00000000000..8e9be722433
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_flag_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_iseo.dmi
new file mode 100644
index 00000000000..3ae7aa626a6
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_skirt_officer_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_skirt_officer_iseo.dmi
new file mode 100644
index 00000000000..ebca31f962c
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_skirt_officer_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_command_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_command_espatiers.dmi
new file mode 100644
index 00000000000..6679c1b6df8
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_command_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_command_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_command_iseo.dmi
new file mode 100644
index 00000000000..c6a7b57b6ba
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_espatiers.dmi
new file mode 100644
index 00000000000..f868545641a
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_flag_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_flag_iseo.dmi
new file mode 100644
index 00000000000..abf388f0a51
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_flag_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_iseo.dmi
new file mode 100644
index 00000000000..8577641b1ff
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_service_uniform_officer_iseo.dmi b/maps/torch/icons/converted_icons/under/under_service_uniform_officer_iseo.dmi
new file mode 100644
index 00000000000..56ad39ced69
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_service_uniform_officer_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_alt_2_iseo.dmi b/maps/torch/icons/converted_icons/under/under_utility_alt_2_iseo.dmi
new file mode 100644
index 00000000000..dccaa90d768
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_alt_2_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_command_iseo.dmi b/maps/torch/icons/converted_icons/under/under_utility_command_iseo.dmi
new file mode 100644
index 00000000000..b7144f23784
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_command_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_green_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_utility_green_espatiers.dmi
new file mode 100644
index 00000000000..b134ec2b11d
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_green_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_grey_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_utility_grey_espatiers.dmi
new file mode 100644
index 00000000000..75873e60c56
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_grey_espatiers.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_iseo.dmi b/maps/torch/icons/converted_icons/under/under_utility_iseo.dmi
new file mode 100644
index 00000000000..56a663231f0
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_iseo.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_iseo_command.dmi b/maps/torch/icons/converted_icons/under/under_utility_iseo_command.dmi
new file mode 100644
index 00000000000..1de554a9a6c
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_iseo_command.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_iseo_medical.dmi b/maps/torch/icons/converted_icons/under/under_utility_iseo_medical.dmi
new file mode 100644
index 00000000000..e2cf6943972
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_iseo_medical.dmi differ
diff --git a/maps/torch/icons/converted_icons/under/under_utility_tan_espatiers.dmi b/maps/torch/icons/converted_icons/under/under_utility_tan_espatiers.dmi
new file mode 100644
index 00000000000..12081b17774
Binary files /dev/null and b/maps/torch/icons/converted_icons/under/under_utility_tan_espatiers.dmi differ
diff --git a/maps/torch/icons/hangar_door_turf.dmi b/maps/torch/icons/hangar_door_turf.dmi
new file mode 100644
index 00000000000..e68e8e2b8c6
Binary files /dev/null and b/maps/torch/icons/hangar_door_turf.dmi differ
diff --git a/maps/torch/icons/mob/onmob_accessories_solgov.dmi b/maps/torch/icons/mob/onmob_accessories_solgov.dmi
new file mode 100644
index 00000000000..5fc0870f7b8
Binary files /dev/null and b/maps/torch/icons/mob/onmob_accessories_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_accessories_terran.dmi b/maps/torch/icons/mob/onmob_accessories_terran.dmi
new file mode 100644
index 00000000000..75c0aa36c3e
Binary files /dev/null and b/maps/torch/icons/mob/onmob_accessories_terran.dmi differ
diff --git a/maps/torch/icons/mob/onmob_feet_solgov.dmi b/maps/torch/icons/mob/onmob_feet_solgov.dmi
new file mode 100644
index 00000000000..18a830bde35
Binary files /dev/null and b/maps/torch/icons/mob/onmob_feet_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_hands_solgov.dmi b/maps/torch/icons/mob/onmob_hands_solgov.dmi
new file mode 100644
index 00000000000..b81ea89d5cf
Binary files /dev/null and b/maps/torch/icons/mob/onmob_hands_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_head_solgov.dmi b/maps/torch/icons/mob/onmob_head_solgov.dmi
new file mode 100644
index 00000000000..2ba3e91c640
Binary files /dev/null and b/maps/torch/icons/mob/onmob_head_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_head_terran.dmi b/maps/torch/icons/mob/onmob_head_terran.dmi
new file mode 100644
index 00000000000..14bc9d0eae2
Binary files /dev/null and b/maps/torch/icons/mob/onmob_head_terran.dmi differ
diff --git a/maps/torch/icons/mob/onmob_suit_solgov.dmi b/maps/torch/icons/mob/onmob_suit_solgov.dmi
new file mode 100644
index 00000000000..4d0f442571b
Binary files /dev/null and b/maps/torch/icons/mob/onmob_suit_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_suit_terran.dmi b/maps/torch/icons/mob/onmob_suit_terran.dmi
new file mode 100644
index 00000000000..05a25993f29
Binary files /dev/null and b/maps/torch/icons/mob/onmob_suit_terran.dmi differ
diff --git a/maps/torch/icons/mob/onmob_under_solgov.dmi b/maps/torch/icons/mob/onmob_under_solgov.dmi
new file mode 100644
index 00000000000..2762f2b4186
Binary files /dev/null and b/maps/torch/icons/mob/onmob_under_solgov.dmi differ
diff --git a/maps/torch/icons/mob/onmob_under_terran.dmi b/maps/torch/icons/mob/onmob_under_terran.dmi
new file mode 100644
index 00000000000..df2bba7ed5c
Binary files /dev/null and b/maps/torch/icons/mob/onmob_under_terran.dmi differ
diff --git a/maps/torch/icons/mob/skrell/onmob_head_solgov_skrell.dmi b/maps/torch/icons/mob/skrell/onmob_head_solgov_skrell.dmi
new file mode 100644
index 00000000000..4a839a0d026
Binary files /dev/null and b/maps/torch/icons/mob/skrell/onmob_head_solgov_skrell.dmi differ
diff --git a/maps/torch/icons/mob/skrell/onmob_suit_solgov_skrell.dmi b/maps/torch/icons/mob/skrell/onmob_suit_solgov_skrell.dmi
new file mode 100644
index 00000000000..65a5b7d589f
Binary files /dev/null and b/maps/torch/icons/mob/skrell/onmob_suit_solgov_skrell.dmi differ
diff --git a/maps/torch/icons/mob/unathi/onmob_head_solgov_unathi.dmi b/maps/torch/icons/mob/unathi/onmob_head_solgov_unathi.dmi
new file mode 100644
index 00000000000..83771b5c527
Binary files /dev/null and b/maps/torch/icons/mob/unathi/onmob_head_solgov_unathi.dmi differ
diff --git a/maps/torch/icons/mob/unathi/onmob_suit_solgov_unathi.dmi b/maps/torch/icons/mob/unathi/onmob_suit_solgov_unathi.dmi
new file mode 100644
index 00000000000..5ec3b38cd2f
Binary files /dev/null and b/maps/torch/icons/mob/unathi/onmob_suit_solgov_unathi.dmi differ
diff --git a/maps/torch/icons/obj/carbine.dmi b/maps/torch/icons/obj/carbine.dmi
new file mode 100644
index 00000000000..39684adb036
Binary files /dev/null and b/maps/torch/icons/obj/carbine.dmi differ
diff --git a/maps/torch/icons/obj/explshotgun.dmi b/maps/torch/icons/obj/explshotgun.dmi
new file mode 100644
index 00000000000..59aebdfe972
Binary files /dev/null and b/maps/torch/icons/obj/explshotgun.dmi differ
diff --git a/maps/torch/icons/obj/fission_core.dmi b/maps/torch/icons/obj/fission_core.dmi
new file mode 100644
index 00000000000..709a79de095
Binary files /dev/null and b/maps/torch/icons/obj/fission_core.dmi differ
diff --git a/maps/torch/icons/obj/guns/carbine.dmi b/maps/torch/icons/obj/guns/carbine.dmi
new file mode 100644
index 00000000000..39684adb036
Binary files /dev/null and b/maps/torch/icons/obj/guns/carbine.dmi differ
diff --git a/maps/torch/icons/obj/guns/secure_pistol.dmi b/maps/torch/icons/obj/guns/secure_pistol.dmi
new file mode 100644
index 00000000000..cff0268c7df
Binary files /dev/null and b/maps/torch/icons/obj/guns/secure_pistol.dmi differ
diff --git a/maps/torch/icons/obj/guns/taser_carbine.dmi b/maps/torch/icons/obj/guns/taser_carbine.dmi
new file mode 100644
index 00000000000..38a56d4ba70
Binary files /dev/null and b/maps/torch/icons/obj/guns/taser_carbine.dmi differ
diff --git a/maps/torch/icons/obj/iseo-decals.dmi b/maps/torch/icons/obj/iseo-decals.dmi
new file mode 100644
index 00000000000..3a83d868a91
Binary files /dev/null and b/maps/torch/icons/obj/iseo-decals.dmi differ
diff --git a/maps/torch/icons/obj/iseo_floor.dmi b/maps/torch/icons/obj/iseo_floor.dmi
new file mode 100644
index 00000000000..ebf79db8309
Binary files /dev/null and b/maps/torch/icons/obj/iseo_floor.dmi differ
diff --git a/maps/torch/icons/obj/lectern.dmi b/maps/torch/icons/obj/lectern.dmi
new file mode 100644
index 00000000000..605526e562c
Binary files /dev/null and b/maps/torch/icons/obj/lectern.dmi differ
diff --git a/maps/torch/icons/obj/obj_accessories_solgov.dmi b/maps/torch/icons/obj/obj_accessories_solgov.dmi
new file mode 100644
index 00000000000..e80b2b92789
Binary files /dev/null and b/maps/torch/icons/obj/obj_accessories_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_accessories_terran.dmi b/maps/torch/icons/obj/obj_accessories_terran.dmi
new file mode 100644
index 00000000000..2ee1f92f015
Binary files /dev/null and b/maps/torch/icons/obj/obj_accessories_terran.dmi differ
diff --git a/maps/torch/icons/obj/obj_feet_solgov.dmi b/maps/torch/icons/obj/obj_feet_solgov.dmi
new file mode 100644
index 00000000000..d9d88aa7c3e
Binary files /dev/null and b/maps/torch/icons/obj/obj_feet_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_hands_solgov.dmi b/maps/torch/icons/obj/obj_hands_solgov.dmi
new file mode 100644
index 00000000000..d0813dae865
Binary files /dev/null and b/maps/torch/icons/obj/obj_hands_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_head_solgov.dmi b/maps/torch/icons/obj/obj_head_solgov.dmi
new file mode 100644
index 00000000000..08b9d02adde
Binary files /dev/null and b/maps/torch/icons/obj/obj_head_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_head_terran.dmi b/maps/torch/icons/obj/obj_head_terran.dmi
new file mode 100644
index 00000000000..9549e1da32e
Binary files /dev/null and b/maps/torch/icons/obj/obj_head_terran.dmi differ
diff --git a/maps/torch/icons/obj/obj_suit_solgov.dmi b/maps/torch/icons/obj/obj_suit_solgov.dmi
new file mode 100644
index 00000000000..a91b3255cc9
Binary files /dev/null and b/maps/torch/icons/obj/obj_suit_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_suit_terran.dmi b/maps/torch/icons/obj/obj_suit_terran.dmi
new file mode 100644
index 00000000000..4f8b80c6547
Binary files /dev/null and b/maps/torch/icons/obj/obj_suit_terran.dmi differ
diff --git a/maps/torch/icons/obj/obj_under_solgov.dmi b/maps/torch/icons/obj/obj_under_solgov.dmi
new file mode 100644
index 00000000000..17ec7a63aab
Binary files /dev/null and b/maps/torch/icons/obj/obj_under_solgov.dmi differ
diff --git a/maps/torch/icons/obj/obj_under_terran.dmi b/maps/torch/icons/obj/obj_under_terran.dmi
new file mode 100644
index 00000000000..596faa7725e
Binary files /dev/null and b/maps/torch/icons/obj/obj_under_terran.dmi differ
diff --git a/maps/torch/icons/obj/skrell/obj_head_solgov_skrell.dmi b/maps/torch/icons/obj/skrell/obj_head_solgov_skrell.dmi
new file mode 100644
index 00000000000..9735f997bac
Binary files /dev/null and b/maps/torch/icons/obj/skrell/obj_head_solgov_skrell.dmi differ
diff --git a/maps/torch/icons/obj/skrell/obj_suit_solgov_skrell.dmi b/maps/torch/icons/obj/skrell/obj_suit_solgov_skrell.dmi
new file mode 100644
index 00000000000..eacb2e0c506
Binary files /dev/null and b/maps/torch/icons/obj/skrell/obj_suit_solgov_skrell.dmi differ
diff --git a/maps/torch/icons/obj/solbanner.dmi b/maps/torch/icons/obj/solbanner.dmi
new file mode 100644
index 00000000000..c81bd60a8d3
Binary files /dev/null and b/maps/torch/icons/obj/solbanner.dmi differ
diff --git a/maps/torch/icons/obj/solgov-decals.dmi b/maps/torch/icons/obj/solgov-decals.dmi
new file mode 100644
index 00000000000..464b4a56397
Binary files /dev/null and b/maps/torch/icons/obj/solgov-decals.dmi differ
diff --git a/maps/torch/icons/obj/solgov_floor.dmi b/maps/torch/icons/obj/solgov_floor.dmi
new file mode 100644
index 00000000000..c7cd8dd0c60
Binary files /dev/null and b/maps/torch/icons/obj/solgov_floor.dmi differ
diff --git a/maps/torch/icons/obj/unathi/obj_head_solgov_unathi.dmi b/maps/torch/icons/obj/unathi/obj_head_solgov_unathi.dmi
new file mode 100644
index 00000000000..7d5c56a7676
Binary files /dev/null and b/maps/torch/icons/obj/unathi/obj_head_solgov_unathi.dmi differ
diff --git a/maps/torch/icons/obj/unathi/obj_suit_solgov_unathi.dmi b/maps/torch/icons/obj/unathi/obj_suit_solgov_unathi.dmi
new file mode 100644
index 00000000000..f73bd4d90a5
Binary files /dev/null and b/maps/torch/icons/obj/unathi/obj_suit_solgov_unathi.dmi differ
diff --git a/maps/torch/icons/obj/uniques.dmi b/maps/torch/icons/obj/uniques.dmi
new file mode 100644
index 00000000000..dc503b04e76
Binary files /dev/null and b/maps/torch/icons/obj/uniques.dmi differ
diff --git a/maps/torch/icons/original_icons/skinsuit/helmet.dmi b/maps/torch/icons/original_icons/skinsuit/helmet.dmi
new file mode 100644
index 00000000000..dfa2b489e74
Binary files /dev/null and b/maps/torch/icons/original_icons/skinsuit/helmet.dmi differ
diff --git a/maps/torch/icons/original_icons/skinsuit/suit.dmi b/maps/torch/icons/original_icons/skinsuit/suit.dmi
new file mode 100644
index 00000000000..e3f7af05efa
Binary files /dev/null and b/maps/torch/icons/original_icons/skinsuit/suit.dmi differ
diff --git a/maps/torch/icons/original_icons/suit_locker/suit_locker.dmi b/maps/torch/icons/original_icons/suit_locker/suit_locker.dmi
new file mode 100644
index 00000000000..ab295a7e2e3
Binary files /dev/null and b/maps/torch/icons/original_icons/suit_locker/suit_locker.dmi differ
diff --git a/maps/torch/icons/original_icons/suit_locker/suit_locker_decals.dmi b/maps/torch/icons/original_icons/suit_locker/suit_locker_decals.dmi
new file mode 100644
index 00000000000..6a98ab7a6d0
Binary files /dev/null and b/maps/torch/icons/original_icons/suit_locker/suit_locker_decals.dmi differ
diff --git a/maps/torch/icons/security_state.dmi b/maps/torch/icons/security_state.dmi
new file mode 100644
index 00000000000..d471a0557c1
Binary files /dev/null and b/maps/torch/icons/security_state.dmi differ
diff --git a/maps/torch/icons/unsorted_missing/messenger_tox.dmi b/maps/torch/icons/unsorted_missing/messenger_tox.dmi
new file mode 100644
index 00000000000..3b0c06e8288
Binary files /dev/null and b/maps/torch/icons/unsorted_missing/messenger_tox.dmi differ
diff --git a/maps/torch/icons/unsorted_missing/satchel_tox.dmi b/maps/torch/icons/unsorted_missing/satchel_tox.dmi
new file mode 100644
index 00000000000..3028c2c8e01
Binary files /dev/null and b/maps/torch/icons/unsorted_missing/satchel_tox.dmi differ
diff --git a/maps/torch/icons/unsorted_missing/vest_white.dmi b/maps/torch/icons/unsorted_missing/vest_white.dmi
new file mode 100644
index 00000000000..ef085b5c373
Binary files /dev/null and b/maps/torch/icons/unsorted_missing/vest_white.dmi differ
diff --git a/maps/torch/items/cards_ids.dm b/maps/torch/items/cards_ids.dm
new file mode 100644
index 00000000000..3fc0f453b14
--- /dev/null
+++ b/maps/torch/items/cards_ids.dm
@@ -0,0 +1,156 @@
+//Torch ID Cards (they have to be here to make the outfits work, no way around it)
+
+/obj/item/card/id/torch
+ name = "identification card"
+ desc = "An identification card issued to personnel aboard the ISEO Endeavour."
+
+/obj/item/card/id/torch/silver
+ desc = "A silver identification card belonging to heads of staff."
+ item_state = "silver_id"
+ extra_details = list("goldstripe")
+ color = "#ccecff"
+
+/obj/item/card/id/torch/gold
+ desc = "A golden identification card belonging to the Commanding Officer."
+ item_state = "gold_id"
+ color = "#d4c780"
+ extra_details = list("goldstripe")
+
+// SolGov Crew and Contractors
+/obj/item/card/id/torch/crew
+ desc = "An identification card issued to SolGov crewmembers aboard the ISEO Endeavour."
+ color = "#d3e3e1"
+ color = "#ccecff"
+
+
+/obj/item/card/id/torch/contractor
+ desc = "An identification card issued to private contractors aboard the ISEO Endeavour."
+ color = COLOR_GRAY80
+
+
+/obj/item/card/id/torch/silver/medical
+ detail_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/card/id/torch/crew/medical
+ detail_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/card/id/torch/crew/medical/senior
+
+/obj/item/card/id/torch/contractor/medical
+ detail_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/card/id/torch/contractor/medical/senior
+
+/obj/item/card/id/torch/contractor/chemist
+ detail_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/card/id/torch/contractor/medical/counselor
+
+/obj/item/card/id/torch/silver/security
+ detail_color = "#e00000"
+
+/obj/item/card/id/torch/crew/security
+ detail_color = "#e00000"
+
+/obj/item/card/id/torch/crew/security/brigchief
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/crew/security/forensic
+
+/obj/item/card/id/torch/silver/engineering
+ detail_color = COLOR_SUN
+
+/obj/item/card/id/torch/crew/engineering
+ detail_color = COLOR_SUN
+
+/obj/item/card/id/torch/crew/engineering/senior
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/contractor/engineering
+ detail_color = COLOR_SUN
+
+/obj/item/card/id/torch/contractor/engineering/roboticist
+
+/obj/item/card/id/torch/crew/supply/deckofficer
+ detail_color = COLOR_BROWN
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/crew/supply
+ detail_color = COLOR_BROWN
+
+/obj/item/card/id/torch/contractor/supply
+ detail_color = COLOR_BROWN
+
+/obj/item/card/id/torch/crew/service //unused
+ detail_color = COLOR_CIVIE_GREEN
+
+/obj/item/card/id/torch/crew/service/janitor
+
+/obj/item/card/id/torch/crew/service/chef
+
+/obj/item/card/id/torch/crew/service/chaplain
+
+/obj/item/card/id/torch/contractor/service //unused
+ detail_color = COLOR_CIVIE_GREEN
+
+/obj/item/card/id/torch/contractor/service/bartender
+
+/obj/item/card/id/torch/crew/representative
+ detail_color = COLOR_COMMAND_BLUE
+
+/obj/item/card/id/torch/crew/sea
+ detail_color = COLOR_COMMAND_BLUE
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/crew/bridgeofficer
+ detail_color = COLOR_COMMAND_BLUE
+
+/obj/item/card/id/torch/crew/pathfinder
+ detail_color = COLOR_PURPLE
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/crew/explorer
+ detail_color = COLOR_PURPLE
+
+/obj/item/card/id/torch/crew/pilot
+ detail_color = COLOR_PURPLE
+
+// EC Science
+/obj/item/card/id/torch/silver/research
+ detail_color = COLOR_RESEARCH
+ color = COLOR_WHITE
+
+/obj/item/card/id/torch/crew/research
+ desc = "A card issued to science personnel aboard the ISEO Endeavour."
+ detail_color = COLOR_RESEARCH
+
+/obj/item/card/id/torch/crew/research/senior_scientist
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/crew/research/scientist
+
+//NanoTrasen and Passengers
+
+/obj/item/card/id/torch/passenger
+ desc = "A card issued to passengers aboard the ISEO Endeavour."
+ detail_color = COLOR_PAKISTAN_GREEN
+
+/obj/item/card/id/torch/passenger/research
+ desc = "A card issued to corporate personnel aboard the ISEO Endeavour."
+ detail_color = COLOR_BOTTLE_GREEN
+
+/obj/item/card/id/torch/passenger/research/senior_scientist
+ extra_details = list("onegoldstripe")
+
+/obj/item/card/id/torch/passenger/corporate
+ color = COLOR_BOTTLE_GREEN
+ detail_color = COLOR_OFF_WHITE
+
+/obj/item/card/id/torch/passenger/corporate/liaison
+ extra_details = list("onegoldstripe")
+
+//Merchant
+/obj/item/card/id/torch/merchant
+ desc = "An identification card issued to Merchants, indicating their right to sell and buy goods."
+ color = COLOR_OFF_WHITE
+ detail_color = COLOR_BEIGE
diff --git a/maps/torch/items/clothing/ec_skillbadges.dm b/maps/torch/items/clothing/ec_skillbadges.dm
new file mode 100644
index 00000000000..ad98a8cba58
--- /dev/null
+++ b/maps/torch/items/clothing/ec_skillbadges.dm
@@ -0,0 +1,39 @@
+/obj/item/clothing/accessory/skillbadge
+ name = "skill badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on spawning wrong types. Informally known as 'Shouldn't be seeing this'."
+ slot = ACCESSORY_SLOT_INSIGNIA
+
+/obj/item/clothing/accessory/skillbadge/botany
+ name = "Field Xenobotany Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on handling exotic xenoflora. Informally known as 'Vine Wrangler'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_botany.dmi'
+
+/obj/item/clothing/accessory/skillbadge/netgun
+ name = "Xenofauna Acquisition Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on capturing alien wildlife with the netgun. Informally known as 'Xeno-Cowboy'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_netgun.dmi'
+
+/obj/item/clothing/accessory/skillbadge/eva
+ name = "Void Mobility Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on moving around in zero-g using a jetpack. Informally known as 'Zoomer'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_eva.dmi'
+
+/obj/item/clothing/accessory/skillbadge/medical
+ name = "Advanced First Aid Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on CPR and basic medical tech. Informally known as 'Para-paramedic'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_firstaid.dmi'
+
+/obj/item/clothing/accessory/skillbadge/mech
+ name = "Exosuit Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on piloting exosuits. Informally known as 'Exonaut'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_exosuit.dmi'
+
+/obj/item/clothing/accessory/skillbadge/electric
+ name = "Electrical Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on working with high-voltage electrical systems. Informally known as 'Jury-rigger'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_electric.dmi'
+
+/obj/item/clothing/accessory/skillbadge/science
+ name = "Research Specialist badge"
+ desc = "An ISEO skill badge signifying that the bearer has passed the advanced training on assisting in the labs and working the sensor suites. Informally known as 'Peeper'."
+ icon = 'maps/torch/icons/converted_icons/accessories/skill_stripes/skillbadge_science.dmi'
diff --git a/maps/torch/items/clothing/solgov-head.dm b/maps/torch/items/clothing/solgov-head.dm
new file mode 100644
index 00000000000..139597f9cb0
--- /dev/null
+++ b/maps/torch/items/clothing/solgov-head.dm
@@ -0,0 +1,2 @@
+
+
diff --git a/maps/torch/items/clothing_bags.dm b/maps/torch/items/clothing_bags.dm
new file mode 100644
index 00000000000..23d57b60156
--- /dev/null
+++ b/maps/torch/items/clothing_bags.dm
@@ -0,0 +1,9 @@
+/obj/item/clothingbag/uniform
+ name = "uniform clothing bag"
+ var/list/spawn_contents = list()
+
+/obj/item/clothingbag/uniform/Initialize(ml, material_key)
+ . = ..()
+ for(var/I in spawn_contents)
+ if(ispath(I))
+ new I(src)
\ No newline at end of file
diff --git a/maps/torch/items/encryption_keys.dm b/maps/torch/items/encryption_keys.dm
new file mode 100644
index 00000000000..d809def235f
--- /dev/null
+++ b/maps/torch/items/encryption_keys.dm
@@ -0,0 +1,82 @@
+/obj/item/encryptionkey/heads/torchexec
+ name = "executive encryption key"
+ icon_state = "cap_cypherkey"
+ channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "Exploration" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/headset_torchnt
+ name = "corporate radio encryption key"
+ icon_state = "nt_cypherkey"
+ channels = list("Science" = 1, "Exploration" = 1)
+
+/obj/item/encryptionkey/headset_torchrd
+ name = "chief science officer radio encryption key"
+ icon_state = "nt_cypherkey"
+ channels = list("Science" = 1, "Command" = 1, "Exploration" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/headset_torchcorp
+ name = "corporate radio encryption key"
+ icon_state = "nt_cypherkey"
+ channels = list("Service" = 1)
+
+/obj/item/encryptionkey/headset_torchcl
+ name = "corporate liaison radio encryption key"
+ icon_state = "nt_cypherkey"
+ channels = list("Service" = 1, "Command" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/headset_deckofficer
+ name = "deck chief's encryption key"
+ icon_state = "qm_cypherkey"
+ channels = list("Supply" = 1, "Command" = 1, "Exploration" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/bridgeofficer
+ name = "bridge officer's encryption key"
+ icon_state = "com_cypherkey"
+ channels = list("Command" = 1, "Engineering" = 1, "Exploration" = 1, "Supply" = 1, "Service" = 1, "Science" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/heads/ai_integrated
+ name = "ai integrated encryption key"
+ desc = "Integrated encryption key."
+ icon_state = "cap_cypherkey"
+ channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "Exploration" = 1, "AI Private" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/exploration
+ name = "exploration radio encryption key"
+ icon_state = "srv_cypherkey"
+ channels = list("Exploration" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/headset_pilot
+ name = "pilot radio encryption key"
+ icon_state = "srv_cypherkey"
+ channels = list("Exploration" = 1, "Supply" = 1, "Science" = 1, "Hailing" = 1)
+
+/obj/item/encryptionkey/headset_mining
+ name = "prospector radio encryption key"
+ icon_state = "srv_cypherkey"
+ channels = list("Exploration" = 1, "Supply" = 1)
+
+/obj/item/storage/box/encryptionkey/exploration
+ name = "box of spare exploration radio keys"
+ desc = "A box full of exploration department radio keys."
+ startswith = list(/obj/item/screwdriver, /obj/item/encryptionkey/exploration = 5)
+
+/obj/item/encryptionkey/pathfinder
+ name = "pathfinder's encryption key"
+ icon_state = "com_cypherkey"
+ channels = list("Exploration" = 1, "Command" = 1, "Science" = 1, "Hailing" = 1)
+
+/obj/item/storage/box/radiokeys
+ name = "box of radio encryption keys"
+ desc = "A box full of assorted encryption keys."
+ startswith = list(/obj/item/encryptionkey/headset_sec = 3,
+ /obj/item/encryptionkey/headset_med = 3,
+ /obj/item/encryptionkey/headset_cargo = 3,
+ /obj/item/encryptionkey/headset_sci = 3)
+
+/obj/item/storage/box/radiokeys/Initialize()
+ . = ..()
+ make_exact_fit()
+
+/obj/item/encryptionkey/heads/sea
+ name = "senior enlisted advisor's encryption key"
+ icon_state = "com_cypherkey"
+ channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "Exploration" = 1, "Hailing" = 1)
diff --git a/maps/torch/items/explo_shotgun.dm b/maps/torch/items/explo_shotgun.dm
new file mode 100644
index 00000000000..fe0f3ed0628
--- /dev/null
+++ b/maps/torch/items/explo_shotgun.dm
@@ -0,0 +1,137 @@
+/obj/item/gun/projectile/shotgun/pump/exploration
+ name = "ballistic launcher"
+ desc = "As the user's handbook will tell you, the Xynergy XP-3 is /not/ a shotgun, it just launches payloads of same caliber at high speed towards targets. Nicknamed 'Boomstick' for the way it behaves when full-power ammunition is loaded."
+ icon = 'maps/torch/icons/obj/explshotgun.dmi'
+ icon_state = "expshotgun0"
+ starts_loaded = 0
+ req_access = list(access_hop)
+ authorized_modes = list(UNAUTHORIZED)
+ firemodes = list(
+ list(mode_name="fire"),
+ )
+ var/explosion_chance = 50
+ var/obj/item/pipe/reinforced
+
+/obj/item/gun/projectile/shotgun/pump/get_mechanics_info()
+ . = ..()
+ . += "
This gun will be allowed to fire freely once off-ship, otherwise needs to be authorized by XO. \
+
While you can load this gun with lethal ammo, there's a considerable risk of explosion when fired."
+
+/obj/item/gun/projectile/shotgun/pump/exploration/get_antag_info()
+ . = ..()
+ . += "
You can reinforce the barrel with a simple pipe, lowering chance of explosion to 1 in 10.
"
+
+/obj/item/gun/projectile/shotgun/pump/exploration/on_update_icon()
+ ..()
+ if(!reinforced)
+ icon_state = "expshotgun[!!chambered]"
+ else
+ icon_state = "ghettexpshotgun[!!chambered]"
+
+/obj/item/gun/projectile/shotgun/pump/exploration/Destroy()
+ QDEL_NULL(reinforced)
+ . = ..()
+
+/obj/item/gun/projectile/shotgun/pump/exploration/free_fire()
+ var/my_z = get_z(src)
+ if(!global.using_map.station_levels.Find(my_z))
+ return TRUE
+ return ..()
+
+/obj/item/gun/projectile/shotgun/pump/exploration/attackby(obj/item/I, mob/user)
+ if(!reinforced && istype(I, /obj/item/pipe) && user.unEquip(I, src))
+ reinforced = I
+ to_chat(user, SPAN_WARNING("You reinforce \the [src] with \the [reinforced]."))
+ playsound(src, 'sound/effects/tape.ogg',25)
+ explosion_chance = 10
+ bulk = bulk + 4
+ update_icon()
+ return 1
+ if(reinforced && isWirecutter(I))
+ to_chat(user, SPAN_WARNING("You remove \the [reinforced] that was reinforcing \the [src]."))
+ playsound(src.loc, 'sound/items/Wirecutter.ogg', 25, 1)
+ reinforced.dropInto(loc)
+ reinforced = null
+ explosion_chance = initial(explosion_chance)
+ bulk = initial(bulk)
+ update_icon()
+ return 1
+ return ..()
+
+/obj/item/gun/projectile/shotgun/pump/exploration/special_check()
+ if(chambered && chambered.BB && prob(explosion_chance))
+ var/damage = chambered.BB.get_structure_damage()
+ if(istype(chambered.BB, /obj/item/projectile/bullet/pellet))
+ var/obj/item/projectile/bullet/pellet/PP = chambered.BB
+ damage = PP.damage*PP.pellets
+ if(damage > 30)
+ var/mob/living/carbon/C = loc
+ if(istype(loc))
+ C.visible_message("[src] explodes in [C]'s hands!", "[src] explodes in your face!")
+ C.drop_from_inventory(src)
+ if(reinforced)
+ reinforced.dropInto(loc)
+ reinforced.throw_at(C, 2, 10)
+ reinforced = null
+ for(var/zone in list(BP_L_HAND, BP_R_HAND, BP_HEAD))
+ C.apply_damage(rand(10,20), def_zone=zone)
+ else
+ visible_message("[src] explodes!")
+ explosion(get_turf(src), -1, -1, 1)
+ qdel(src)
+ return FALSE
+ return ..()
+
+/obj/item/ammo_magazine/shotholder/net
+ name = "net shell holder"
+ ammo_type = /obj/item/ammo_casing/shotgun/net
+ matter = list(MATERIAL_STEEL = 720)
+ marking_color = COLOR_PALE_PURPLE_GRAY
+
+/obj/item/ammo_casing/shotgun/net
+ name = "net shell"
+ desc = "A net shell."
+ icon_state = "netshell"
+ projectile_type = /obj/item/projectile/bullet/shotgun/beanbag/net
+ matter = list(MATERIAL_STEEL = 180)
+
+/obj/item/projectile/bullet/shotgun/beanbag/net
+ name = "netshell"
+ damage = 5
+ agony = 10
+/*
+/obj/item/projectile/bullet/shotgun/beanbag/net/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
+ var/obj/item/energy_net/safari/net = new(loc)
+ net.try_capture_mob(target)
+ return TRUE
+*/
+
+/obj/item/storage/box/ammo/explo_shells
+ name = "box of utility shells"
+ startswith = list(/obj/item/ammo_magazine/shotholder/beanbag = 1,
+ /obj/item/ammo_magazine/shotholder/net = 1,
+ /obj/item/ammo_magazine/shotholder/flash = 1)
+
+/obj/structure/closet/secure_closet/explo_gun
+ name = "gun locker"
+ desc = "Wall locker holding the boomstick."
+ req_access = list(access_expedition_shuttle_helm)
+ closet_appearance = /decl/closet_appearance/wall/explo_gun
+ density = 0
+ anchored = 1
+ wall_mounted = 1
+ storage_types = CLOSET_STORAGE_ITEMS
+
+/obj/structure/closet/secure_closet/explo_gun/WillContain()
+ return list(
+ /obj/item/storage/box/ammo/explo_shells = 3,
+ /obj/item/gun/projectile/shotgun/pump/exploration
+ )
+
+/decl/closet_appearance/wall/explo_gun
+ color = COLOR_GRAY20
+ decals = null
+ can_lock = 1
+ extra_decals = list(
+ "stripe_outer" = COLOR_PURPLE
+ )
\ No newline at end of file
diff --git a/maps/torch/items/guns.dm b/maps/torch/items/guns.dm
new file mode 100644
index 00000000000..b7f142138f7
--- /dev/null
+++ b/maps/torch/items/guns.dm
@@ -0,0 +1,82 @@
+/obj/item/gun/energy/shock_carbine
+ name = "shock carbine"
+ desc = "A 'Zeus' E05 nonlethal energy carbine, designed to incapacitate targets with a powerful electrolaser. Has two modes: shock, and shockier."
+ icon = 'maps/torch/icons/obj/guns/taser_carbine.dmi'
+ icon_state = ICON_STATE_WORLD
+ slot_flags = SLOT_LOWER_BODY|SLOT_BACK
+ w_class = ITEM_SIZE_LARGE
+ force = 10
+ one_hand_penalty = 2
+ bulk = GUN_BULK_RIFLE
+ origin_tech = "{'combat':3,'magnets':2}"
+ material = /decl/material/solid/metal/steel
+ projectile_type = /obj/item/projectile/beam/stun/heavy
+
+ firemodes = list(
+ list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun/heavy),
+ list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock/heavy)
+ )
+
+/obj/item/gun/projectile/pistol/secure
+ name = "smartpistol"
+ desc = "The SEM-05A is a 'smart' weapon that will only fire if is authorized to fire it's loaded ammunition. Widely used by police forces across human space."
+ icon = 'maps/torch/icons/obj/guns/secure_pistol.dmi'
+ req_access = list(list(access_brig, access_bridge))
+ authorized_modes = list(ALWAYS_AUTHORIZED, UNAUTHORIZED, UNAUTHORIZED)
+ magazine_type = /obj/item/ammo_magazine/pistol/stun
+ var/list/allowed_projectile = list(/obj/item/ammo_casing/pistol/stun)
+
+ firemodes = list(
+ list(mode_name="nonlethal", allowed_projectile=list(/obj/item/ammo_casing/pistol/stun)),
+ list(mode_name="less than lethal", allowed_projectile=list(/obj/item/ammo_casing/pistol/stun,/obj/item/ammo_casing/pistol/rubber)),
+ list(mode_name="lethal", allowed_projectile=list(/obj/item/ammo_casing/pistol/stun,/obj/item/ammo_casing/pistol/rubber,/obj/item/ammo_casing/pistol))
+ )
+
+/obj/item/gun/projectile/pistol/secure/preauthorized
+ authorized_modes = list(ALWAYS_AUTHORIZED, ALWAYS_AUTHORIZED, ALWAYS_AUTHORIZED)
+
+/obj/item/gun/projectile/pistol/secure/special_check()
+ if(is_secure_gun() && !free_fire() && (!authorized_modes[sel_mode] || !registered_owner))
+ audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3)
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0)
+ return 0
+ var/obj/ammo
+ if(length(ammo_magazine.stored_ammo))
+ ammo = ammo_magazine.stored_ammo[1]
+ if(ammo_magazine && length(ammo_magazine.stored_ammo) && !isnull(ammo) && !(ammo.type in allowed_projectile)) //Comparing the first round in the magazine to the allowed projectile.
+ audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3)
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0)
+ return 0
+ . = ..()
+
+/obj/item/ammo_casing/pistol/stun
+ desc = "A taser pistol bullet casing."
+ projectile_type = /obj/item/projectile/energy/electrode
+ bullet_color = COLOR_GRAY40
+
+/obj/item/ammo_magazine/pistol/stun
+ labels = list("stun")
+ ammo_type = /obj/item/ammo_casing/pistol/stun
+
+/obj/item/storage/box/ammo/pistol_magazines/rubber
+ name = "box of magazines (10mm, rubber)"
+ icon_state = "ammo"
+ startswith = list(/obj/item/ammo_magazine/pistol/rubber = 7)
+
+/obj/item/storage/box/ammo/pistol_magazines/stun
+ name = "box of magazines (10mm, stun)"
+ icon_state = "ammo"
+ startswith = list(/obj/item/ammo_magazine/pistol/stun = 7)
+
+/obj/item/storage/box/ammo/pistol_magazines/lethal
+ name = "box of magazines (10mm, lethal)"
+ icon_state = "ammo"
+ startswith = list(/obj/item/ammo_magazine/pistol = 7)
+
+/obj/item/gun/energy/gun
+ firemodes = list(
+ list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun, indicator_color=COLOR_CYAN, charge_cost = 20),
+ list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock, indicator_color=COLOR_YELLOW, charge_cost = 20),
+ list(mode_name="kill", projectile_type=/obj/item/projectile/beam/smalllaser, indicator_color=COLOR_RED, charge_cost = 10),
+ )
+
diff --git a/maps/torch/items/headsets.dm b/maps/torch/items/headsets.dm
new file mode 100644
index 00000000000..f7051606867
--- /dev/null
+++ b/maps/torch/items/headsets.dm
@@ -0,0 +1,163 @@
+/obj/item/radio/headset/torchnanotrasen
+ name = "research headset"
+ desc = "A headset for researchers."
+ icon_state = "sci_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_torchnt
+
+/obj/item/radio/headset/heads/torchexec
+ name = "executive headset"
+ desc = "The headset of those brave men and women who command the Torch."
+ icon_state = "com_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/heads/torchexec
+
+/obj/item/radio/headset/heads/torchexec/alt
+ name = "executive bowman headset"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+
+/obj/item/radio/headset/heads/torchcorp
+ name = "corporate headset"
+ desc = "Headset of the servants to the corporate overlords."
+ icon_state = "nt_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_torchcorp
+
+/obj/item/radio/headset/heads/torchcorp/alt
+ name = "corporate bowman headset"
+ icon_state = "nt_headset_alt"
+ item_state = "nt_headset_alt"
+
+/obj/item/radio/headset/heads/torchntcommand
+ name = "corporate command headset"
+ desc = "Headset of the corporate overlords."
+ icon_state = "nt_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_torchcl
+
+/obj/item/radio/headset/heads/torchntcommand/alt
+ name = "corporate command bowman headset"
+ icon_state = "nt_headset_alt"
+ item_state = "nt_headset_alt"
+
+/obj/item/radio/headset/heads/torchntdirector
+ name = "chief science officer headset"
+ desc = "Headset of the masters of the universe."
+ icon_state = "com_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_torchrd
+
+/obj/item/radio/headset/heads/torchntdirector/alt
+ name = "chief science officer's bowman headset"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+
+/obj/item/radio/headset/heads/torchntcommand/alt
+ name = "corporate command bowman headset"
+ icon_state = "nt_headset_alt"
+ item_state = "nt_headset_alt"
+
+/obj/item/radio/headset/heads/cos
+ name = "chief of security's headset"
+ desc = "The headset of the man who protects your worthless lives."
+ icon_state = "com_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/heads/hos
+
+/obj/item/radio/headset/heads/cos/alt
+ name = "chief of security's bowman headset"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+
+/obj/item/radio/headset/headset_deckofficer
+ name = "deck chief's radio headset"
+ desc = "The headset of the chief box pusher."
+ icon_state = "cargo_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_deckofficer
+
+/obj/item/radio/headset/headset_deckofficer/alt
+ name = "deck chief's bowman headset"
+ item_state = "cargo_headset_alt"
+ icon_state = "cargo_headset_alt"
+ max_keys = 3
+
+/obj/item/radio/headset/sea
+ name = "senior enlisted advisor's headset"
+ desc = "A headset for the guy or gal who advises the enlisted whilst from a position of seniority."
+ icon_state = "com_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/heads/sea
+
+/obj/item/radio/headset/sea/alt
+ name = "senior enlisted advisor's bowman headset"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+
+/obj/item/radio/headset/bridgeofficer
+ name = "bridge officer's headset"
+ desc = "A headset with access to the command, engineering and exploration channels."
+ icon_state = "com_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/bridgeofficer
+
+/obj/item/radio/headset/bridgeofficer/alt
+ name = "bridge officer's bowman headset"
+ icon_state = "com_headset_alt"
+ item_state = "com_headset_alt"
+ max_keys = 4
+
+/obj/item/radio/headset/exploration
+ name = "exploration headset"
+ desc = "A headset with access to the exploration channel. It has an inbuilt subspace antenna for better reception."
+ icon_state = "exp_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/exploration
+
+/obj/item/radio/headset/exploration/alt
+ name = "exploration bowman headset"
+ icon_state = "exp_headset_alt"
+ item_state = "exp_headset_alt"
+
+/obj/item/radio/headset/pathfinder
+ name = "pathfinder's headset"
+ desc = "A headset with access to the command and exploration channels. It has an inbuilt subspace antenna for better reception."
+ icon_state = "exp_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/pathfinder
+
+/obj/item/radio/headset/pathfinder/alt
+ name = "pathfinder's bowman headset"
+ icon_state = "exp_headset_alt"
+ item_state = "exp_headset_alt"
+
+/obj/item/radio/headset/headset_cargo
+ desc = "A headset used by the Deck Chief and his slaves."
+
+/obj/item/radio/headset/headset_cargo/alt
+ desc = "A bowman headset used by the Deck Chief and his slaves."
+
+/obj/item/radio/headset/headset_corpsman
+ name = "medical headset"
+ desc = "A headset to yell into while patching open wounds. It has an inbuilt subspace antenna for better reception."
+ icon_state = "par_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_med
+
+/obj/item/radio/headset/headset_corpsman/alt
+ name = "medical bowman headset"
+ icon_state = "par_headset_alt"
+ item_state = "par_headset_alt"
+
+/obj/item/radio/headset/headset_pilot
+ name = "pilot's headset"
+ desc = "A headset for cool-tempered smugglers, cocky flyboys, and bus-drivers like you. It has an inbuilt subspace antenna for better reception."
+ icon_state = "pilot_headset"
+ item_state = "headset"
+ ks1type = /obj/item/encryptionkey/headset_pilot
+
+/obj/item/radio/headset/headset_pilot/alt
+ name = "pilot's bowman headset"
+ icon_state = "pilot_headset_alt"
+ item_state = "pilot_headset_alt"
diff --git a/maps/torch/items/hearth_clothing/armor.dm b/maps/torch/items/hearth_clothing/armor.dm
new file mode 100644
index 00000000000..1badb001aff
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/armor.dm
@@ -0,0 +1,14 @@
+/obj/item/clothing/suit/armor/vest/government
+ icon = 'maps/torch/icons/converted_icons/armor/armor.dmi'
+
+/obj/item/clothing/suit/armor/vest/government/command
+ desc = "An armor vest with gold highlights for Command personnel."
+ icon = 'maps/torch/icons/converted_icons/armor/armor_command.dmi'
+
+/obj/item/clothing/suit/armor/vest/government/peacekeeper
+ desc = "An armor vest typically worn by Espatier Corps peacekeepers."
+ icon = 'maps/torch/icons/converted_icons/armor/armor_peacekeeper.dmi'
+
+/obj/item/clothing/suit/armor/vest/government/sec
+ desc = "An armor vest typically worn by ISEO Security personnel."
+ icon = 'maps/torch/icons/converted_icons/armor/armor_sec.dmi'
diff --git a/maps/torch/items/hearth_clothing/attachments.dm b/maps/torch/items/hearth_clothing/attachments.dm
new file mode 100644
index 00000000000..0ba6b45eefe
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/attachments.dm
@@ -0,0 +1,314 @@
+//
+// ISEO ranks
+//
+
+/obj/item/clothing/accessory/rank/iseo
+ desc = "A set of rank tabs. Intended for ISEO uniforms."
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_technician_iseo.dmi'
+
+/obj/item/clothing/accessory/rank/iseo/t1
+ ranking = "CN"
+ ranking_full = "Crewman"
+
+/obj/item/clothing/accessory/rank/iseo/t2
+ ranking = "T3"
+ ranking_full = "Technician Third Class"
+
+/obj/item/clothing/accessory/rank/iseo/t3
+ ranking = "T2"
+ ranking_full = "Technician Second Class"
+
+/obj/item/clothing/accessory/rank/iseo/t4
+ ranking = "T1"
+ ranking_full = "Technician First Class"
+
+/obj/item/clothing/accessory/rank/iseo/officer
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_specialist_iseo.dmi'
+
+/obj/item/clothing/accessory/rank/iseo/officer/s1
+ ranking = "S1"
+ ranking_full = "Ensign"
+
+/obj/item/clothing/accessory/rank/iseo/officer/s2
+ ranking = "S2"
+ ranking_full = "Lieutenant"
+
+/obj/item/clothing/accessory/rank/iseo/officer/s3
+ ranking = "S3"
+ ranking_full = "Lieutenant-Commander"
+
+/obj/item/clothing/accessory/rank/iseo/command
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_command_iseo.dmi'
+
+/obj/item/clothing/accessory/rank/iseo/command/s4
+ ranking = "S4"
+ ranking_full = "Commander"
+
+/obj/item/clothing/accessory/rank/iseo/command/s5
+ ranking = "S5"
+ ranking_full = "Captain"
+
+//
+// Espatier Ranks
+//
+
+/obj/item/clothing/accessory/rank/espatier
+ desc = "A set of rank tabs. Intended for espatier uniforms."
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_enlisted_espatier.dmi'
+
+/obj/item/clothing/accessory/rank/espatier/e1
+ ranking = "E1"
+ ranking_full = "Private"
+
+/obj/item/clothing/accessory/rank/espatier/e2
+ ranking = "E2"
+ ranking_full = "Private First Class"
+
+/obj/item/clothing/accessory/rank/espatier/e3
+ ranking = "E3"
+ ranking_full = "Lance Corporal"
+
+/obj/item/clothing/accessory/rank/espatier/e4
+ ranking = "E4"
+ ranking_full = "Corporal"
+
+/obj/item/clothing/accessory/rank/espatier/e5
+ ranking = "E5"
+ ranking_full = "Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e6
+ ranking = "E6"
+ ranking_full = "Staff Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e7
+ ranking = "E7"
+ ranking_full = "Gunnery Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e8
+ ranking = "E8"
+ ranking_full = "Master Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e8_alt
+ ranking = "E8"
+ ranking_full = "First Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e9
+ ranking = "E9"
+ ranking_full = "Master Gunnery Sergeant"
+
+/obj/item/clothing/accessory/rank/espatier/e9_alt
+ ranking = "E9"
+ ranking_full = "Command Sergeant Major"
+
+/obj/item/clothing/accessory/rank/espatier/e9_alt2
+ ranking = "E9"
+ ranking_full = "Sergeant Major"
+
+/obj/item/clothing/accessory/rank/espatier/officer
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_officer_espatier.dmi'
+
+/obj/item/clothing/accessory/rank/espatier/officer/o1
+ ranking = "O1"
+ ranking_full = "Second Lieutenant"
+
+/obj/item/clothing/accessory/rank/espatier/officer/o2
+ ranking = "O2"
+ ranking_full = "First Lieutenant"
+
+/obj/item/clothing/accessory/rank/espatier/officer/o3
+ ranking = "O3"
+ ranking_full = "Captain"
+
+/obj/item/clothing/accessory/rank/espatier/command/o4
+ ranking = "O4"
+ ranking_full = "Major"
+
+/obj/item/clothing/accessory/rank/espatier/command
+ icon = 'maps/torch/icons/converted_icons/accessories/rank_command_espatier.dmi'
+
+/obj/item/clothing/accessory/rank/espatier/command/o5
+ ranking = "O5"
+ ranking_full = "Lieutenant-Colonel"
+
+/obj/item/clothing/accessory/rank/espatier/command/o6
+ ranking = "O6"
+ ranking_full = "Colonel"
+
+/obj/item/clothing/accessory/rank/espatier/command/o7
+ ranking = "O7"
+ ranking_full = "Brigadier General"
+
+/obj/item/clothing/accessory/rank/espatier/command/o8
+ ranking = "O8"
+ ranking_full = "Major General"
+
+/obj/item/clothing/accessory/rank/espatier/command/o9
+ ranking = "O8"
+ ranking_full = "Lieutenant General"
+
+/obj/item/clothing/accessory/rank/espatier/command/o10
+ ranking = "O10"
+ ranking_full = "General"
+
+/obj/item/clothing/accessory/rank/espatier/command/o10_alt
+ ranking = "10"
+ ranking_full = "General of the Corps"
+
+
+
+//
+// Department Stripes
+// Just color these, except for the command pips.
+
+/obj/item/clothing/accessory/department
+ removable = FALSE
+
+/obj/item/clothing/accessory/department/iseo
+ name = "department stripes"
+ desc = "A set of colored, velcro-backed strips. These are tailored for ISEO uniforms."
+ icon = 'maps/torch/icons/converted_icons/accessories/dept_stripe_iseo.dmi'
+
+/obj/item/clothing/accessory/department/iseo/engineering
+ color = "#ff7f00"
+
+/obj/item/clothing/accessory/department/iseo/security
+ color = "#bf0000"
+
+/obj/item/clothing/accessory/department/iseo/command
+ color = "#e5ea4f"
+
+/obj/item/clothing/accessory/department/iseo/supply
+ color = "#bb9042"
+
+/obj/item/clothing/accessory/department/iseo/exploration
+ color = "#68099e"
+
+/obj/item/clothing/accessory/department/iseo/medical
+ color = "#4c9ce4"
+
+/obj/item/clothing/accessory/department/iseo/service
+ color = "#6eaa2c"
+
+/obj/item/clothing/accessory/department/espatier
+ name = "department stripes"
+ desc = "A set of colored, velcro-backed strips. These are tailored for espatier uniforms."
+ icon = 'maps/torch/icons/converted_icons/accessories/dept_stripe_espatier.dmi'
+
+/obj/item/clothing/accessory/department/espatier/engineering
+ color = "#ff7f00"
+
+/obj/item/clothing/accessory/department/espatier/security
+ color = "#bf0000"
+
+/obj/item/clothing/accessory/department/espatier/command
+ color = "#e5ea4f"
+
+/obj/item/clothing/accessory/department/espatier/supply
+ color = "#bb9042"
+
+/obj/item/clothing/accessory/department/espatier/exploration
+ color = "#68099e"
+
+/obj/item/clothing/accessory/department/espatier/medical
+ color = "#4c9ce4"
+
+/obj/item/clothing/accessory/department/espatier/service
+ color = "#6eaa2c"
+
+/obj/item/clothing/accessory/department/espatier/jackettags
+ name = "espatier jacket department stripes"
+ desc = "A set of colored, velcro-backed strips intended to attach to an espatier jacket."
+ icon = 'maps/torch/icons/converted_icons/accessories/service_jacket_tags_espatier.dmi'
+
+/obj/item/clothing/accessory/department/espatier/jackettags/engineering
+ color = "#ff7f00"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/security
+ color = "#bf0000"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/command
+ color = "#e5ea4f"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/supply
+ color = "#bb9042"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/exploration
+ color = "#68099e"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/medical
+ color = "#4c9ce4"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/service
+ color = "#6eaa2c"
+
+//ISEO Jacket Tags
+/obj/item/clothing/accessory/department/iseo/jackettags
+ name = "iseo jacket department stripes"
+ desc = "A set of colored, velcro-backed strips intended to attach to an ISEO jacket."
+ icon = 'maps/torch/icons/converted_icons/accessories/iseo_jacket_tags.dmi'
+
+/obj/item/clothing/accessory/department/iseo/jackettags/engineering
+ color = "#ff7f00"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/security
+ color = "#bf0000"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/command
+ color = "#e5ea4f"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/supply
+ color = "#bb9042"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/exploration
+ color = "#68099e"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/medical
+ color = "#4c9ce4"
+
+/obj/item/clothing/accessory/department/iseo/jackettags/service
+ color = "#6eaa2c"
+
+/obj/item/clothing/accessory/department/espatier/jackettags/command
+ name = "service jacket command pips"
+ desc = "A set of gold pips intended to attach to an espatier service jacket."
+ icon = 'maps/torch/icons/converted_icons/accessories/service_jacket_tags_command_espatier.dmi'
+
+//
+// Master At Arms accessories
+//
+
+/obj/item/clothing/accessory/badge/maa
+ badge_string = "Master At Arms"
+ icon = 'maps/torch/icons/converted_icons/accessories/maa_badge.dmi'
+
+/obj/item/clothing/accessory/armband/maa
+ name = "Master At Arms band"
+ desc = "An armband denoting that the wearer is a Master At Arms."
+ icon = 'maps/torch/icons/converted_icons/accessories/maa_band.dmi'
+
+
+
+//
+// Skrell accessories
+//
+/obj/item/clothing/accessory/rank/SDTF
+ desc = "Insigna denothing some sort of position in a SDTF."
+ icon = 'mods/species/skrell/icons/clothing/accessories/obj_skrell_blank.dmi'
+ hide_on_uniform_rollsleeves = FALSE
+ slot = ACCESSORY_SLOT_RANK
+
+/obj/item/clothing/accessory/rank/SDTF/QZQX
+ ranking = "QZQX"
+ ranking_full = "Qrii-Zuumqix"
+ icon = 'mods/species/skrell/icons/clothing/accessories/obj_skrell_zuumqix.dmi'
+
+/obj/item/clothing/accessory/rank/SDTF/QVX
+ ranking = "QVX"
+ ranking_full = "Qrii-Vuxix"
+ icon = 'mods/species/skrell/icons/clothing/accessories/obj_skrell_vuxix.dmi'
+
+/datum/mil_rank/skrell_fleet/zuumqix
+ accessory = list(/obj/item/clothing/accessory/rank/SDTF/QZQX)
+
+/datum/mil_rank/skrell_fleet/vuxix
+ accessory = list(/obj/item/clothing/accessory/rank/SDTF/QVX)
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/gloves.dm b/maps/torch/items/hearth_clothing/gloves.dm
new file mode 100644
index 00000000000..223111271ac
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/gloves.dm
@@ -0,0 +1,31 @@
+/obj/item/clothing/gloves/duty
+ name = "duty gloves"
+ desc = "A pair of sturdy, comfortable gloves."
+
+/obj/item/clothing/gloves/duty/com
+ name = "command duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_command.dmi'
+
+/obj/item/clothing/gloves/duty/eng
+ name = "engineering duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_engineering.dmi'
+
+/obj/item/clothing/gloves/duty/sec
+ name = "security duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_security.dmi'
+
+/obj/item/clothing/gloves/duty/sci
+ name = "exploration duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_science.dmi'
+
+/obj/item/clothing/gloves/duty/med
+ name = "medical duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_medical.dmi'
+
+/obj/item/clothing/gloves/duty/srv
+ name = "service duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_service.dmi'
+
+/obj/item/clothing/gloves/duty/sup
+ name = "supply duty gloves"
+ icon = 'maps/torch/icons/converted_icons/gloves/duty_gloves_supply.dmi'
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/hats.dm b/maps/torch/items/hearth_clothing/hats.dm
new file mode 100644
index 00000000000..e1608f9219c
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/hats.dm
@@ -0,0 +1,53 @@
+/obj/item/clothing/head/helmet/pilot/alternate
+ name = "pilot's helmet"
+ desc = "A pilot's helmet for operating the cockpit in style. This one is worn by members of the ISEO Fleet."
+ icon = 'maps/torch/icons/borrowed_icons/pilot/helmet.dmi'
+ var/open = FALSE
+
+/obj/item/clothing/head/helmet/pilot/alternate/attack_self(mob/user)
+ open = !open
+ to_chat(user, SPAN_NOTICE("You [open ? "flip your visor up and undo your mask." : "flip your visor down and put your mask on."]"))
+ update_icon()
+ adjust_airtightness()
+
+/obj/item/clothing/head/helmet/pilot/alternate/on_update_icon(mob/user)
+ . = ..()
+ icon_state = get_world_inventory_state()
+ if(open && check_state_in_icon("[icon_state]-open", icon))
+ icon_state = "[icon_state]-open"
+ update_clothing_icon()
+
+/obj/item/clothing/head/helmet/pilot/alternate/adjust_mob_overlay(var/mob/living/user_mob, var/bodytype, var/image/overlay, var/slot, var/bodypart)
+ if(overlay && open && check_state_in_icon("[overlay.icon_state]-open", overlay.icon))
+ overlay.icon_state = "[overlay.icon_state]-open"
+ . = ..()
+
+/obj/item/clothing/head/helmet/pilot/alternate/proc/adjust_airtightness()
+ if(open)
+ item_flags &= ~ITEM_FLAG_AIRTIGHT
+ else
+ item_flags |= ITEM_FLAG_AIRTIGHT
+
+//Variants below.
+
+/obj/item/clothing/head/helmet/pilot/alternate/mobius
+ icon = 'maps/torch/icons/borrowed_icons/pilot/mobius.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/viper
+ icon = 'maps/torch/icons/borrowed_icons/pilot/viper.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/luke
+ icon = 'maps/torch/icons/borrowed_icons/pilot/luke.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/shark
+ icon = 'maps/torch/icons/borrowed_icons/pilot/shark.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/corvid
+ icon = 'maps/torch/icons/borrowed_icons/pilot/corvid.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/ace
+ icon = 'maps/torch/icons/borrowed_icons/pilot/ace.dmi'
+
+/obj/item/clothing/head/helmet/pilot/alternate/checker
+ icon = 'maps/torch/icons/borrowed_icons/pilot/checker.dmi'
+
diff --git a/maps/torch/items/hearth_clothing/hats_espatier.dm b/maps/torch/items/hearth_clothing/hats_espatier.dm
new file mode 100644
index 00000000000..308380d6acb
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/hats_espatier.dm
@@ -0,0 +1,88 @@
+//
+// Utility Cap
+//
+
+/obj/item/clothing/head/espatier/utility
+ name = "green utility cap"
+ desc = "A plain green cap, typically used in casual settings. Tailored for forested enviroments."
+ icon = 'maps/torch/icons/converted_icons/head/utility_cap_green_espatier.dmi'
+
+/obj/item/clothing/head/espatier/utility/tan
+ name = "tan utility cap"
+ desc = "A plain tan cap, typically used in casual settings. Tailored for arid enviroments."
+ icon = 'maps/torch/icons/converted_icons/head/utility_cap_tan_espatier.dmi'
+
+/obj/item/clothing/head/espatier/utility/grey
+ name = "grey utility cap"
+ desc = "A plain grey cap, typically used in casual settings. Tailored for urban enviroments"
+ icon = 'maps/torch/icons/converted_icons/head/utility_cap_grey_espatier.dmi'
+
+//
+// Garrison Cap
+//
+
+/obj/item/clothing/head/espatier/garrison_cap
+ name = "green garrison cap"
+ desc = "A green garrison cap, typically used in semi-formal situations."
+ icon = 'maps/torch/icons/converted_icons/head/garrison_cap_espatier.dmi'
+
+//
+// Wheel Caps
+//
+
+/obj/item/clothing/head/espatier/wheel_cap
+ name = "wheel cap"
+ desc = "A green wheel cap, typically used in formal occasions."
+ icon = 'maps/torch/icons/converted_icons/head/wheel_cap_espatier.dmi'
+
+/obj/item/clothing/head/espatier/wheel_cap/command
+ desc = "A green wheel cap, typically used in formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/head/wheel_cap_command_espatier.dmi'
+
+//
+// Berets
+//
+
+/obj/item/clothing/head/espatier/beret
+ name = "black beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/engineering
+ name = "black engineering beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a orange-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_engineering_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/security
+ name = "black security beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a red-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_security_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/medical
+ name = "black medical beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a blue-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_medical_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/service
+ name = "black service beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a green-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_service_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/supply
+ name = "black supply beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a tan-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_supply_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/command
+ name = "black command beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a gold-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_command_espatier.dmi'
+
+/obj/item/clothing/head/espatier/beret/exploration
+ name = "black exploration beret"
+ desc = "A plain black beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a purple-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_exploration_espatier.dmi'
+
+/obj/item/clothing/head/beret/espatier
+ name = "dress beret"
+ color = COLOR_BLACK
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/hats_general.dm b/maps/torch/items/hearth_clothing/hats_general.dm
new file mode 100644
index 00000000000..3f56bfa262f
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/hats_general.dm
@@ -0,0 +1,29 @@
+/obj/item/clothing/head/beret/iseo/peacekeeper
+ name = "peacekeeper beret"
+ desc = "A beret in UN colors. For peacekeepers that are more inclined towards style than safety."
+ color = COLOR_BABY_BLUE
+
+/obj/item/clothing/head/beret/iseo/gateway
+ name = "ISEO beret"
+ desc = "An orange beret denoting service in one of the ISEO's many departments. For personnel that are more inclined towards style than safety."
+ color = COLOR_ORANGE
+
+/obj/item/clothing/head/beret/iseo/orbital
+ name = "orbital assault beret"
+ desc = "A blue beret denoting orbital assault training. For helljumpers that are more inclined towards style than safety."
+ color = COLOR_DARK_BLUE_GRAY
+
+/obj/item/clothing/head/beret/iseo/research
+ name = "government research beret"
+ desc = "A green beret denoting service in the Bureau of Research. For scientists that are more inclined towards style than safety."
+ color = COLOR_DARK_GREEN_GRAY
+
+/obj/item/clothing/head/beret/iseo/health
+ name = "health service beret"
+ desc = "A white beret denoting service in the Interstellar Health Service. For medics that are more inclined towards style than safety."
+ color = COLOR_WHITE
+
+/obj/item/clothing/head/beret/iseo/diplomatic
+ name = "diplomatic security beret"
+ desc = "A tan beret denoting service in the Espatier Corps Diplomatic Security Group. For security personnel who are more inclined towards style than safety."
+ color = COLOR_TAN
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/hats_iseo.dm b/maps/torch/items/hearth_clothing/hats_iseo.dm
new file mode 100644
index 00000000000..2c168535fff
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/hats_iseo.dm
@@ -0,0 +1,91 @@
+//
+// Utility Cap
+//
+
+/obj/item/clothing/head/iseo/utility
+ name = "navy utility cap"
+ desc = "A plain navy blue cap, typically used in casual settings."
+ icon = 'maps/torch/icons/converted_icons/head/utility_cap_iseo.dmi'
+
+//
+// Garrison Cap
+//
+
+/obj/item/clothing/head/iseo/garrison_cap
+ name = "white garrison cap"
+ desc = "A white garrison cap, typically used in semi-formal situations."
+ icon = 'maps/torch/icons/converted_icons/head/garrison_cap_iseo.dmi'
+
+//
+// Wheel Caps
+//
+
+/obj/item/clothing/head/iseo/wheel_cap
+ name = "wheel cap"
+ desc = "A white wheel cap, typically used in formal occasions."
+ icon = 'maps/torch/icons/converted_icons/head/wheel_cap_iseo.dmi'
+
+/obj/item/clothing/head/iseo/wheel_cap/command
+ desc = "A white wheel cap, typically used in formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/head/wheel_cap_command_iseo.dmi'
+
+//
+// Peak Caps
+//
+
+/obj/item/clothing/head/iseo/peak_cap
+ name = "peak cap"
+ desc = "A white peak cap, typically used in semi-formal occasions."
+ icon = 'maps/torch/icons/converted_icons/head/peak_cap_iseo.dmi'
+
+/obj/item/clothing/head/iseo/peak_cap/command
+ desc = "A white peak cap, typically used in semi-formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/head/peak_cap_command_iseo.dmi'
+
+//
+// Berets
+//
+
+/obj/item/clothing/head/iseo/beret
+ name = "navy beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/engineering
+ name = "navy engineering beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a orange-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_engineering_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/security
+ name = "navy security beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a red-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_security_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/medical
+ name = "navy medical beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a blue-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_medical_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/service
+ name = "navy service beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a green-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_service_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/supply
+ name = "navy supply beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a tan-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_supply_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/command
+ name = "navy command beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a gold-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_command_iseo.dmi'
+
+/obj/item/clothing/head/iseo/beret/exploration
+ name = "navy exploration beret"
+ desc = "A plain navy blue beret, typically used as a fashion statement with semi-formal uniforms or casual use. This one has a purple-colored insignia on it."
+ icon = 'maps/torch/icons/converted_icons/head/berets/beret_exploration_iseo.dmi'
+
+/obj/item/clothing/head/beret/iseo
+ name = "dress beret"
+ color = COLOR_WHITE
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/skinsuits.dm b/maps/torch/items/hearth_clothing/skinsuits.dm
new file mode 100644
index 00000000000..8f0f23efa08
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/skinsuits.dm
@@ -0,0 +1,60 @@
+/obj/item/clothing/suit/space/skinsuit
+ name = "skinsuit"
+ desc = "A one-size-fits-all emergency skinsuit."
+ icon = 'maps/torch/icons/original_icons/skinsuit/suit.dmi'
+ markings_icon = "_markings"
+ markings_color = COLOR_GRAY40
+ allowed = list(/obj/item/tank)
+
+/obj/item/clothing/suit/space/skinsuit/engineering
+ name = "engineering skinsuit"
+ markings_color = COMMS_COLOR_ENGINEER
+
+/obj/item/clothing/suit/space/skinsuit/security
+ name = "security skinsuit"
+ markings_color = COLOR_MAROON
+
+/obj/item/clothing/suit/space/skinsuit/command
+ name = "command skinsuit"
+ markings_color = "#344c87"
+
+/obj/item/clothing/suit/space/skinsuit/science
+ name = "research skinsuit"
+ markings_color = COMMS_COLOR_SCIENCE
+
+/obj/item/clothing/suit/space/skinsuit/medical
+ name = "medical skinsuit"
+ markings_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/clothing/suit/space/skinsuit/generic
+ markings_color = COLOR_GRAY
+
+/obj/item/clothing/head/helmet/space/skinsuit
+ name = "skinsuit helmet"
+ desc = "A one-size-fits-all emergency skinsuit helmet."
+ icon = 'maps/torch/icons/original_icons/skinsuit/helmet.dmi'
+ markings_icon = "_markings"
+ markings_color = COLOR_GRAY40
+
+/obj/item/clothing/head/helmet/space/skinsuit/engineering
+ name = "engineering skinsuit helmet"
+ markings_color = COMMS_COLOR_ENGINEER
+
+/obj/item/clothing/head/helmet/space/skinsuit/security
+ name = "security skinsuit helmet"
+ markings_color = COLOR_MAROON
+
+/obj/item/clothing/head/helmet/space/skinsuit/command
+ name = "command skinsuit helmet"
+ markings_color = "#344c87"
+
+/obj/item/clothing/head/helmet/space/skinsuit/science
+ name = "research skinsuit helmet"
+ markings_color = COMMS_COLOR_SCIENCE
+
+/obj/item/clothing/head/helmet/space/skinsuit/medical
+ name = "medical skinsuit helmet"
+ markings_color = COLOR_PALE_BLUE_GRAY
+
+/obj/item/clothing/head/helmet/space/skinsuit/generic
+ markings_color = COLOR_GRAY
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/suits_espatier.dm b/maps/torch/items/hearth_clothing/suits_espatier.dm
new file mode 100644
index 00000000000..9f8b79f31cf
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/suits_espatier.dm
@@ -0,0 +1,41 @@
+//
+// Utility
+// We use attachments to customize these.
+
+/obj/item/clothing/suit/storage/espatier/jacket
+ name = "espatier jacket"
+ desc = "A green jacket, typically used in casual occasions. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_service_espatiers.dmi'
+ allowed = list (/obj/item/tank/emergency,/obj/item/flashlight,/obj/item/handcuffs,/obj/item/taperecorder,/obj/item/crowbar,/obj/item/radio)
+
+/obj/item/clothing/suit/storage/espatier/jacket/engineering
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/engineering)
+
+/obj/item/clothing/suit/storage/espatier/jacket/security
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/security)
+
+/obj/item/clothing/suit/storage/espatier/jacket/command
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/command)
+
+/obj/item/clothing/suit/storage/espatier/jacket/supply
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/supply)
+
+/obj/item/clothing/suit/storage/espatier/jacket/service
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/service)
+
+/obj/item/clothing/suit/storage/espatier/jacket/science
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/jackettags/exploration)
+
+//
+// Dress
+//
+
+/obj/item/clothing/suit/espatier/dress
+ name = "dress jacket"
+ desc = "A black and red dress jacket, typically used in formal occasions. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_espatiers.dmi'
+
+/obj/item/clothing/suit/espatier/dress/command
+ name = "dress jacket"
+ desc = "A black and red dress jacket, typically used in formal occasions. Fitted for both sexes. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_command_espatiers.dmi'
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/suits_iseo.dm b/maps/torch/items/hearth_clothing/suits_iseo.dm
new file mode 100644
index 00000000000..aac1f9207b1
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/suits_iseo.dm
@@ -0,0 +1,72 @@
+//
+// Utility
+//
+
+/obj/item/clothing/suit/storage/iseo/utility
+ name = "utility jacket"
+ desc = "A rugged, navy blue jacket for casual wear."
+ icon = 'maps/torch/icons/converted_icons/suits/iseo_jacket.dmi'
+ allowed = list (/obj/item/tank/emergency,/obj/item/flashlight,/obj/item/handcuffs,/obj/item/taperecorder,/obj/item/crowbar,/obj/item/radio)
+
+/obj/item/clothing/suit/storage/iseo/utility/engineering
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/engineering)
+
+/obj/item/clothing/suit/storage/iseo/utility/security
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/security)
+
+/obj/item/clothing/suit/storage/iseo/utility/medical
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/medical)
+
+/obj/item/clothing/suit/storage/iseo/utility/command
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/command)
+
+/obj/item/clothing/suit/storage/iseo/utility/science
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/exploration)
+
+/obj/item/clothing/suit/storage/iseo/utility/service
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/service)
+
+/obj/item/clothing/suit/storage/iseo/utility/supply
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/jackettags/supply)
+
+//
+// Service
+//
+
+/obj/item/clothing/suit/storage/iseo/service
+ name = "service jacket"
+ desc = "A navy blue service jacket, typically used in semi-formal occasions. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_service_iseo.dmi'
+ allowed = list(/obj/item/tank/emergency,/obj/item/pen,/obj/item/taperecorder,/obj/item/radio,/obj/item/taperoll)
+/obj/item/clothing/suit/storage/iseo/service/officer
+ desc = "A navy blue service jacket, typically used in semi-formal occasions. Fitted for both sexes. This one has silver highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_service_officer_iseo.dmi'
+
+/obj/item/clothing/suit/storage/iseo/service/command
+ desc = "A navy blue service jacket, typically used in semi-formal occasions. Fitted for both sexes. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_service_command_iseo.dmi'
+
+/obj/item/clothing/suit/storage/iseo/service/flag
+ desc = "A navy blue service jacket, typically used in semi-formal occasions. Fitted for both sexes. This one has red highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_service_flag_iseo.dmi'
+
+//
+// Dress
+//
+
+/obj/item/clothing/suit/iseo/dress
+ name = "dress jacket"
+ desc = "A dark navy blue dress jacket, typically used in formal occasions. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_iseo.dmi'
+
+/obj/item/clothing/suit/iseo/dress/officer
+ desc = "A dark navy blue dress jacket, typically used in formal occasions. Fitted for both sexes. This one has silver highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_officer_iseo.dmi'
+
+/obj/item/clothing/suit/iseo/dress/command
+ desc = "A dark navy blue dress jacket, typically used in formal occasions. Fitted for both sexes. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_command_iseo.dmi'
+
+/obj/item/clothing/suit/iseo/dress/flag
+ desc = "A dark navy blue dress jacket, typically used in formal occasions. Fitted for both sexes. This one has red highlights."
+ icon = 'maps/torch/icons/converted_icons/suits/suit_dress_flag_iseo.dmi'
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/uniforms_contractor.dm b/maps/torch/items/hearth_clothing/uniforms_contractor.dm
new file mode 100644
index 00000000000..7f83623c49d
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/uniforms_contractor.dm
@@ -0,0 +1,5 @@
+/obj/item/clothing/under/hazard/contractor
+ siemens_coefficient = 0.9
+ armor = list(
+ rad = ARMOR_RAD_MINOR
+ )
\ No newline at end of file
diff --git a/maps/torch/items/hearth_clothing/uniforms_espatier.dm b/maps/torch/items/hearth_clothing/uniforms_espatier.dm
new file mode 100644
index 00000000000..b2736a92a2a
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/uniforms_espatier.dm
@@ -0,0 +1,100 @@
+/obj/item/clothing/under/espatier/Initialize()
+ . = ..()
+ LAZYREMOVE(sprite_sheets, BODYTYPE_UNATHI) // contained in the base icon
+
+//
+// PT Uniform
+//
+
+/obj/item/clothing/under/espatier/pt
+ name = "pt uniform"
+ desc = "A plain black set of shorts and t-shirt. Utiliarian to the extreme. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/under/under_pt_espatiers.dmi'
+//
+// Utility
+//
+/obj/item/clothing/under/espatier/utility
+ name = "green utility fatigues"
+ desc = "A set of green fatigues made from sturdy, durable synthetic fibers. Mildly flash and stain resistant. Tailored for forested climates."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_green_espatiers.dmi'
+ siemens_coefficient = 0.8
+ armor = list(
+ melee = ARMOR_MELEE_MINOR,
+ energy = ARMOR_ENERGY_MINOR
+ )
+
+/obj/item/clothing/under/espatier/utility/command
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/command)
+
+/obj/item/clothing/under/espatier/utility/security
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/security)
+
+/obj/item/clothing/under/espatier/utility/medical
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/medical, /obj/item/clothing/accessory/armband/medblue)
+
+/obj/item/clothing/under/espatier/utility/engineering
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/engineering, /obj/item/clothing/accessory/armband/engine)
+
+/obj/item/clothing/under/espatier/utility/supply
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/supply, /obj/item/clothing/accessory/armband/cargo)
+
+/obj/item/clothing/under/espatier/utility/service
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/service)
+
+/obj/item/clothing/under/espatier/utility/science
+ starting_accessories = list(/obj/item/clothing/accessory/department/espatier/exploration)
+
+/obj/item/clothing/under/iseo/utility/alt
+ name = "tan utility fatigues"
+ desc = "A set of tan fatigues made from sturdy, durable synthetic fibers. Mildly flash and stain resistant. Tailored for arid climates."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_tan_espatiers.dmi'
+
+/obj/item/clothing/under/iseo/utility/alt2
+ name = "grey utility fatigues"
+ desc = "A set of grey fatigues made from sturdy, durable synthetic fibers. Mildly flash and stain resistant. Tailored for urban use."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_grey_espatiers.dmi'
+//
+// Service
+//
+
+/obj/item/clothing/under/espatier/service/uniform
+ name = "service uniform"
+ desc = "A fetching service uniform, with green pants and a brown dress shirt. For all semi-formal and formal occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/service/uniform/officer
+ desc = "A fetching service uniform, with green pants and a brown dress shirt. For all semi-formal and formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_command_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/service/skirt
+ name = "service skirt"
+ desc = "A fetching service uniform, with a green skirt and a brown dress shirt. For all semi-formal and formal occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/service/skirt/officer
+ name = "service skirt"
+ desc = "A fetching service uniform, with a green skirt and a brown dress shirt. For all semi-formal and formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_command_espatiers.dmi'
+
+//
+// Dress
+//
+
+/obj/item/clothing/under/espatier/dress/uniform
+ name = "dress uniform"
+ desc = "A set of black dress pants with a brown dress shirt with red highlights. Typically used only for the most formal of occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_dress_uniform_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/dress/uniform/command
+ desc = "A set of black dress pants with a brown dress shirt with gold highlights. Typically used only for the most formal of occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_dress_uniform_command_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/dress/skirt
+ name = "dress skirt"
+ desc = "A black skirt with a brown dress shirt with red highlights. Typically used only for the most formal of occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_dress_skirt_espatiers.dmi'
+
+/obj/item/clothing/under/espatier/dress/skirt/command
+ name = "dress skirt"
+ desc = "A black skirt with a brown dress shirt with gold highlights. Typically used only for the most formal of occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_dress_skirt_command_espatiers.dmi'
diff --git a/maps/torch/items/hearth_clothing/uniforms_iseo.dm b/maps/torch/items/hearth_clothing/uniforms_iseo.dm
new file mode 100644
index 00000000000..2e892e6178d
--- /dev/null
+++ b/maps/torch/items/hearth_clothing/uniforms_iseo.dm
@@ -0,0 +1,95 @@
+/obj/item/clothing/under/iseo/Initialize()
+ . = ..()
+ LAZYREMOVE(sprite_sheets, BODYTYPE_UNATHI) // contained in the base icon
+
+//
+// PT Uniform
+//
+
+/obj/item/clothing/under/iseo/pt
+ name = "pt uniform"
+ desc = "A plain black set of shorts with a navy blue t-shirt. Utiliarian to the extreme. Fitted for both sexes."
+ icon = 'maps/torch/icons/converted_icons/under/under_pt_iseo.dmi'
+
+//
+// Utility
+//
+
+/obj/item/clothing/under/iseo/utility
+ name = "utility fatigues"
+ desc = "A set of black fatigues made from sturdy, durable synthetic fibers used by the ISEO Surveyor Corps. Mildly flash and stain resistant."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_iseo.dmi'
+ siemens_coefficient = 0.8
+ armor = list(
+ melee = ARMOR_MELEE_MINOR,
+ energy = ARMOR_ENERGY_MINOR
+ )
+
+/obj/item/clothing/under/iseo/utility/command
+ desc = "A set of blue fatigues made from sturdy, durable synthetic fibers used by the ISEO Surveyor Corps. Mildly flash and stain resistant."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_iseo_command.dmi'
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/command)
+
+/obj/item/clothing/under/iseo/utility/security
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/security)
+
+/obj/item/clothing/under/iseo/utility/engineering
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/engineering, /obj/item/clothing/accessory/armband/engine)
+
+/obj/item/clothing/under/iseo/utility/supply
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/supply, /obj/item/clothing/accessory/armband/cargo)
+
+/obj/item/clothing/under/iseo/utility/science
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/exploration)
+
+/obj/item/clothing/under/iseo/utility/medical
+ desc = "A set of white fatigues made from sturdy, durable synthetic fibers used by the ISEO Surveyor Corps. Very stain resistant - and sterile."
+ icon = 'maps/torch/icons/converted_icons/under/under_utility_iseo_medical.dmi'
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/medical, /obj/item/clothing/accessory/armband/medblue)
+
+/obj/item/clothing/under/iseo/utility/service
+ starting_accessories = list(/obj/item/clothing/accessory/department/iseo/service)
+
+//
+// Service
+//
+
+/obj/item/clothing/under/iseo/service/uniform
+ name = "service uniform"
+ desc = "A fetching service uniform, with a white dress shirt and blue pants. For all semi-formal and formal occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/uniform/officer
+ desc = "A fetching service uniform, with a white dress shirt and blue pants. For all semi-formal and formal occasions. This one has silver highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_officer_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/uniform/command
+ desc = "A fetching service uniform, with a white dress shirt and blue pants. For all semi-formal and formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_command_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/uniform/flag
+ desc = "A fetching service uniform, with a white dress shirt and blue pants. For all semi-formal and formal occasions. This one has red highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_uniform_flag_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/skirt
+ name = "service skirt"
+ desc = "A fetching service uniform, with a white dress shirt and a blue skirt. For all semi-formal and formal occasions."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/skirt/officer
+ desc = "A fetching service uniform, with a white dress shirt and a blue skirt. For all those semi-formal and formal occasions. This one has silver highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_officer_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/skirt/command
+ desc = "A fetching service uniform, with a white dress shirt and a blue skirt. For all those semi-formal and formal occasions. This one has gold highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_command_iseo.dmi'
+
+/obj/item/clothing/under/iseo/service/skirt/flag
+ desc = "A fetching service uniform, with a white dress shirt and a blue skirt. For all those semi-formal and formal occasions. This one has red highlights."
+ icon = 'maps/torch/icons/converted_icons/under/under_service_skirt_flag_iseo.dmi'
+
+//ISEO use service uniforms as the under for their dress clothing.
+
+
+
+
diff --git a/maps/torch/items/hearth_spacesuits.dm b/maps/torch/items/hearth_spacesuits.dm
new file mode 100644
index 00000000000..9ed922b1f9e
--- /dev/null
+++ b/maps/torch/items/hearth_spacesuits.dm
@@ -0,0 +1,414 @@
+//Engineering Voidsuits
+
+/obj/item/clothing/head/helmet/space/void/engineering/alt/hazard
+ name = "engineering hazard voidsuit helmet"
+ desc = "A heavy, radiation-shielded voidsuit helmet with a surprisingly comfortable interior."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit_helmet.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_RESISTANT,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SHIELDED
+ )
+
+/obj/item/clothing/suit/space/void/engineering/alt/hazard
+ name = "engineering hazard voidsuit"
+ desc = "A bulky industrial voidsuit. An alternate model, this one is up-to-date and includes climate control. Fancy and expensive."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/eng_hazard_hardsuit.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_RESISTANT,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SHIELDED
+ )
+
+//Explo Voidsuits!
+
+/obj/item/clothing/head/helmet/space/void/exploration
+ desc = "An atmos resistant helmet for space and planet exploration. Has a wide visor for superior visibility"
+ name = "exploration voidsuit helmet"
+ icon = 'maps/torch/icons/converted_icons/spacesuits/explo_voidsuit_helmet.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+
+/obj/item/clothing/suit/space/void/exploration
+ desc = "An atmos resistant voidsuit for space and planet exploration."
+ name = "exploration voidsuit"
+ icon = 'maps/torch/icons/converted_icons/spacesuits/explo_voidsuit.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+ allowed = list(/obj/item/flashlight,/obj/item/tank,/obj/item/suit_cooling_unit,/obj/item/storage/toolbox,/obj/item/storage/briefcase/inflatable,/obj/item/t_scanner,/obj/item/rcd,/obj/item/hatchet/machete)
+
+//Command Voidsuit
+
+/obj/item/clothing/head/helmet/space/void/command
+ desc = "A sealed helmet, intended for a spacesuit."
+ name = "command voidsuit helmet"
+ icon = 'maps/torch/icons/converted_icons/spacesuits/command_voidsuit_helmet.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+
+/obj/item/clothing/suit/space/void/command
+ desc = "An atmos resistant voidsuit for protection from hazardous enviroments."
+ name = "command voidsuit"
+ icon = 'maps/torch/icons/converted_icons/spacesuits/command_voidsuit.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_MINOR,
+ laser = ARMOR_LASER_MINOR,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+ allowed = list(/obj/item/flashlight,/obj/item/tank,/obj/item/suit_cooling_unit,/obj/item/storage/toolbox,/obj/item/storage/briefcase/inflatable,/obj/item/t_scanner,/obj/item/rcd,/obj/item/hatchet/machete)
+
+//RIG suits below.
+
+/obj/item/rig/command
+ name = "command HCM"
+ suit_type = "command hardsuit"
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/command_rig.dmi'
+ desc = "A specialized hardsuit rig control module issued to command staff of the ISSC and their peers."
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_SMALL,
+ laser = ARMOR_LASER_MINOR,
+ energy = ARMOR_ENERGY_SMALL,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+ online_slowdown = 0.50
+ offline_slowdown = 2
+ offline_vision_restriction = TINT_HEAVY
+
+ chest = /obj/item/clothing/suit/space/rig/command
+ helmet = /obj/item/clothing/head/helmet/space/rig/command
+ boots = /obj/item/clothing/shoes/magboots/rig/command
+ gloves = /obj/item/clothing/gloves/rig/command
+
+ allowed = list(/obj/item/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/flashlight,
+ /obj/item/tank,
+ /obj/item/suit_cooling_unit,
+ /obj/item/storage/secure/briefcase)
+
+ req_access = list(access_bridge)
+
+/obj/item/clothing/head/helmet/space/rig/command
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/command_rig.dmi'
+ camera = /obj/machinery/camera/network/command
+ //species_restricted = list(SPECIES_HUMAN,SPECIES_IPC) //no available icons for aliens
+
+/obj/item/clothing/suit/space/rig/command
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/command_rig.dmi'
+ //species_restricted = list(SPECIES_HUMAN,SPECIES_IPC)
+
+/obj/item/clothing/shoes/magboots/rig/command
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/boots/command_rigs.dmi'
+ //species_restricted = list(SPECIES_HUMAN,SPECIES_IPC)
+
+/obj/item/clothing/gloves/rig/command
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/hands/command_rigs.dmi'
+ //species_restricted = list(SPECIES_HUMAN,SPECIES_IPC)
+
+/obj/item/rig/command/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash,
+ /obj/item/rig_module/cooling_unit
+ )
+
+/*
+ * EXECUTIVE OFFICER
+ */
+/obj/item/rig/command/xo
+ name = "officer's command HCM"
+ suit_type = "advanced command hardsuit"
+ desc = "A specialized hardsuit rig control module issued to high ranking officers of the ISSC and their peers."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/xo_rig.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_SMALL,
+ laser = ARMOR_LASER_MINOR,
+ energy = ARMOR_ENERGY_SMALL,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+
+ chest = /obj/item/clothing/suit/space/rig/command/xo
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/xo
+ boots = /obj/item/clothing/shoes/magboots/rig/command
+ gloves = /obj/item/clothing/gloves/rig/command
+
+ req_access = list(access_hop)
+
+/obj/item/clothing/head/helmet/space/rig/command/xo
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/xo_rig.dmi'
+/obj/item/clothing/suit/space/rig/command/xo
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/xo_rig.dmi'
+
+/obj/item/rig/command/xo/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash/advanced,
+ /obj/item/rig_module/grenade_launcher/smoke,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+ * COMMANDING OFFICER
+ */
+/obj/item/rig/command/co
+ name = "commanding officer's command HCM"
+ suit_type = "advanced command hardsuit"
+ desc = "A specialized hardsuit rig control module issued to commanding officers of the ISSC."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/co_rig.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_RESISTANT,
+ bullet = ARMOR_BALLISTIC_PISTOL,
+ laser = ARMOR_LASER_SMALL,
+ energy = ARMOR_ENERGY_SMALL,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+
+ chest = /obj/item/clothing/suit/space/rig/command/co
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/co
+
+ req_access = list(access_captain)
+
+/obj/item/clothing/head/helmet/space/rig/command/co
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/co_rig.dmi'
+/obj/item/clothing/suit/space/rig/command/co
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/co_rig.dmi'
+
+/obj/item/rig/command/co/equipped
+ initial_modules = list(
+ /obj/item/rig_module/ai_container,
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash/advanced,
+ /obj/item/rig_module/grenade_launcher/smoke,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+ * CHIEF MEDICAL OFFICER
+ */
+/obj/item/rig/command/medical
+ name = "medical command HCM"
+ suit_type = "medical command hardsuit"
+ desc = "A specialized hardsuit rig control module issued to ranking medical officers of the ISSC and their peers."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/cmo_rig.dmi'
+
+ chest = /obj/item/clothing/suit/space/rig/command/medical
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/medical
+
+ allowed = list(/obj/item/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/flashlight,
+ /obj/item/tank,
+ /obj/item/suit_cooling_unit,
+ /obj/item/storage/firstaid,
+ /obj/item/scanner/health,
+ /obj/item/stack/medical,
+ /obj/item/roller)
+
+ req_access = list(access_cmo)
+
+/obj/item/clothing/head/helmet/space/rig/command/medical
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/cmo_rig.dmi'
+/obj/item/clothing/suit/space/rig/command/medical
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/cmo_rig.dmi'
+
+/obj/item/rig/command/medical/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash,
+ /obj/item/rig_module/device/healthscanner,
+ /obj/item/rig_module/device/defib,
+ /obj/item/rig_module/chem_dispenser/injector,
+ /obj/item/rig_module/vision/medhud,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+* CHIEF OF SECURITY
+*/
+/obj/item/rig/command/security
+ name = "security command HCM"
+ suit_type = "security command hardsuit"
+ desc = "A specialized hardsuit rig control module issued to ranking security officers of the ISSC and their peers."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/cso_rig.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_RESISTANT,
+ bullet = ARMOR_BALLISTIC_PISTOL,
+ laser = ARMOR_LASER_SMALL,
+ energy = ARMOR_ENERGY_SMALL,
+ bomb = ARMOR_BOMB_PADDED,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SMALL
+ )
+
+ chest = /obj/item/clothing/suit/space/rig/command/security
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/security
+
+ allowed = list(/obj/item/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/handcuffs,
+ /obj/item/flashlight,
+ /obj/item/tank,
+ /obj/item/suit_cooling_unit,
+ /obj/item/baton)
+
+ req_access = list(access_hos)
+
+/obj/item/clothing/head/helmet/space/rig/command/security
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/hos_rig.dmi'
+/obj/item/clothing/suit/space/rig/command/security
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/cso_rig.dmi'
+
+/obj/item/rig/command/security/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash,
+ /obj/item/rig_module/vision/sechud,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+* CHIEF SCIENCE OFFICER
+*/
+/obj/item/rig/command/science
+ name = "research command HCM"
+ suit_type = "research command hardsuit"
+ desc = "A specialized hardsuit rig control module issued to ranking research officers of the ISSC."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/cso_rig.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_KNIVES,
+ bullet = ARMOR_BALLISTIC_SMALL,
+ laser = ARMOR_LASER_MINOR,
+ energy = ARMOR_ENERGY_STRONG,
+ bomb = ARMOR_BOMB_RESISTANT,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SHIELDED
+ )
+
+ chest = /obj/item/clothing/suit/space/rig/command/science
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/science
+
+ allowed = list(/obj/item/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/flashlight,
+ /obj/item/tank,
+ /obj/item/suit_cooling_unit,
+ /obj/item/stack/flag,
+ /obj/item/storage/excavation,
+ /obj/item/scanner/health,
+ /obj/item/measuring_tape,
+ /obj/item/ano_scanner,
+ /obj/item/depth_scanner,
+ /obj/item/core_sampler,
+ /obj/item/gps,
+ /obj/item/pinpointer/radio,
+ /obj/item/radio/beacon,
+ /obj/item/pickaxe/xeno,
+ /obj/item/storage/bag/fossils,
+ /obj/item/rig_module/grenade_launcher/light)
+
+ req_access = list(access_rd)
+
+/obj/item/clothing/head/helmet/space/rig/command/science
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/cso_rig.dmi'
+
+/obj/item/clothing/suit/space/rig/command/science
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/cso_rig.dmi'
+
+
+/obj/item/rig/command/science/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash,
+ /obj/item/rig_module/device/anomaly_scanner,
+ /obj/item/rig_module/grenade_launcher/light,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+* EXPLORATION
+*/
+/obj/item/rig/exploration
+ name = "heavy exploration HCM"
+ suit_type = "heavy exploration hardsuit"
+ desc = "Expeditionary Corps' Exoplanet Exploration Armored Unit, A-Unit for short. Built for more hostile (and hungry) environments, it features additional armor and powered exoskeleton."
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/module/explo_rig.dmi'
+ armor = list(
+ melee = ARMOR_MELEE_MAJOR,
+ bullet = ARMOR_BALLISTIC_SMALL,
+ laser = ARMOR_LASER_SMALL,
+ energy = ARMOR_ENERGY_RESISTANT,
+ bomb = ARMOR_BOMB_MINOR,
+ bio = ARMOR_BIO_SHIELDED,
+ rad = ARMOR_RAD_SHIELDED
+ )
+
+ chest = /obj/item/clothing/suit/space/rig/command/exploration
+ helmet = /obj/item/clothing/head/helmet/space/rig/command/exploration
+ boots = /obj/item/clothing/shoes/magboots/rig/command/exploration
+ gloves = /obj/item/clothing/gloves/rig/command/exploration
+
+ allowed = list(/obj/item/gun,
+ /obj/item/ammo_magazine,
+ /obj/item/flashlight,
+ /obj/item/tank,
+ /obj/item/suit_cooling_unit)
+
+ online_slowdown = 0.50
+ offline_slowdown = 4
+ offline_vision_restriction = TINT_BLIND
+
+/obj/item/clothing/head/helmet/space/rig/command/exploration
+ camera = /obj/machinery/camera/network/exploration
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/head/explo_rig.dmi'
+ brightness_on = 0.8
+
+/obj/item/clothing/suit/space/rig/command/exploration
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/body/explo_rig.dmi'
+
+/obj/item/clothing/gloves/rig/command/exploration
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/hands/explo_rig.dmi'
+
+/obj/item/clothing/shoes/magboots/rig/command/exploration
+ icon = 'maps/torch/icons/converted_icons/spacesuits/rigs/boots/explo_rig.dmi'
+
+/obj/item/rig/exploration/equipped
+ initial_modules = list(
+ /obj/item/rig_module/maneuvering_jets,
+ /obj/item/rig_module/device/flash,
+ /obj/item/rig_module/device/anomaly_scanner,
+ /obj/item/rig_module/grenade_launcher/light,
+ /obj/item/rig_module/cooling_unit)
+
+/*
+ Overrides for standard mapset rig items
+ */
+
+/obj/item/clothing/head/helmet/space/rig/industrial
+ camera = /obj/machinery/camera/network/supply
+
diff --git a/maps/torch/items/items.dm b/maps/torch/items/items.dm
new file mode 100644
index 00000000000..a7a40cf994d
--- /dev/null
+++ b/maps/torch/items/items.dm
@@ -0,0 +1,174 @@
+/*******************
+Random item spawning
+*******************/
+
+/obj/random/solgov
+ name = "random iseo equipment"
+ desc = "This is a random piece of iseo equipment or clothing."
+ icon = 'maps/torch/icons/obj/obj_head_solgov.dmi'
+ icon_state = "solsoft"
+
+/obj/random/solgov/spawn_choices()
+ return list(/obj/item/clothing/head/espatier/utility/tan = 4,
+ /obj/item/clothing/head/iseo/utility = 2,
+ /obj/item/clothing/head/espatier/utility= 4,
+ /obj/item/clothing/head/helmet = 1,
+ /obj/item/clothing/suit/armor/vest/government/sec = 2,
+ /obj/item/clothing/under/iseo/utility = 5,
+ /obj/item/clothing/under/espatier/utility = 3,
+ /obj/item/clothing/under/espatier/pt = 4,
+ /obj/item/clothing/under/iseo/pt= 4
+ )
+
+/obj/random/maintenance/solgov
+ name = "random maintenance item"
+ desc = "This is a random maintenance item."
+ icon = 'icons/obj/items/gift_wrapped.dmi'
+ icon_state = "gift1"
+
+/obj/random/maintenance/solgov/spawn_choices()
+ return list(/obj/random/junk = 4,
+ /obj/random/trash = 4,
+ /obj/random/maintenance/solgov/clean = 5)
+
+/obj/random/maintenance/solgov/clean
+ name = "random maintenance item"
+ desc = "This is a random maintenance item."
+ icon = 'icons/obj/items/gift_wrapped.dmi'
+ icon_state = "gift2"
+
+/obj/random/maintenance/solgov/clean/spawn_choices()
+ return list(/obj/random/solgov = 3,
+ /obj/random/maintenance/clean = 800)
+
+/*******************
+Torch specific items
+*******************/
+
+/obj/item/modular_computer/pda/explorer
+ icon_state = "pda-exp"
+ //icon_state_unpowered = "pda-exp"
+
+/obj/item/modular_computer/pda/heads/hop
+ stored_pen = /obj/item/pen/multi/cmd/xo
+
+/obj/item/modular_computer/pda/captain
+ stored_pen = /obj/item/pen/multi/cmd/co
+
+/obj/item/storage/backpack/explorer
+ name = "explorer backpack"
+ desc = "A rugged backpack."
+ icon_state = "exppack"
+
+/obj/item/storage/backpack/satchel/explorer
+ name = "explorer satchel"
+ desc = "A rugged satchel for field work."
+ icon_state = "satchel-exp"
+
+/obj/item/storage/backpack/messenger/explorer
+ name = "explorer messenger bag"
+ desc = "A rugged backpack worn over one shoulder."
+ icon_state = "courierbagexp"
+
+/***********
+Unique items
+***********/
+
+/obj/item/pen/multi/cmd/xo
+ name = "executive officer's pen"
+ icon = 'maps/torch/icons/obj/uniques.dmi'
+ icon_state = "pen_xo"
+ desc = "A slightly bulky pen with a silvery case. Twisting the top allows you to switch the nib for different colors."
+
+/obj/item/pen/multi/cmd/co
+ name = "commanding officer's pen"
+ icon = 'maps/torch/icons/obj/uniques.dmi'
+ icon_state = "pen_co"
+ desc = "A slightly bulky pen with a golden case. Twisting the top allows you to switch the nib for different colors."
+
+/obj/item/pen/multi/cmd/attack_self(mob/user)
+ if(++selectedColor > 3)
+ selectedColor = 1
+ colour = colors[selectedColor]
+ to_chat(user, "Changed color to '[colour].'")
+
+/******
+Weapons
+******/
+
+/obj/item/gun/energy/gun/small/secure/corporate
+ desc = "An access-locked EXO-branded LAEP90-CS. It's designed to please paranoid corporate liaisons. Body cam not included."
+ req_access = list(access_liaison)
+
+/obj/item/gun/projectile/revolver/medium/captain
+ name = "Final Argument"
+ icon = 'maps/torch/icons/obj/uniques.dmi'
+ icon_state = "mosley"
+ desc = "A shiny al-Maliki & Mosley Autococker automatic revolver, with black accents. Marketed as the 'Revolver for the Modern Era'. This one has 'To the Captain of ISEO Endeavour' engraved."
+ fire_delay = 5.7 //Autorevolver. Also synced with the animation
+ fire_anim = "mosley_fire"
+ origin_tech = "{'combat':3,'materials':3}"
+ starts_loaded = 0 //Nobody keeps ballistic weapons loaded
+
+/obj/item/gun/energy/stunrevolver/secure/nanotrasen
+ name = "corporate stun revolver"
+ desc = "This A&M X6 is fitted with an NT1019 chip which allows remote authorization of weapon functionality. It has a NanoTrasen logo on the grip."
+ req_access = list(list(access_brig, access_heads, access_rd, access_sec_guard))
+
+/obj/item/gun/projectile/pistol/holdout/liaison
+ magazine_type = /obj/item/ammo_magazine/pistol/small/oneway
+
+/obj/item/ammo_magazine/pistol/small/oneway
+ initial_ammo = 1
+
+/obj/effect/paint/hull
+ color = COLOR_HULL
+
+/obj/effect/paint/expeditionary
+ color = "#68099e"
+
+/obj/item/gun/projectile/service_carbine
+ name = "service carbine"
+ desc = "The Zendai Armories MS2-A 'Legate' is a medium-caliber service carbine utilized across human-controlled space. Fires 10mm rounds."
+ icon = 'maps/torch/icons/obj/carbine.dmi'
+ fire_delay = 3
+ origin_tech = "{'combat':3,'materials':3}"
+ starts_loaded = 0
+ caliber = CALIBER_RIFLE
+ ammo_type = /obj/item/ammo_casing/pistol
+ slot_flags = SLOT_BACK
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/carbine
+ allowed_magazines = /obj/item/ammo_magazine/carbine
+ one_hand_penalty = 8
+ bulk = GUN_BULK_RIFLE
+ mag_insert_sound = 'sound/weapons/guns/interaction/batrifle_magin.ogg'
+ mag_remove_sound = 'sound/weapons/guns/interaction/batrifle_magout.ogg'
+ material = /decl/material/solid/metal/steel
+ matter = list(
+ /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT,
+ /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE
+ )
+
+/obj/item/gun/projectile/service_carbine/update_base_icon()
+ if(ammo_magazine)
+ if(ammo_magazine.stored_ammo.len)
+ icon_state = "[get_world_inventory_state()]-loaded"
+ else
+ icon_state = "[get_world_inventory_state()]-empty"
+ else
+ icon_state = get_world_inventory_state()
+
+/obj/item/ammo_magazine/carbine
+ name = "carbine magazine"
+ icon_state = "bullup"
+ origin_tech = "{'combat':2}"
+ mag_type = MAGAZINE
+ caliber = CALIBER_RIFLE
+ material = /decl/material/solid/metal/steel
+ ammo_type = /obj/item/ammo_casing/pistol
+ max_ammo = 20 //if we lived in a world where normal mags had 30 rounds, this would be a 20 round mag
+ multiple_sprites = 1
+
+
+
diff --git a/maps/torch/items/machinery.dm b/maps/torch/items/machinery.dm
new file mode 100644
index 00000000000..308cfa3738a
--- /dev/null
+++ b/maps/torch/items/machinery.dm
@@ -0,0 +1,91 @@
+//Shouldn't be a lot in here, only torch versions of existing machines that need a different access req or something along those lines.
+
+/obj/machinery/vending/medical/torch
+ req_access = list(access_medical)
+
+/obj/machinery/drone_fabricator/torch
+ fabricator_tag = "ISEO Endeavour Maintenance"
+
+/obj/machinery/drone_fabricator/torch/adv
+ name = "advanced drone fabricator"
+ fabricator_tag = "SFV Arrow Maintenance"
+ drone_type = /mob/living/silicon/robot/drone/construction
+
+//telecommunications gubbins for torch-specific networks
+
+/obj/machinery/telecomms/hub/preset
+ id = "Hub"
+ network = "tcommsat"
+ autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "b_relay", "1_relay", "2_relay", "3_relay", "4_relay", "5_relay", "s_relay", "science", "medical",
+ "supply", "service", "common", "command", "engineering", "security", "exploration", "receiverA", "broadcasterA")
+
+/obj/machinery/telecomms/receiver/preset_right
+ freq_listening = list(AI_FREQ, SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ, ENT_FREQ, EXP_FREQ, MED_I_FREQ, SEC_I_FREQ)
+
+/obj/machinery/telecomms/bus/preset_two
+ freq_listening = list(SUP_FREQ, SRV_FREQ, EXP_FREQ)
+ autolinkers = list("processor2", "supply", "service", "exploration")
+
+/obj/machinery/telecomms/server/presets/service
+ id = "Service Server"
+ freq_listening = list(SRV_FREQ)
+ channel_tags = list(
+ list(SRV_FREQ, "Service", COMMS_COLOR_SERVICE),
+ )
+ autolinkers = list("service")
+
+/obj/machinery/telecomms/server/presets/exploration
+ id = "Exploration Server"
+ freq_listening = list(EXP_FREQ)
+ channel_tags = list(list(EXP_FREQ, "Exploration", COMMS_COLOR_EXPLORER))
+ autolinkers = list("exploration")
+
+// Suit cyclers and storage
+/obj/machinery/suit_cycler/exploration
+ name = "Exploration suit cycler"
+ model_text = "Exploration"
+ req_access = list(access_explorer)
+ /*
+ available_modifications = list(/decl/item_modifier/space_suit/explorer)
+ species = list(SPECIES_HUMAN,SPECIES_SKRELL,SPECIES_UNATHI)
+ */
+ suit = /obj/item/clothing/suit/space/void/exploration
+ helmet = /obj/item/clothing/head/helmet/space/void/exploration
+ boots = /obj/item/clothing/shoes/magboots
+ //tank = /obj/item/tank/oxygen
+ //mask = /obj/item/clothing/mask/breath
+ req_access = list(access_explorer)
+ locked = TRUE
+
+/obj/machinery/suit_cycler/pilot
+ name = "Pilot Voidsuit Storage Unit"
+ suit = /obj/item/clothing/suit/space/void/pilot
+ helmet = /obj/item/clothing/head/helmet/space/void/pilot
+ boots = /obj/item/clothing/shoes/magboots
+ //tank = /obj/item/tank/oxygen
+ //mask = /obj/item/clothing/mask/breath
+ req_access = list(access_pilot)
+ locked = TRUE
+
+/obj/machinery/suit_cycler/command
+ name = "Command Voidsuit Storage Unit"
+ suit = /obj/item/clothing/suit/space/void/command
+ helmet = /obj/item/clothing/head/helmet/space/void/command
+ boots = /obj/item/clothing/shoes/magboots
+ //tank = /obj/item/tank/oxygen
+ //mask = /obj/item/clothing/mask/breath
+ req_access = list(access_bridge, access_keycard_auth)
+ locked = TRUE
+
+// Vending machines & dispensers
+/obj/machinery/vending/security
+ products = list(
+ /obj/item/handcuffs = 14,
+ /obj/item/grenade/flashbang = 4,
+ /obj/item/grenade/chem_grenade/teargas = 4,
+ /obj/item/flash = 7,
+ /obj/item/chems/spray/pepper = 4,
+ /obj/item/holowarrant = 4,
+ /obj/item/chems/food/donut/normal = 12,
+ /obj/item/storage/box/evidence = 8,
+ /obj/item/clothing/accessory/badge/maa = 6)
diff --git a/maps/torch/items/manuals.dm b/maps/torch/items/manuals.dm
new file mode 100644
index 00000000000..4dbb3163fd3
--- /dev/null
+++ b/maps/torch/items/manuals.dm
@@ -0,0 +1,156 @@
+/obj/item/book/manual/solgov_law
+ name = "Sol Central Government Law"
+ desc = "A brief overview of SolGov Law."
+ icon_state = "bookSolGovLaw"
+ author = "The Sol Central Government"
+ title = "Sol Central Government Law"
+
+/obj/item/book/manual/solgov_law/Initialize()
+ . = ..()
+ dat = {"
+
+
+
+
+
+
+