")
+
+// colors for faction alert overrides, used for admin menus
+#define faction_alert_colors list("default", "green", "blue", "pink", "yellow", "orange", "red", "purple", "grey")
+
+/**
+ * Design a faction alert. Returns a string.
+ *
+ * Arguments
+ * * title - required, the title to use for this alert
+ * * subtitle - optional, the subtitle/subheader to use for this alert
+ * * message - required, the message to use for this alert
+ * * color_override - optional, the color to use for this alert instead of blue
+ * * minor - is this a minor alert?
+ */
+/proc/assemble_alert(title, subtitle, message, color_override, minor = FALSE)
+ if(!title || !message)
+ return
-/proc/priority_announce(message, title = "Announcement", type = ANNOUNCEMENT_REGULAR, sound = 'sound/misc/notice2.ogg', list/receivers = (GLOB.alive_human_list + GLOB.ai_list + GLOB.observer_list))
+ var/list/alert_strings = list()
+ var/header
+ var/finalized_alert
+ header = minor ? span_faction_alert_minortitle(title) : span_faction_alert_title(title)
+
+ if(subtitle)
+ header += span_faction_alert_subtitle(subtitle)
+
+ alert_strings += span_alert_header(header)
+ alert_strings += span_faction_alert_text(message)
+
+ if(color_override)
+ finalized_alert = faction_alert_colored_span(color_override, jointext(alert_strings, ""))
+ else
+ finalized_alert = faction_alert_default_span(jointext(alert_strings, ""))
+
+ return finalized_alert
+
+/**
+ * Make a priority announcement to a target
+ *
+ * Arguments
+ * * message - **required,** the content of the announcement
+ * * title - optional, the title of the announcement
+ * * subtitle - optional, the subtitle/subheader of the announcement
+ * * type - optional, the type of the announcement (see defines in `__HELPERS/announce.dm`)
+ * * sound - optional, the sound played accompanying the announcement
+ * * channel_override - optional, what channel is this sound going to be played on?
+ * * color_override - **recommended,** string, use the passed color instead of the default blue (see defines in `__HELPERS/announce.dm`)
+ * * receivers - a list of all players to send the message to. defaults to all players, not including those in lobby
+ */
+/proc/priority_announce(message, title = "Announcement", subtitle = "", type = ANNOUNCEMENT_REGULAR, sound = 'sound/misc/notice2.ogg', channel_override = CHANNEL_ANNOUNCEMENTS, color_override, list/receivers = (GLOB.alive_human_list + GLOB.ai_list + GLOB.observer_list))
if(!message)
return
- var/announcement
+ // header/subtitle to use when using assemble_alert()
+ var/assembly_header
+ var/assembly_subtitle
switch(type)
if(ANNOUNCEMENT_REGULAR)
- announcement += "
[html_encode(title)]
"
+ assembly_header = title
if(ANNOUNCEMENT_PRIORITY)
- announcement += "
"
-
-
- announcement += " [span_alert("[html_encode(message)]")] "
- announcement += " "
-
- var/s = sound(sound, channel = CHANNEL_ANNOUNCEMENTS)
+ assembly_header = "Command Announcement"
+
+ if(subtitle && type != ANNOUNCEMENT_PRIORITY)
+ assembly_subtitle = subtitle
+
+ var/finalized_announcement
+ if(color_override)
+ finalized_announcement = assemble_alert(
+ title = assembly_header,
+ subtitle = assembly_subtitle,
+ message = message,
+ color_override = color_override
+ )
+ else
+ finalized_announcement = assemble_alert(
+ title = assembly_header,
+ subtitle = assembly_subtitle,
+ message = message
+ )
+
+ var/s = sound(sound, channel = channel_override)
for(var/i in receivers)
var/mob/M = i
if(!isnewplayer(M))
- to_chat(M, announcement)
+ to_chat(M, finalized_announcement)
SEND_SOUND(M, s)
@@ -46,8 +126,16 @@
P.info = papermessage
P.update_icon()
-
-/proc/minor_announce(message, title = "Attention:", alert, list/receivers = GLOB.alive_human_list)
+/**
+ * Make a minor announcement to a target
+ *
+ * Arguments
+ * * message - required, this is the announcement message
+ * * title - optional, the title of the announcement
+ * * alert - optional, alert or notice?
+ * * receivers - a list of all players to send the message to
+ */
+/proc/minor_announce(message, title = "Attention:", alert, list/receivers = GLOB.alive_human_list, should_play_sound = TRUE)
if(!message)
return
@@ -55,5 +143,18 @@
S.channel = CHANNEL_ANNOUNCEMENTS
for(var/mob/M AS in receivers)
if(!isnewplayer(M) && !isdeaf(M))
- to_chat(M, "[html_encode(title)] [html_encode(message)] ")
- SEND_SOUND(M, S)
+ to_chat(M, assemble_alert(
+ title = title,
+ message = message,
+ minor = TRUE
+ ))
+ if(should_play_sound)
+ SEND_SOUND(M, S)
+
+#undef span_alert_header
+#undef span_faction_alert_title
+#undef span_faction_alert_minortitle
+#undef span_faction_alert_subtitle
+#undef span_faction_alert_text
+#undef faction_alert_default_span
+#undef faction_alert_colored_span
diff --git a/code/__HELPERS/datums.dm b/code/__HELPERS/datums.dm
new file mode 100644
index 0000000000000..7cf87c203b736
--- /dev/null
+++ b/code/__HELPERS/datums.dm
@@ -0,0 +1,9 @@
+///Check if a datum has not been deleted and is a valid source
+/proc/is_valid_src(datum/source_datum)
+ if(istype(source_datum))
+ return !QDELETED(source_datum)
+ return FALSE
+
+/proc/call_async(datum/source, proc_type, list/arguments)
+ set waitfor = FALSE
+ return call(source, proc_type)(arglist(arguments))
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index d29ff6dfdab30..6387ca4f6e1f1 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -41,14 +41,6 @@
return ERROR_NO_SUPPORT
return NO_ERROR
-/proc/trange(rad = 0, turf/centre = null) //alternative to range (ONLY processes turfs and thus less intensive)
- if(!centre)
- return
-
- var/turf/x1y1 = locate(((centre.x - rad) < 1 ? 1 : centre.x - rad), ((centre.y-rad) < 1 ? 1 : centre.y - rad), centre.z)
- var/turf/x2y2 = locate(((centre.x + rad) > world.maxx ? world.maxx : centre.x + rad), ((centre.y + rad) > world.maxy ? world.maxy : centre.y + rad), centre.z)
- return block(x1y1, x2y2)
-
// Same as above but for alien candidates.
/proc/get_alien_candidate()
var/mob/dead/observer/picked
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 668b273e5cb2c..18a6a5d991780 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -955,21 +955,19 @@ ColorTone(rgb, tone)
/proc/generate_asset_name(file)
return "asset.[md5(fcopy_rsc(file))]"
-//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
-// exporting it as text, and then parsing the base64 from that.
-// (This relies on byond automatically storing icons in savefiles as base64)
+/**
+ * Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
+ * exporting it as text, and then parsing the base64 from that.
+ * (This relies on byond automatically storing icons in savefiles as base64)
+ */
/proc/icon2base64(icon/icon)
if(!isicon(icon))
return FALSE
- var/savefile/dummySave = new("tmp/dummySave.sav")
+ var/savefile/dummySave = new
WRITE_FILE(dummySave["dummy"], icon)
var/iconData = dummySave.ExportText("dummy")
var/list/partial = splittext(iconData, "{")
- . = replacetext(copytext_char(partial[2], 3, -5), "\n", "") //if cleanup fails we want to still return the correct base64
- dummySave.Unlock()
- dummySave = null
- fdel("tmp/dummySave.sav") //if you get the idea to try and make this more optimized, make sure to still call unlock on the savefile after every write to unlock it.
-
+ return replacetext(copytext_char(partial[2], 3, -5), "\n", "") //if cleanup fails we want to still return the correct base64
///given a text string, returns whether it is a valid dmi icons folder path
/proc/is_valid_dmi_file(icon_path)
@@ -1086,7 +1084,7 @@ ColorTone(rgb, tone)
if (isnull(icon_state))
icon_state = thing.icon_state
//Despite casting to atom, this code path supports mutable appearances, so let's be nice to them
- if(isnull(icon_state) || (isatom(thing) && thing.flags_atom & HTML_USE_INITAL_ICON_1))
+ if(isnull(icon_state) || (isatom(thing) && thing.atom_flags & HTML_USE_INITAL_ICON_1))
icon_state = initial(thing.icon_state)
if (isnull(dir))
dir = initial(thing.dir)
diff --git a/code/__HELPERS/jatum.dm b/code/__HELPERS/jatum.dm
index ff0643f071225..cb1d0f83485fa 100644
--- a/code/__HELPERS/jatum.dm
+++ b/code/__HELPERS/jatum.dm
@@ -125,7 +125,7 @@
json_structure["jatum\\new_arglist"] = _jatum_serialize_value(new_arglist, seen_references)
for(var/var_name in D.vars)
- if(var_name == "vars" || var_name == "parent_type" || var_name == "type")
+ if(var_name == "vars" || var_name == "parent_type" || var_name == "type" || var_name == "open_uis")
continue
var/d_value = D.vars[var_name]
diff --git a/code/__HELPERS/logging/attack.dm b/code/__HELPERS/logging/attack.dm
index 0dc3ab17e60c9..9cca53a23f349 100644
--- a/code/__HELPERS/logging/attack.dm
+++ b/code/__HELPERS/logging/attack.dm
@@ -33,12 +33,12 @@
var/postfix = "[sobject][saddition][hp]"
var/message = "[what_done] [starget][postfix]"
- user.log_message(message, LOG_ATTACK, color="red")
+ user?.log_message(message, LOG_ATTACK, color="red")
//if(user != target) // ORIGINAL
if(target && user != target) // RUTMGC EDITION
var/reverse_message = "was [what_done] by [ssource][postfix]"
- target.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE)
+ target?.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE)
/// Logging for bombs detonating
/proc/log_bomber(atom/user, details, atom/bomb, additional_details, message_admins = FALSE)
diff --git a/code/__HELPERS/math.dm b/code/__HELPERS/math.dm
index 31a1f2c098ac7..9f239e0daaf2e 100644
--- a/code/__HELPERS/math.dm
+++ b/code/__HELPERS/math.dm
@@ -49,7 +49,7 @@
for(var/obj/stuff_in_turf in to_turf)
if(!stuff_in_turf.opacity)
continue
- if(!CHECK_BITFIELD(stuff_in_turf.flags_atom, ON_BORDER))
+ if(!CHECK_BITFIELD(stuff_in_turf.atom_flags, ON_BORDER))
return FALSE
if(ISDIAGONALDIR(stuff_in_turf.dir))
return FALSE
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 65eb16b1b36af..ed5fbb89cc985 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -42,6 +42,13 @@
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
+/**
+ * Shear the transform on either or both axes.
+ * * x - X axis shearing
+ * * y - Y axis shearing
+ */
+/matrix/proc/Shear(x, y)
+ return Multiply(matrix(1, x, 0, y, 1, 0))
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index e6d8c69878529..89160bdb2cc1e 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -157,9 +157,11 @@
/proc/deadchat_broadcast(message, source = null, mob/follow_target = null, turf/turf_target = null, speaker_key = null, message_type = DEADCHAT_REGULAR)
message = span_deadsay("[source][span_linkify("[message]")]")
for(var/mob/M in GLOB.player_list)
+ if(!M.client)
+ continue
var/chat_toggles = TOGGLES_CHAT_DEFAULT
var/deadchat_toggles = TOGGLES_DEADCHAT_DEFAULT
- if(M.client.prefs)
+ if(M?.client?.prefs)
var/datum/preferences/prefs = M.client.prefs
chat_toggles = prefs.toggles_chat
deadchat_toggles = prefs.toggles_deadchat
diff --git a/code/__HELPERS/pronouns.dm b/code/__HELPERS/pronouns.dm
index 2c0382648dbe9..140baaac15a60 100644
--- a/code/__HELPERS/pronouns.dm
+++ b/code/__HELPERS/pronouns.dm
@@ -245,7 +245,7 @@
//humans need special handling, because they can have their gender hidden
/mob/living/carbon/human/p_they(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -253,7 +253,7 @@
/mob/living/carbon/human/p_their(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -261,7 +261,7 @@
/mob/living/carbon/human/p_them(capitalized, temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -269,7 +269,7 @@
/mob/living/carbon/human/p_have(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -277,7 +277,7 @@
/mob/living/carbon/human/p_are(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -285,7 +285,7 @@
/mob/living/carbon/human/p_were(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -293,7 +293,7 @@
/mob/living/carbon/human/p_do(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -301,7 +301,7 @@
/mob/living/carbon/human/p_s(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
@@ -309,7 +309,7 @@
/mob/living/carbon/human/p_es(temp_gender)
var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask?.flags_inv_hide & HIDEFACE || head?.flags_inv_hide & HIDEFACE)
+ var/skipface = (wear_mask?.inv_hide_flags & HIDEFACE || head?.inv_hide_flags & HIDEFACE)
if((SLOT_W_UNIFORM & obscured) && skipface)
temp_gender = PLURAL
return ..()
diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm
index a351e6f74994a..64cc762b92893 100644
--- a/code/__HELPERS/spatial_info.dm
+++ b/code/__HELPERS/spatial_info.dm
@@ -35,9 +35,9 @@
/mob/oranges_ear/Initialize(mapload)
SHOULD_CALL_PARENT(FALSE)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("Warning: [src]([type]) initialized multiple times!")
- flags_atom |= INITIALIZED
+ atom_flags |= INITIALIZED
return INITIALIZE_HINT_NORMAL
/mob/oranges_ear/Destroy(force)
diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
new file mode 100644
index 0000000000000..0829b3dc8d0e7
--- /dev/null
+++ b/code/__HELPERS/traits.dm
@@ -0,0 +1,44 @@
+#define TRAIT_CALLBACK_ADD(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitAdd), ##target, ##trait, ##source)
+#define TRAIT_CALLBACK_REMOVE(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitRemove), ##target, ##trait, ##source)
+
+///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback.
+/proc/___TraitAdd(target, trait, source)
+ if(!target || !trait || !source)
+ return
+
+ if(islist(target))
+ for(var/datum/listed_target in target)
+ ADD_TRAIT(listed_target, trait, source)
+ return
+
+ ASSERT(isdatum(target), "Invalid target used in TRAIT_CALLBACK_ADD! Expected a datum reference, got [target] instead.")
+
+ var/datum/datum_target = target
+ ADD_TRAIT(datum_target, trait, source)
+
+///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback.
+/proc/___TraitRemove(target, trait, source)
+ if(!target || !trait || !source)
+ return
+
+ if(islist(target))
+ for(var/datum/listed_target in target)
+ REMOVE_TRAIT(listed_target, trait, source)
+ return
+
+ ASSERT(isdatum(target), "Invalid target used in TRAIT_CALLBACK_REMOVE! Expected a datum reference, got [target] instead.")
+
+ var/datum/datum_target = target
+ REMOVE_TRAIT(datum_target, trait, source)
+
+/// Proc that handles adding multiple traits to a target via a list. Must have a common source and target.
+/datum/proc/add_traits(list/list_of_traits, source)
+ ASSERT(islist(list_of_traits), "Invalid arguments passed to add_traits! Invoked on [src] with [list_of_traits], source being [source].")
+ for(var/trait in list_of_traits)
+ ADD_TRAIT(src, trait, source)
+
+/// Proc that handles removing multiple traits from a target via a list. Must have a common source and target.
+/datum/proc/remove_traits(list/list_of_traits, source)
+ ASSERT(islist(list_of_traits), "Invalid arguments passed to remove_traits! Invoked on [src] with [list_of_traits], source being [source].")
+ for(var/trait in list_of_traits)
+ REMOVE_TRAIT(src, trait, source)
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 6f52ce997359a..76b1c1e65ac45 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -5,83 +5,6 @@
return splittext(trim(file2text(filename)),seperator)
return splittext(file2text(filename),seperator)
-//Returns an integer given a hex input
-/proc/hex2num(hex)
- if(!istext(hex))
- return
-
- var/num = 0
- var/power = 0
- var/i = length(hex)
-
- while(i > 0)
- var/char = copytext(hex, i, i + 1)
- switch(char)
- if("9", "8", "7", "6", "5", "4", "3", "2", "1")
- num += text2num(char) * 16 ** power
- if("a", "A")
- num += 16 ** power * 10
- if("b", "B")
- num += 16 ** power * 11
- if("c", "C")
- num += 16 ** power * 12
- if("d", "D")
- num += 16 ** power * 13
- if("e", "E")
- num += 16 ** power * 14
- if("f", "F")
- num += 16 ** power * 15
- else
- return
- power++
- i--
- return num
-
-
-//Returns the hex value of a number given a value assumed to be a base-ten value
-/proc/num2hex(num, placeholder)
- if(placeholder == null)
- placeholder = 2
-
- if(!isnum(num))
- return
-
- if(num == 0)
- var/final = ""
- for(var/i in 1 to placeholder)
- final = "[final]0"
- return final
-
- var/hex = ""
- var/i = 0
- while(16 ** i < num)
- i++
- var/power = null
- power = i - 1
- while(power >= 0)
- var/val = round(num / 16 ** power)
- num -= val * 16 ** power
- switch(val)
- if(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
- hex += "[val]"
- if(10)
- hex += "A"
- if(11)
- hex += "B"
- if(12)
- hex += "C"
- if(13)
- hex += "D"
- if(14)
- hex += "E"
- if(15)
- hex += "F"
- else
- power--
- while(length(hex) < placeholder)
- hex = "0[hex]"
- return hex
-
//Turns a direction into text
/proc/num2dir(direction)
switch(direction)
@@ -177,7 +100,6 @@
return WEST
return NORTH|WEST
-
//returns the north-zero clockwise angle in degrees, given a direction
/proc/dir2angle(D)
switch(D)
@@ -251,6 +173,8 @@
. += "[seperator]+RUNTIME"
if(rights & R_LOG)
. += "[seperator]+LOG"
+ if(rights & R_POLLS)
+ . += "[seperator]+POLLS"
/proc/ui_style2icon(ui_style)
@@ -372,3 +296,26 @@
/// for use inside of browse() calls to html assets that might be loaded on a cdn.
/proc/url2htmlloader(url)
return {""}
+
+//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
+///Takes a hex color provided as string and returns the proper color matrix using hex2num.
+/proc/color_hex2color_matrix(string)
+ var/length = length(string)
+ if((length != 7 && length != 9) || length != length_char(string))
+ return color_matrix_identity()
+ var/r = hex2num(copytext(string, 2, 4))/255
+ var/g = hex2num(copytext(string, 4, 6))/255
+ var/b = hex2num(copytext(string, 6, 8))/255
+ var/a = 1
+ if(length == 9)
+ a = hex2num(copytext(string, 8, 10))/255
+ if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
+ return color_matrix_identity()
+ return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
+
+///will drop all values not on the diagonal
+///returns a hex color
+/proc/color_matrix2color_hex(list/the_matrix)
+ if(!istype(the_matrix) || the_matrix.len != 20)
+ return "#ffffffff"
+ return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
diff --git a/code/__HELPERS/type_processing.dm b/code/__HELPERS/type_processing.dm
new file mode 100644
index 0000000000000..6ad09353e1679
--- /dev/null
+++ b/code/__HELPERS/type_processing.dm
@@ -0,0 +1,74 @@
+///Turns a list of typepaths into 'fancy' titles for admins.
+/proc/make_types_fancy(list/types)
+ if(ispath(types))
+ types = list(types)
+ . = list()
+ for(var/type in types)
+ var/typename = "[type]"
+ var/static/list/TYPES_SHORTCUTS = list(
+ /obj/effect/decal/cleanable = "CLEANABLE",
+ /obj/item/radio/headset = "HEADSET",
+ /obj/item/clothing/head/helmet/space = "SPESSHELMET",
+ /obj/item/book/manual = "MANUAL",
+ /obj/item/reagent_containers = "REAGENT_CONTAINERS",
+ /obj/machinery/atmospherics = "ATMOS_MECH",
+ /obj/machinery/portable_atmospherics = "PORT_ATMOS",
+ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
+ /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
+ /obj/item/organ = "ORGAN",
+ /obj/item = "ITEM",
+ /obj/machinery = "MACHINERY",
+ /obj/effect = "EFFECT",
+ /obj = "O",
+ /datum = "D",
+ /turf/open = "OPEN",
+ /turf/closed = "CLOSED",
+ /turf = "T",
+ /mob/living/carbon = "CARBON",
+ /mob/living/simple_animal = "SIMPLE",
+ /mob/living = "LIVING",
+ /mob = "M"
+ )
+ for (var/tn in TYPES_SHORTCUTS)
+ if(copytext(typename, 1, length("[tn]/") + 1) == "[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
+ typename = TYPES_SHORTCUTS[tn] + copytext(typename, length("[tn]/"))
+ break
+ .[typename] = type
+
+///Generates a static list of 'fancy' atom types, or returns that if its already been generated.
+/proc/get_fancy_list_of_atom_types()
+ var/static/list/pre_generated_list
+ if(!pre_generated_list) //init
+ pre_generated_list = make_types_fancy(typesof(/atom))
+ return pre_generated_list
+
+///Generates a static list of 'fancy' datum types, excluding everything atom, or returns that if its already been generated.
+/proc/get_fancy_list_of_datum_types()
+ var/static/list/pre_generated_list
+ if(!pre_generated_list) //init
+ pre_generated_list = make_types_fancy(sort_list(typesof(/datum) - typesof(/atom)))
+ return pre_generated_list
+
+/**
+ * Takes a given fancy list and filters out a given filter text.
+ * Args:
+ * fancy_list - The list provided we filter.
+ * filter - the text we use to filter fancy_list
+ */
+/proc/filter_fancy_list(list/fancy_list, filter as text)
+ var/list/matches = new
+ var/end_len = -1
+ var/list/endcheck = splittext(filter, "!")
+ if(endcheck.len > 1)
+ filter = endcheck[1]
+ end_len = length_char(filter)
+
+ for(var/key in fancy_list)
+ var/value = fancy_list[key]
+ if(findtext("[key]", filter, -end_len) || findtext("[value]", filter, -end_len))
+ matches[key] = value
+ return matches
+
+///Splits the type with parenthesis between each word so admins visually tell it is a typepath.
+/proc/return_typenames(type)
+ return splittext("[type]", "/")
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 478f483e98de5..86348e043bd51 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -21,8 +21,6 @@
#undef DELTA_CALC
-#define UNTIL(X) while(!(X)) stoplag()
-
/**
* NAMEOF: Compile time checked variable name to string conversion
* evaluates to a string equal to "X", but compile errors if X isn't a var on datum.
@@ -139,6 +137,7 @@
else if(. >= 360)
. -= 360
+///Returns one of the 8 directions based on an angle
/proc/angle_to_dir(angle)
switch(angle)
if(338 to 360, 0 to 22)
@@ -158,6 +157,18 @@
if(293 to 337)
return NORTHWEST
+///Returns one of the 4 cardinal directions based on an angle
+/proc/angle_to_cardinal_dir(angle)
+ switch(angle)
+ if(316 to 360, 0 to 45)
+ return NORTH
+ if(46 to 135)
+ return EAST
+ if(136 to 225)
+ return SOUTH
+ if(226 to 315)
+ return WEST
+
///returns degrees between two angles
/proc/get_between_angles(degree_one, degree_two)
var/angle = abs(degree_one - degree_two) % 360
@@ -207,7 +218,7 @@
continue
if((object.allow_pass_flags & PASS_AIR) && air_pass)
continue
- if(object.flags_atom & ON_BORDER && object.dir != direction)
+ if(object.atom_flags & ON_BORDER && object.dir != direction)
continue
return TRUE
return FALSE
@@ -594,9 +605,7 @@
/proc/get_cardinal_dir(atom/A, atom/B)
- var/dx = abs(B.x - A.x)
- var/dy = abs(B.y - A.y)
- return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12)
+ return angle_to_cardinal_dir(Get_Angle(get_turf(A), get_turf(B)))
/// If given a diagonal dir, return a corresponding cardinal dir. East/west preferred
/proc/closest_cardinal_dir(dir)
@@ -1016,9 +1025,9 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/mob/dview/Initialize(mapload) //Properly prevents this mob from gaining huds or joining any global lists
SHOULD_CALL_PARENT(FALSE)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("Warning: [src]([type]) initialized multiple times!")
- flags_atom |= INITIALIZED
+ atom_flags |= INITIALIZED
return INITIALIZE_HINT_NORMAL
/mob/dview/Destroy(force = FALSE)
@@ -1095,11 +1104,11 @@ will handle it, but:
for(var/client/C in show_to)
C.images += I
animate(I, transform = 0, alpha = 255, time = 0.5 SECONDS, easing = ELASTIC_EASING)
- addtimer(CALLBACK(GLOBAL_PROC, TYPE_PROC_REF(/, fade_out), I), duration - 0.5 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fade_out), I), duration - 0.5 SECONDS)
/proc/fade_out(image/I, list/show_to)
animate(I, alpha = 0, time = 0.5 SECONDS, easing = EASE_IN)
- addtimer(CALLBACK(GLOBAL_PROC, TYPE_PROC_REF(/, remove_images_from_clients), I, show_to), 0.5 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_images_from_clients), I, show_to), 0.5 SECONDS)
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm
index 445bfee77327e..753b8fe4b47ec 100644
--- a/code/__byond_version_compat.dm
+++ b/code/__byond_version_compat.dm
@@ -9,13 +9,6 @@
#endif
#endif
-//Update this whenever the byond version is stable so people stop updating to hilariously broken versions
-#define MAX_COMPILER_VERSION 515
-#define MAX_COMPILER_BUILD 1620
-#if DM_VERSION > MAX_COMPILER_VERSION || DM_BUILD > MAX_COMPILER_BUILD
-#warn WARNING! your byond version is over the recommended version! There may be unexpected byond bugs!
-#endif
-
// So we want to have compile time guarantees these methods exist on local type
// We use wrappers for this in case some part of the api ever changes, and to make their function more clear
// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global.
diff --git a/code/_globalvars/admin.dm b/code/_globalvars/admin.dm
index 2816cacf8a3c7..30630c5e7780f 100644
--- a/code/_globalvars/admin.dm
+++ b/code/_globalvars/admin.dm
@@ -35,3 +35,19 @@ GLOBAL_PROTECT(admin_ranks)
GLOBAL_LIST_EMPTY(protected_ranks)
GLOBAL_PROTECT(protected_ranks)
+
+// A list of all the special byond lists that need to be handled different by vv
+GLOBAL_LIST_INIT(vv_special_lists, init_special_list_names())
+
+/proc/init_special_list_names()
+ var/list/output = list()
+ var/obj/sacrifice = new
+ for(var/varname in sacrifice.vars)
+ var/value = sacrifice.vars[varname]
+ if(!islist(value))
+ if(!isdatum(value) && hascall(value, "Cut"))
+ output += varname
+ continue
+ if(isnull(locate(REF(value))))
+ output += varname
+ return output
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 9902c088eaf38..961a3cf7f1d46 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -15,7 +15,8 @@ GLOBAL_LIST_INIT(bitfields, list(
"SPAWN" = R_SPAWN,
"DBRANKS" = R_DBRANKS,
"RUNTIME" = R_RUNTIME,
- "LOG" = R_LOG
+ "LOG" = R_LOG,
+ "POLLS" = R_POLLS
),
"machine_stat" = list(
"BROKEN" = BROKEN,
@@ -28,7 +29,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"KNOCKED_DOWN" = KNOCKED_DOWN,
"MACHINE_DO_NOT_PROCESS" = MACHINE_DO_NOT_PROCESS
),
- "flags_gun_features" = list(
+ "gun_features_flags" = list(
"GUN_CAN_POINTBLANK" = GUN_CAN_POINTBLANK,
"GUN_UNUSUAL_DESIGN" = GUN_UNUSUAL_DESIGN,
"GUN_AMMO_COUNTER" = GUN_AMMO_COUNTER,
@@ -47,12 +48,12 @@ GLOBAL_LIST_INIT(bitfields, list(
"GUN_SHOWS_LOADED" = GUN_SHOWS_LOADED,
"GUN_SMOKE_PARTICLES" = GUN_SMOKE_PARTICLES
),
- "flags_flamer_features" = list(
+ "flamer_features_flags" = list(
"FLAMER_IS_LIT" = FLAMER_IS_LIT,
"FLAMER_NO_LIT_OVERLAY" = FLAMER_NO_LIT_OVERLAY,
"FLAMER_USES_GUN_FLAMES" = FLAMER_USES_GUN_FLAMES
),
- "flags_magazine" = list(
+ "magazine_flags" = list(
"MAGAZINE_REFILLABLE" = MAGAZINE_REFILLABLE,
"MAGAZINE_HANDFUL" = MAGAZINE_HANDFUL,
"MAGAZINE_WORN" = MAGAZINE_WORN,
@@ -81,7 +82,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"BE_SQUAD_STRICT" = BE_SQUAD_STRICT,
"BE_ALIEN_UNREVIVABLE" = BE_ALIEN_UNREVIVABLE
),
- "flags_atom" = list(
+ "atom_flags" = list(
"UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1,
"AI_BLOCKED" = AI_BLOCKED,
"NOINTERACT" = NOINTERACT,
@@ -99,7 +100,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"SHUTTLE_IMMUNE" = SHUTTLE_IMMUNE,
"HTML_USE_INITAL_ICON_1" = HTML_USE_INITAL_ICON_1,
),
- "flags_area" = list(
+ "area_flags" = list(
"DISALLOW_WEEDING" = DISALLOW_WEEDING,
"NEAR_FOB" = NEAR_FOB,
"NO_DROPPOD" = NO_DROPPOD,
@@ -112,7 +113,6 @@ GLOBAL_LIST_INIT(bitfields, list(
"CAN_BE_HIT" = CAN_BE_HIT,
"PROJ_IGNORE_DENSITY" = PROJ_IGNORE_DENSITY,
"LIGHT_CAN_BE_SHUT" = LIGHT_CAN_BE_SHUT,
- "AUTOBALANCE_CHECK" = AUTOBALANCE_CHECK
),
"appearance_flags" = list(
"LONG_GLIDE" = LONG_GLIDE,
@@ -144,7 +144,8 @@ GLOBAL_LIST_INIT(bitfields, list(
"PASS_THROW" = PASS_THROW,
"PASS_PROJECTILE" = PASS_PROJECTILE,
"PASS_AIR" = PASS_AIR,
- "PASS_WALKOVER" = PASS_WALKOVER
+ "PASS_WALKOVER" = PASS_WALKOVER,
+ "PASS_TANK" = PASS_TANK,
),
"pass_flags" = list(
"PASS_LOW_STRUCTURE" = PASS_LOW_STRUCTURE,
@@ -157,7 +158,8 @@ GLOBAL_LIST_INIT(bitfields, list(
"PASS_THROW" = PASS_THROW,
"PASS_PROJECTILE" = PASS_PROJECTILE,
"PASS_AIR" = PASS_AIR,
- "PASS_WALKOVER" = PASS_WALKOVER
+ "PASS_WALKOVER" = PASS_WALKOVER,
+ "PASS_TANK" = PASS_TANK,
),
"status_flags" = list(
"CANSTUN" = CANSTUN,
@@ -171,7 +173,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"TK_USER" = TK_USER,
"CANUNCONSCIOUS" = CANUNCONSCIOUS,
"CANCONFUSE" = CANCONFUSE,
- "INCORPOREAL" = INCORPOREAL
+ "INCORPOREAL" = INCORPOREAL,
),
"muted" = list(
"MUTE_IC" = MUTE_IC,
@@ -188,7 +190,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"PIPING_DEFAULT_LAYER_ONLY" = PIPING_DEFAULT_LAYER_ONLY,
"PIPING_CARDINAL_AUTONORMALIZE" = PIPING_CARDINAL_AUTONORMALIZE
),
- "flags_inv_hide" = list(
+ "inv_hide_flags" = list(
"HIDEGLOVES" = HIDEGLOVES,
"HIDESUITSTORAGE" = HIDESUITSTORAGE,
"HIDEJUMPSUIT" = HIDEJUMPSUIT,
@@ -202,7 +204,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"HIDEFACE" = HIDEFACE,
"HIDE_EXCESS_HAIR" = HIDE_EXCESS_HAIR
),
- "flags_inventory" = list(
+ "inventory_flags" = list(
"NOSLIPPING" = NOSLIPPING,
"COVEREYES" = COVEREYES,
"COVERMOUTH" = COVERMOUTH,
@@ -211,7 +213,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"NOPRESSUREDMAGE" = NOPRESSUREDMAGE,
"NOQUICKEQUIP" = NOQUICKEQUIP
),
- "flags_armor_features" = list(
+ "armor_features_flags" = list(
"ARMOR_SQUAD_OVERLAY" = ARMOR_SQUAD_OVERLAY,
"ARMOR_LAMP_OVERLAY" = ARMOR_LAMP_OVERLAY,
"ARMOR_LAMP_ON" = ARMOR_LAMP_ON,
@@ -219,13 +221,13 @@ GLOBAL_LIST_INIT(bitfields, list(
"ARMOR_NO_DECAP" = ARMOR_NO_DECAP,
"ARMOR_FIRE_RESISTANT" = ARMOR_FIRE_RESISTANT
),
- "flags_marine_helmet" = list(
+ "marine_helmet_flags" = list(
"HELMET_SQUAD_OVERLAY" = HELMET_SQUAD_OVERLAY,
"HELMET_GARB_OVERLAY" = HELMET_GARB_OVERLAY,
"HELMET_STORE_GARB" = HELMET_STORE_GARB,
"HELMET_IS_DAMAGED" = HELMET_IS_DAMAGED
),
- "flags_equip_slot" = list(
+ "equip_slot_flags" = list(
"ITEM_SLOT_OCLOTHING" = ITEM_SLOT_OCLOTHING,
"ITEM_SLOT_ICLOTHING" = ITEM_SLOT_ICLOTHING,
"ITEM_SLOT_GLOVES" = ITEM_SLOT_GLOVES,
@@ -240,7 +242,9 @@ GLOBAL_LIST_INIT(bitfields, list(
"ITEM_SLOT_R_POCKET" = ITEM_SLOT_R_POCKET,
"ITEM_SLOT_L_POCKET" = ITEM_SLOT_L_POCKET,
"ITEM_SLOT_SUITSTORE" = ITEM_SLOT_SUITSTORE,
- "ITEM_SLOT_HANDCUFF" = ITEM_SLOT_HANDCUFF
+ "ITEM_SLOT_HANDCUFF" = ITEM_SLOT_HANDCUFF,
+ "ITEM_SLOT_L_HAND" = ITEM_SLOT_L_HAND,
+ "ITEM_SLOT_R_HAND" = ITEM_SLOT_R_HAND
),
"thermal_protection_flags" = list(
"HEAD" = HEAD,
@@ -257,7 +261,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"HAND_LEFT" = HAND_LEFT,
"HAND_RIGHT" = HAND_RIGHT
),
- "flags_armor_protection" = list(
+ "armor_protection_flags" = list(
"HEAD" = HEAD,
"FACE" = FACE,
"EYES" = EYES,
@@ -272,7 +276,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"HAND_LEFT" = HAND_LEFT,
"HAND_RIGHT" = HAND_RIGHT
),
- "flags_cold_protection" = list(
+ "cold_protection_flags" = list(
"HEAD" = HEAD,
"FACE" = FACE,
"EYES" = EYES,
@@ -287,7 +291,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"HAND_LEFT" = HAND_LEFT,
"HAND_RIGHT" = HAND_RIGHT
),
- "flags_heat_protection" = list(
+ "heat_protection_flags" = list(
"HEAD" = HEAD,
"FACE" = FACE,
"EYES" = EYES,
@@ -303,30 +307,13 @@ GLOBAL_LIST_INIT(bitfields, list(
"HAND_RIGHT" = HAND_RIGHT
),
"update_overlay" = list(
- "APC_UPOVERLAY_CHARGEING0" = APC_UPOVERLAY_CHARGEING0,
- "APC_UPOVERLAY_CHARGEING1" = APC_UPOVERLAY_CHARGEING1,
- "APC_UPOVERLAY_CHARGEING2" = APC_UPOVERLAY_CHARGEING2,
- "APC_UPOVERLAY_EQUIPMENT0" = APC_UPOVERLAY_EQUIPMENT0,
- "APC_UPOVERLAY_EQUIPMENT1" = APC_UPOVERLAY_EQUIPMENT1,
- "APC_UPOVERLAY_EQUIPMENT2" = APC_UPOVERLAY_EQUIPMENT2,
- "APC_UPOVERLAY_LIGHTING0" = APC_UPOVERLAY_LIGHTING0,
- "APC_UPOVERLAY_LIGHTING1" = APC_UPOVERLAY_LIGHTING1,
- "APC_UPOVERLAY_LIGHTING2" = APC_UPOVERLAY_LIGHTING2,
- "APC_UPOVERLAY_ENVIRON0" = APC_UPOVERLAY_ENVIRON0,
- "APC_UPOVERLAY_ENVIRON1" = APC_UPOVERLAY_ENVIRON1,
- "APC_UPOVERLAY_ENVIRON2" = APC_UPOVERLAY_ENVIRON2,
- "APC_UPOVERLAY_LOCKED" = APC_UPOVERLAY_LOCKED,
- "APC_UPOVERLAY_OPERATING" = APC_UPOVERLAY_OPERATING,
- "APC_UPOVERLAY_CELL_IN" = APC_UPOVERLAY_CELL_IN,
- "APC_UPOVERLAY_BLUESCREEN" = APC_UPOVERLAY_BLUESCREEN
+ "UPOVERLAY_OPERATING" = UPOVERLAY_OPERATING,
+ "UPOVERLAY_LOCKED" = UPOVERLAY_LOCKED,
),
"update_state" = list(
- "UPSTATE_OPENED1" = UPSTATE_OPENED1,
- "UPSTATE_OPENED2" = UPSTATE_OPENED2,
- "UPSTATE_MAINT" = UPSTATE_MAINT,
"UPSTATE_BROKE" = UPSTATE_BROKE,
+ "UPSTATE_MAINT" = UPSTATE_MAINT,
"UPSTATE_WIREEXP" = UPSTATE_WIREEXP,
- "UPSTATE_ALLGOOD" = UPSTATE_ALLGOOD
),
"apcwires" = list(
"APC_WIRE_IDSCAN" = APC_WIRE_IDSCAN,
@@ -438,22 +425,16 @@ GLOBAL_LIST_INIT(bitfields, list(
"CONFIG_ENTRY_LOCKED" = CONFIG_ENTRY_LOCKED,
"CONFIG_ENTRY_HIDDEN" = CONFIG_ENTRY_HIDDEN
),
- "flags_ammo_behavior" = list(
- "AMMO_EXPLOSIVE" = AMMO_EXPLOSIVE,
+ "ammo_behavior_flags" = list(
+ "AMMO_TARGET_TURF" = AMMO_TARGET_TURF,
"AMMO_XENO" = AMMO_XENO,
"AMMO_UNWIELDY" = AMMO_UNWIELDY,
"AMMO_ENERGY" = AMMO_ENERGY,
- "AMMO_ROCKET" = AMMO_ROCKET,
"AMMO_SNIPER" = AMMO_SNIPER,
"AMMO_INCENDIARY" = AMMO_INCENDIARY,
"AMMO_SKIPS_ALIENS" = AMMO_SKIPS_ALIENS,
- "AMMO_IS_SILENCED" = AMMO_IS_SILENCED,
- "AMMO_IGNORE_ARMOR" = AMMO_IGNORE_ARMOR,
- "AMMO_IGNORE_RESIST" = AMMO_IGNORE_RESIST,
"AMMO_BALLISTIC" = AMMO_BALLISTIC,
- "AMMO_SUNDERING" = AMMO_SUNDERING,
"AMMO_SPECIAL_PROCESS" = AMMO_SPECIAL_PROCESS,
- "AMMO_SENTRY" = AMMO_SENTRY,
"AMMO_FLAME" = AMMO_FLAME,
"AMMO_IFF" = AMMO_IFF,
"AMMO_HITSCAN" = AMMO_HITSCAN,
@@ -463,7 +444,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"AMMO_PASS_THROUGH_MOB" = AMMO_PASS_THROUGH_MOB,
"AMMO_SOUND_PITCH" = AMMO_SOUND_PITCH
),
- "flags_attach_features" = list(
+ "attach_features_flags" = list(
"ATTACH_REMOVABLE" = ATTACH_REMOVABLE,
"ATTACH_ACTIVATION" = ATTACH_ACTIVATION,
"ATTACH_SAME_ICON" = ATTACH_SAME_ICON,
@@ -473,11 +454,11 @@ GLOBAL_LIST_INIT(bitfields, list(
"ATTACH_BYPASS_ALLOWED_LIST" = ATTACH_BYPASS_ALLOWED_LIST,
"ATTACH_DIFFERENT_MOB_ICON_STATE" = ATTACH_DIFFERENT_MOB_ICON_STATE
),
- "flags_barrier" = list(
+ "barrier_flags" = list(
"HANDLE_BARRIER_CHANCE" = HANDLE_BARRIER_CHANCE,
"HANDLE_BARRIER_BLOCK" = HANDLE_BARRIER_BLOCK
),
- "flags_item" = list(
+ "item_flags" = list(
"IN_INVENTORY" = IN_INVENTORY,
"NOBLUDGEON" = NOBLUDGEON,
"DELONDROP" = DELONDROP,
@@ -497,11 +478,16 @@ GLOBAL_LIST_INIT(bitfields, list(
"DEPLOYED_WRENCH_DISASSEMBLE" = DEPLOYED_WRENCH_DISASSEMBLE,
"DEPLOYED_ANCHORED_FIRING_ONLY" = DEPLOYED_ANCHORED_FIRING_ONLY,
"FULLY_WIELDED" = FULLY_WIELDED,
- "HAS_UNDERLAY" = HAS_UNDERLAY
+ "HAS_UNDERLAY" = HAS_UNDERLAY,
+ "AUTOBALANCE_CHECK" = AUTOBALANCE_CHECK,
),
- "flags_storage" = list(
+ "storage_flags" = list(
"BYPASS_VENDOR_CHECK" = BYPASS_VENDOR_CHECK,
),
+ "id_flags" = list(
+ "CAN_BUY_LOADOUT" = CAN_BUY_LOADOUT,
+ "USED_GHMME" = USED_GHMME,
+ ),
"ghost_hud" = list(
"GHOST_HUD_MED" = GHOST_HUD_MED,
"GHOST_HUD_SEC" = GHOST_HUD_SEC,
@@ -525,6 +511,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"RADIAL_STACKS" = RADIAL_STACKS,
"AUTO_INTERACT_DEPLOYABLES" = AUTO_INTERACT_DEPLOYABLES,
"RADIAL_LASERGUNS" = RADIAL_LASERGUNS,
+ "DIRECTIONAL_ATTACKS" = DIRECTIONAL_ATTACKS,
),
"toggles_deadchat" = list(
"DISABLE_DEATHRATTLE" = DISABLE_DEATHRATTLE,
@@ -546,7 +533,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"CHAT_STATISTICS" = CHAT_STATISTICS,
"CHAT_LOOC" = CHAT_LOOC
),
- "flags_scuttle" = list(
+ "scuttle_flags" = list(
"FLAGS_EVACUATION_DENY" = FLAGS_EVACUATION_DENY,
"FLAGS_SELF_DESTRUCT_DENY" = FLAGS_SELF_DESTRUCT_DENY,
"FLAGS_SDEVAC_TIMELOCK" = FLAGS_SDEVAC_TIMELOCK
@@ -617,7 +604,6 @@ GLOBAL_LIST_INIT(bitfields, list(
"ABILITY_IGNORE_SELECTED_ABILITY" = ABILITY_IGNORE_SELECTED_ABILITY,
"ABILITY_DO_AFTER_ATTACK" = ABILITY_DO_AFTER_ATTACK,
"ABILITY_USE_BURROWED" = ABILITY_USE_BURROWED,
- "ABILITY_USE_ROOTED" = ABILITY_USE_ROOTED
),
"pipe_flags" = list(
"PIPING_ALL_LAYER" = PIPING_ALL_LAYER,
diff --git a/code/_globalvars/colorvars.dm b/code/_globalvars/colorvars.dm
new file mode 100644
index 0000000000000..c49a3d90dfc0e
--- /dev/null
+++ b/code/_globalvars/colorvars.dm
@@ -0,0 +1 @@
+GLOBAL_LIST_INIT(color_vars, list("color"))
diff --git a/code/_globalvars/lists/client.dm b/code/_globalvars/lists/client.dm
index a62f8f1c8fd80..259dfbff12fe7 100644
--- a/code/_globalvars/lists/client.dm
+++ b/code/_globalvars/lists/client.dm
@@ -10,18 +10,19 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
"1408" = "bug preventing client display overrides from working leads to clients being able to see things/mobs they shouldn't be able to see",
))
// This is a mapping from JS keys to Byond - ref: https://keycode.info/
+// TODO: tgui has keyCodeToByond already
GLOBAL_LIST_INIT(_kbMap, list(
- "UP" = "North",
- "RIGHT" = "East",
- "DOWN" = "South",
- "LEFT" = "West",
+ "ARROWUP" = "North",
+ "ARROWRIGHT" = "East",
+ "ARROWDOWN" = "South",
+ "ARROWLEFT" = "West",
"INSERT" = "Insert",
"HOME" = "Northwest",
"PAGEUP" = "Northeast",
- "DEL" = "Delete",
+ "DELETE" = "Delete",
"END" = "Southwest",
"PAGEDOWN" = "Southeast",
- "SPACEBAR" = "Space",
+ " " = "Space",
"ALT" = "Alt",
"SHIFT" = "Shift",
"CONTROL" = "Ctrl"
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index affca044d8edc..bed10110f86b2 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -107,6 +107,7 @@ GLOBAL_LIST_INIT(playable_icons, list(
"mech_pilot",
"medical",
"pilot",
+ "transportofficer",
"praetorian",
"private",
"puppeteer",
@@ -141,7 +142,7 @@ GLOBAL_LIST_INIT(playable_squad_icons, list(
"smartgunner",
))
-GLOBAL_LIST_INIT(campaign_icon_types, list(
+GLOBAL_LIST_INIT(campaign_asset_icon_types, list(
"b18",
"gorgon",
"medkit",
@@ -208,29 +209,130 @@ GLOBAL_LIST_INIT(campaign_mission_icon_types, list(
"final_tgmc",
))
-/* RUTGMC DELETION BEGIN, moved to modular
+GLOBAL_LIST_INIT(campaign_perk_icon_types, list(
+ "health_1",
+ "soft_footed",
+ "health_2",
+ "cqc_1",
+ "cqc_2",
+ "melee_1",
+ "melee_2",
+ "pistols",
+ "shotguns",
+ "rifles",
+ "smgs",
+ "heavy",
+ "construction",
+ "medical",
+ "stamina_1",
+ "stamina_2",
+ "leadership",
+ "smartguns",
+ "firearms",
+ "overclock",
+ "sword",
+ "axe",
+))
+
+GLOBAL_LIST_INIT(campaign_loadout_item_icon_types, list(
+ "default",
+ "empty",
+ "light_armour_shield",
+ "medium_armour_shield",
+ "heavy_armour_shield",
+ "light_armour",
+ "medium_armour",
+ "heavy_armour",
+ "gorgon",
+ "medkit",
+ "materials",
+ "tyr",
+ "lorica",
+ "riot_shield",
+ "grenade",
+ "shotgun",
+ "scout",
+ "ballistic",
+ "lasergun",
+ "volkite",
+ "smartgun",
+ "helmet",
+ "boots",
+ "machete",
+ "axe",
+ "pistol",
+ "smg",
+ "construction",
+ "tx55",
+ "m25",
+ "m240",
+ "m1911c",
+ "rt3",
+ "88m4",
+ "v11",
+ "t19",
+ "t90",
+ "sg29",
+ "t18",
+ "t12",
+ "alf51b",
+ "tx11",
+ "sshotgun",
+ "tx15",
+ "t160",
+ "t60",
+ "v34",
+ "ak47",
+ "v41",
+ "rpg",
+ "t35",
+))
+
GLOBAL_LIST_INIT(minimap_icons, init_minimap_icons())
+///Populates minimap_icons
/proc/init_minimap_icons()
. = list()
for(var/icon_state in GLOB.playable_icons)
- .[icon_state] = icon2base64(icon('icons/UI_icons/map_blips.dmi', icon_state, frame = 1)) //RUTGMC edit - icon change
-RUTGMC EDIT END */
+ .[icon_state] = icon2base64(icon('modular_RUtgmc/icons/UI_icons/map_blips.dmi', icon_state, frame = 1)) //RUTGMC edit - icon change
-GLOBAL_LIST_INIT(campaign_icons, init_campaign_icons())
-/proc/init_campaign_icons()
+GLOBAL_LIST_INIT(campaign_asset_icons, init_campaign_asset_icons())
+
+///Populates campaign_asset_icons
+/proc/init_campaign_asset_icons()
. = list()
var/list/colours = list("green", "orange", "grey", "red", "blue")
- for(var/icon_state in GLOB.campaign_icon_types)
+ for(var/icon_state in GLOB.campaign_asset_icon_types)
for(var/colour in colours)
- .["[icon_state]_[colour]"] = icon2base64(icon('icons/UI_icons/campaign_icons.dmi', "[icon_state]_[colour]", frame = 1))
+ . += "[icon_state]_[colour]"
GLOBAL_LIST_INIT(campaign_mission_icons, init_campaign_mission_icons())
+///Populates campaign_mission_icons
/proc/init_campaign_mission_icons()
. = list()
var/list/colours = list("green", "yellow", "grey", "red", "blue")
for(var/icon_state in GLOB.campaign_mission_icon_types)
for(var/colour in colours)
- .["[icon_state]_[colour]"] = icon2base64(icon('icons/UI_icons/mission_icons.dmi', "[icon_state]_[colour]", frame = 1))
+ . += "[icon_state]_[colour]"
+
+GLOBAL_LIST_INIT(campaign_perk_icons, init_campaign_perk_icons())
+
+///Populates campaign_perk_icons
+/proc/init_campaign_perk_icons()
+ . = list()
+ var/list/colours = list("green", "orange", "grey", "red", "blue")
+ for(var/icon_state in GLOB.campaign_perk_icon_types)
+ for(var/colour in colours)
+ . += "[icon_state]_[colour]"
+
+GLOBAL_LIST_INIT(campaign_loadout_item_icons, init_campaign_loadout_item_icons())
+
+///Populates campaign_loadout_item_icons
+/proc/init_campaign_loadout_item_icons()
+ . = list()
+ var/list/colours = list("green", "orange", "grey", "red", "blue")
+ for(var/icon_state in GLOB.campaign_loadout_item_icon_types)
+ for(var/colour in colours)
+ . += "[icon_state]_[colour]"
diff --git a/code/_globalvars/lists/game_modes.dm b/code/_globalvars/lists/game_modes.dm
index 84bba8d371e9e..bb57b3b0bc19f 100644
--- a/code/_globalvars/lists/game_modes.dm
+++ b/code/_globalvars/lists/game_modes.dm
@@ -6,3 +6,65 @@ GLOBAL_LIST_INIT(ranked_jobs_by_faction, list(
FACTION_TERRAGOV = list(CAPTAIN, FIELD_COMMANDER, STAFF_OFFICER, SQUAD_LEADER),
FACTION_SOM = list(SOM_COMMANDER, SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_SQUAD_LEADER, SOM_SQUAD_VETERAN),
))
+
+///All jobs used in campaign
+GLOBAL_LIST_INIT(campaign_jobs, list(
+ SQUAD_MARINE,
+ SQUAD_ENGINEER,
+ SQUAD_CORPSMAN,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+))
+
+///Loot table if Marines win a major victory in a campaign mission
+GLOBAL_LIST_INIT(campaign_tgmc_major_loot, list(
+ /obj/effect/supply_drop/medical_basic = 7,
+ /obj/effect/supply_drop/marine_sentry = 5,
+ /obj/effect/supply_drop/recoilless_rifle = 3,
+ /obj/effect/supply_drop/armor_upgrades = 5,
+ /obj/effect/supply_drop/mmg = 4,
+ /obj/effect/supply_drop/zx_shotgun = 3,
+ /obj/effect/supply_drop/minigun = 3,
+ /obj/effect/supply_drop/scout = 3,
+))
+
+///Loot table if Marines win a minor victory in a campaign mission
+GLOBAL_LIST_INIT(campaign_tgmc_minor_loot, list(
+ /obj/effect/supply_drop/medical_basic = 7,
+ /obj/effect/supply_drop/marine_sentry = 5,
+ /obj/effect/supply_drop/recoilless_rifle = 3,
+ /obj/effect/supply_drop/armor_upgrades = 5,
+ /obj/effect/supply_drop/mmg = 4,
+))
+
+///Loot table if SOM win a major victory in a campaign mission
+GLOBAL_LIST_INIT(campaign_som_major_loot, list(
+ /obj/effect/supply_drop/medical_basic = 7,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope = 5,
+ /obj/effect/supply_drop/som_rpg = 3,
+ /obj/effect/supply_drop/som_armor_upgrades = 5,
+ /obj/effect/supply_drop/charger = 4,
+ /obj/effect/supply_drop/culverin = 3,
+ /obj/effect/supply_drop/blink_kit = 3,
+ /obj/effect/supply_drop/som_shotgun_burst = 3,
+))
+
+///Loot table if SOM win a minor victory in a campaign mission
+GLOBAL_LIST_INIT(campaign_som_minor_loot, list(
+ /obj/effect/supply_drop/medical_basic = 7,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope = 5,
+ /obj/effect/supply_drop/som_rpg = 3,
+ /obj/effect/supply_drop/som_armor_upgrades = 5,
+ /obj/effect/supply_drop/charger = 4,
+))
diff --git a/code/_globalvars/lists/keybinding.dm b/code/_globalvars/lists/keybinding.dm
index 0b6e960c095ef..e829bd18ea363 100644
--- a/code/_globalvars/lists/keybinding.dm
+++ b/code/_globalvars/lists/keybinding.dm
@@ -26,7 +26,7 @@
/proc/init_emote_keybinds()
for(var/i in subtypesof(/datum/emote))
var/datum/emote/faketype = i
- if(!initial(faketype.key) || initial(faketype.flags_emote) & NO_KEYBIND)
+ if(!initial(faketype.key) || initial(faketype.emote_flags) & NO_KEYBIND)
continue
var/datum/keybinding/emote/emote_kb = new
emote_kb.link_to_emote(faketype)
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 845fe4d2eaa7d..c1c9df1a4d40d 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtype
GLOBAL_LIST_EMPTY(alive_living_list) //all alive /mob/living, including clientless.
GLOBAL_LIST_EMPTY(offered_mob_list) //all /mobs offered by admins
GLOBAL_LIST_EMPTY(ai_list)
+GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define
GLOBAL_LIST_EMPTY(living_cameras)
GLOBAL_LIST_EMPTY(aiEyes)
@@ -116,8 +117,9 @@ GLOBAL_LIST_INIT(xeno_types_tier_one, list(/mob/living/carbon/xenomorph/runner,
//RUTGMC EDIT - Moved to modular_RUtgmc\code\_globalvars\lists\mobs.dm
/*
GLOBAL_LIST_INIT(xeno_types_tier_two, list(/mob/living/carbon/xenomorph/hunter, /mob/living/carbon/xenomorph/warrior, /mob/living/carbon/xenomorph/spitter, /mob/living/carbon/xenomorph/hivelord, /mob/living/carbon/xenomorph/carrier, /mob/living/carbon/xenomorph/bull, /mob/living/carbon/xenomorph/wraith, /mob/living/carbon/xenomorph/puppeteer))
-GLOBAL_LIST_INIT(xeno_types_tier_three, list(/mob/living/carbon/xenomorph/gorger, /mob/living/carbon/xenomorph/widow, /mob/living/carbon/xenomorph/ravager, /mob/living/carbon/xenomorph/praetorian, /mob/living/carbon/xenomorph/boiler, /mob/living/carbon/xenomorph/defiler, /mob/living/carbon/xenomorph/crusher, /mob/living/carbon/xenomorph/shrike, /mob/living/carbon/xenomorph/behemoth))
+GLOBAL_LIST_INIT(xeno_types_tier_three, list(/mob/living/carbon/xenomorph/gorger, /mob/living/carbon/xenomorph/widow, /mob/living/carbon/xenomorph/ravager, /mob/living/carbon/xenomorph/praetorian, /mob/living/carbon/xenomorph/boiler, /mob/living/carbon/xenomorph/defiler, /mob/living/carbon/xenomorph/crusher, /mob/living/carbon/xenomorph/shrike, /mob/living/carbon/xenomorph/behemoth, /mob/living/carbon/xenomorph/warlock))
*/
+GLOBAL_LIST_INIT(xeno_types_tier_four, list(/mob/living/carbon/xenomorph/shrike, /mob/living/carbon/xenomorph/queen, /mob/living/carbon/xenomorph/king))
GLOBAL_LIST_INIT_TYPED(hive_datums, /datum/hive_status, init_hive_datum_list()) // init by make_datum_references_lists()
/proc/init_hive_datum_list()
@@ -181,3 +183,16 @@ GLOBAL_LIST_INIT(hive_ui_static_data, init_hive_status_lists()) // init by make_
for(var/i in GLOB.mob_list)
var/mob/M = i
M.update_config_movespeed()
+
+///The actions given to all humans on init
+GLOBAL_LIST_INIT(human_init_actions, list(
+ /datum/action/skill/toggle_orders,
+ /datum/action/skill/issue_order/move,
+ /datum/action/skill/issue_order/hold,
+ /datum/action/skill/issue_order/focus,
+ /datum/action/innate/order/attack_order/personal,
+ /datum/action/innate/order/defend_order/personal,
+ /datum/action/innate/order/retreat_order/personal,
+ /datum/action/innate/order/rally_order/personal,
+ /datum/action/innate/message_squad,
+))
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 058cf05a69d2e..a8890dd6256a2 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -98,7 +98,15 @@ GLOBAL_LIST_INIT(supply_drops, typecacheof(list(
/obj/vehicle/unmanned)))
//hypersleep related
-GLOBAL_LIST_EMPTY(cryoed_item_list)
+GLOBAL_LIST_EMPTY(cryoed_item_list_gun)
+GLOBAL_LIST_EMPTY(cryoed_item_list_ammo)
+GLOBAL_LIST_EMPTY(cryoed_item_list_explosive)
+GLOBAL_LIST_EMPTY(cryoed_item_list_melee)
+GLOBAL_LIST_EMPTY(cryoed_item_list_clothing)
+GLOBAL_LIST_EMPTY(cryoed_item_list_food)
+GLOBAL_LIST_EMPTY(cryoed_item_list_drugs)
+GLOBAL_LIST_EMPTY(cryoed_item_list_containers)
+GLOBAL_LIST_EMPTY(cryoed_item_list_other)
GLOBAL_LIST_INIT(do_not_preserve, typecacheof(list(
/obj/item/clothing/mask/cigarette,
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index a6bee2bfacf29..01181294589aa 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -42,5 +42,8 @@ GLOBAL_PROTECT(key_to_time_of_death)
GLOBAL_LIST_EMPTY(key_to_time_of_xeno_death)
GLOBAL_PROTECT(key_to_time_of_xeno_death)
+GLOBAL_LIST_EMPTY(key_to_time_of_caste_swap)
+GLOBAL_PROTECT(key_to_time_of_caste_swap)
+
///List of ssd living mobs
GLOBAL_LIST_EMPTY(ssd_living_mobs)
diff --git a/code/_globalvars/regexes.dm b/code/_globalvars/regexes.dm
index e7125f3dcd930..9a4b7be7e9ead 100644
--- a/code/_globalvars/regexes.dm
+++ b/code/_globalvars/regexes.dm
@@ -5,10 +5,18 @@ GLOBAL_DATUM_INIT(is_website, /regex, regex("http|www.|\[a-z0-9_-]+.(com|org|net
GLOBAL_DATUM_INIT(is_email, /regex, regex("\[a-z0-9_-]+@\[a-z0-9_-]+.\[a-z0-9_-]+", "i"))
GLOBAL_DATUM_INIT(is_alphanumeric, /regex, regex("\[a-z0-9]+", "i"))
GLOBAL_DATUM_INIT(is_punctuation, /regex, regex("\[.!?]+", "i"))
+GLOBAL_DATUM_INIT(is_color, /regex, regex("^#\[0-9a-fA-F]{6}$"))
+GLOBAL_DATUM_INIT(is_alpha_color, /regex, regex("^#\[0-9a-fA-F]{8}$"))
+
+//finds text strings recognized as links on discord. Mainly used to stop embedding.
+GLOBAL_DATUM_INIT(has_discord_embeddable_links, /regex, regex("(https?://\[^\\s|<\]{2,})"))
//All < and > characters
GLOBAL_DATUM_INIT(angular_brackets, /regex, regex(@"[<>]", "g"))
+//All characters between < a > inclusive of the bracket
+GLOBAL_DATUM_INIT(html_tags, /regex, regex(@"<.*?>", "g"))
+
//All characters forbidden by filenames: ", \, \n, \t, /, ?, %, *, :, |, <, >
-GLOBAL_DATUM_INIT(filename_forbidden_chars, /regex, regex(@{""|[\\\n\t/?%*:|<>]"}, "g"))
+GLOBAL_DATUM_INIT(filename_forbidden_chars, /regex, regex(@{""|[\\\n\t/?%*:|<>]|\.\."}, "g"))
// had to use the OR operator for quotes instead of putting them in the character class because it breaks the syntax highlighting otherwise.
diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
index b4c341ddf5fb3..aef97a44e60ca 100644
--- a/code/_onclick/adjacent.dm
+++ b/code/_onclick/adjacent.dm
@@ -10,16 +10,16 @@
Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you
to check that the mob is not inside of something
*/
-/datum/proc/Adjacent(atom/neighbor) // basic inheritance, unused
+/datum/proc/Adjacent(atom/neighbor, atom/target, atom/movable/mover) // basic inheritance, unused
return FALSE
-/datum/wires/Adjacent(atom/neighbor)
+/datum/wires/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
return holder.Adjacent(neighbor)
// Not a sane use of the function and (for now) indicative of an error elsewhere
-/area/Adjacent(atom/neighbor)
+/area/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
CRASH("Call to /area/Adjacent(), unimplemented proc")
@@ -75,7 +75,7 @@
Note: Multiple-tile objects are created when the bound_width and bound_height are creater than the tile size.
This is not used in stock /tg/station currently.
*/
-/atom/movable/Adjacent(atom/neighbor)
+/atom/movable/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
if(neighbor == loc)
return TRUE
if(!isturf(loc))
@@ -86,8 +86,8 @@
//Multitile special cases.
-/obj/structure/Adjacent(atom/neighbor)
- if(bound_width > 32 || bound_height > 32)
+/obj/structure/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
+ if(isturf(loc) && bound_width > 32 || bound_height > 32) //locs will show loc if loc is not a turf
for(var/turf/myloc AS in locs)
if(myloc.Adjacent(neighbor, target = neighbor, mover = src))
return TRUE
@@ -101,8 +101,10 @@
return FALSE
//Multitile special cases.
-/obj/vehicle/Adjacent(atom/neighbor)
- if(bound_width > 32 || bound_height > 32)
+/obj/vehicle/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
+ if(hitbox)
+ return hitbox.Adjacent(neighbor)
+ if(isturf(loc) && bound_width > 32 || bound_height > 32) //locs will show loc if loc is not a turf
for(var/turf/myloc AS in locs)
if(myloc.Adjacent(neighbor, target = neighbor, mover = src))
return TRUE
@@ -115,16 +117,22 @@
return TRUE
return FALSE
+/obj/hitbox/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
+ for(var/turf/T AS in locs)
+ if(T.Adjacent(neighbor, neighbor, mover))
+ return TRUE
+ return FALSE
+
-/mob/living/silicon/decoy/Adjacent(atom/neighbor)
+/mob/living/silicon/decoy/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
for(var/turf/myloc AS in locs)
if(myloc.Adjacent(neighbor, target = neighbor, mover = src))
return TRUE
return FALSE
-/obj/machinery/door/Adjacent(atom/neighbor)
- if(bound_width > 32 || bound_height > 32)
+/obj/machinery/door/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
+ if(isturf(loc) && bound_width > 32 || bound_height > 32) //locs will show loc if loc is not a turf
for(var/turf/myloc AS in locs)
if(myloc.Adjacent(neighbor, target = neighbor, mover = src))
return TRUE
@@ -139,7 +147,7 @@
// This is necessary for storage items not on your person.
-/obj/item/Adjacent(atom/neighbor)
+/obj/item/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
if(isnull(loc)) //User input can sometimes cause adjacency checks to things no longer in the map.
return FALSE
@@ -161,12 +169,12 @@
return FALSE
-/obj/projectile/Adjacent(atom/neighbor) //Projectiles don't behave like regular items.
+/obj/projectile/Adjacent(atom/neighbor, atom/target, atom/movable/mover) //Projectiles don't behave like regular items.
var/turf/T = get_turf(loc)
return T?.Adjacent(neighbor, target = neighbor, mover = src)
-/obj/item/detpack/Adjacent(atom/neighbor) //Snowflake detpacks.
+/obj/item/detpack/Adjacent(atom/neighbor, atom/target, atom/movable/mover) //Snowflake detpacks.
if(neighbor == loc)
return TRUE
var/turf/T = get_turf(loc)
@@ -185,7 +193,7 @@
if(O == target_atom || O == mover || (O.allow_pass_flags & PASS_PROJECTILE)) //check if there's a dense object present on the turf
continue // PASS_THROW is used for anything you can click through (or the firedoor special case, see above)
- if(O.flags_atom & ON_BORDER) // windows have PASS_PROJECTILE but are on border, check them first
+ if(O.atom_flags & ON_BORDER) // windows have PASS_PROJECTILE but are on border, check them first
if(O.dir & target_dir || O.dir & (O.dir-1)) // full tile windows are just diagonals mechanically
return FALSE
@@ -195,13 +203,13 @@
/atom/proc/handle_barriers(mob/living/M)
for(var/obj/structure/S in M.loc)
- if(S.flags_atom & ON_BORDER && S.dir & get_dir(M,src) || S.dir&(S.dir-1))
- if(S.flags_barrier & HANDLE_BARRIER_CHANCE)
+ if(S.atom_flags & ON_BORDER && S.dir & get_dir(M,src) || S.dir&(S.dir-1))
+ if(S.barrier_flags & HANDLE_BARRIER_CHANCE)
if(S.handle_barrier_chance(M))
return S // blocked
for(var/obj/structure/S in loc)
- if(S.flags_atom & ON_BORDER && S.dir & get_dir(src,M) || S.dir&(S.dir-1))
- if(S.flags_barrier & HANDLE_BARRIER_CHANCE)
+ if(S.atom_flags & ON_BORDER && S.dir & get_dir(src,M) || S.dir&(S.dir-1))
+ if(S.barrier_flags & HANDLE_BARRIER_CHANCE)
if(S.handle_barrier_chance(M))
return S // blocked
return src // not blocked
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 49af82f6f4e54..7d2d5863dc3da 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -193,7 +193,7 @@
/* Firealarm */
/obj/machinery/firealarm/AICtrlClick(mob/living/silicon/ai/user) // toggle the fire alarm
var/area/A = get_area(src)
- if(A.flags_alarm_state & ALARM_WARNING_FIRE)
+ if(A.alarm_state_flags & ALARM_WARNING_FIRE)
reset()
else
alarm()
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 60736d84611c2..080e73de0491e 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -18,18 +18,18 @@
Note that this proc can be overridden, and is in the case of screen objects.
*/
/atom/Click(location, control, params)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
SEND_SIGNAL(src, COMSIG_CLICK, location, control, params, usr)
usr.ClickOn(src, location, params)
/atom/DblClick(location, control, params)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
usr.DblClickOn(src, params)
/atom/MouseWheel(delta_x, delta_y, location, control, params)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
usr.MouseWheelOn(src, delta_x, delta_y, params)
@@ -113,13 +113,18 @@
return
if(in_throw_mode)
- throw_item(A)
+ if(throw_item(A))
+ changeNext_move(CLICK_CD_THROWING)
return
var/obj/item/W = get_active_held_item()
if(W == A)
- W.attack_self(src)
+ if(modifiers["right"])
+ W.attack_self_alternate(src)
+ else
+ W.attack_self(src)
+
update_inv_l_hand()
update_inv_r_hand()
return
@@ -148,10 +153,13 @@
var/proximity = A.Adjacent(src)
if(!proximity || !A.attackby(W, src, params))
W.afterattack(A, src, proximity, params)
+ RangedAttack(A, params)
else
if(A.Adjacent(src))
A.attack_hand(src)
- RangedAttack(A, params)
+ else
+ RangedAttack(A, params)
+
/atom/movable/proc/CanReach(atom/ultimate_target, obj/item/tool, view_only = FALSE)
@@ -203,14 +211,14 @@
if(!T)
return FALSE
for(var/atom/movable/AM AS in T)
- if(AM.flags_atom & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
+ if(AM.atom_flags & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
return TRUE
return FALSE
/turf/IsObscured()
for(var/atom/movable/AM AS in src)
- if(AM.flags_atom & PREVENT_CLICK_UNDER && AM.density)
+ if(AM.atom_flags & PREVENT_CLICK_UNDER && AM.density)
return TRUE
return FALSE
@@ -350,6 +358,7 @@ if(selected_ability.target_flags & flagname && !istype(A, typepath)){\
return FALSE
if(COMSIG_MOB_CLICK_HANDLED)
return TRUE
+
return A.RightClick(src)
/mob/living/carbon/human/RightClickOn(atom/A)
@@ -407,8 +416,13 @@ if(selected_ability.target_flags & flagname && !istype(A, typepath)){\
/mob/living/carbon/human/ShiftClickOn(atom/A)
if(client.prefs.toggles_gameplay & MIDDLESHIFTCLICKING)
return ..()
- var/obj/item/held_thing = get_active_held_item()
+ if(selected_ability)
+ A = ability_target(A)
+ if(selected_ability.can_use_ability(A))
+ selected_ability.use_ability(A)
+ return TRUE
+ var/obj/item/held_thing = get_active_held_item()
if(held_thing && SEND_SIGNAL(held_thing, COMSIG_ITEM_SHIFTCLICKON, A, src) & COMPONENT_ITEM_CLICKON_BYPASS)
return FALSE
return ..()
@@ -426,6 +440,7 @@ if(selected_ability.target_flags & flagname && !istype(A, typepath)){\
/atom/proc/ShiftClick(mob/user)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_CLICK_SHIFT, user)
+ user.examinate(src)
return TRUE
/*
diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm
index d88012c61c4dd..8d1c4a7cd1b14 100644
--- a/code/_onclick/drag_drop.dm
+++ b/code/_onclick/drag_drop.dm
@@ -19,7 +19,7 @@
// recieve a mousedrop
/atom/proc/MouseDrop_T(atom/dropping, mob/user)
SHOULD_CALL_PARENT(TRUE)
- if(dropping.flags_atom & NOINTERACT)
+ if(dropping.atom_flags & NOINTERACT)
return TRUE //Already handled
SEND_SIGNAL(src, COMSIG_MOUSEDROPPED_ONTO, dropping, user)
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index 4785d51b105a0..a14f1a042e15e 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -90,6 +90,17 @@
var/mob/living/silicon/ai/AI = usr
AI.toggle_camera_light()
+/atom/movable/screen/ai/supply_interface
+ name = "Supply Interface"
+ icon_state = "pda"
+
+/atom/movable/screen/ai/supply_interface/Click()
+ . = ..()
+ if(.)
+ return
+ var/mob/living/silicon/ai/AI = usr
+ AI.supply_interface()
+
/atom/movable/screen/ai/multicam
name = "Multicamera Mode"
@@ -103,7 +114,6 @@
var/mob/living/silicon/ai/AI = usr
AI.toggle_multicam()
-
/atom/movable/screen/ai/add_multicam
name = "New Camera"
icon_state = "new_cam"
@@ -122,47 +132,52 @@
var/atom/movable/screen/using
//AI core
- using = new /atom/movable/screen/ai/aicore()
+ using = new /atom/movable/screen/ai/aicore(null, src)
using.screen_loc = ui_ai_core
static_inventory += using
//Camera list
- using = new /atom/movable/screen/ai/camera_list()
+ using = new /atom/movable/screen/ai/camera_list(null, src)
using.screen_loc = ui_ai_camera_list
static_inventory += using
//Track
- using = new /atom/movable/screen/ai/camera_track()
+ using = new /atom/movable/screen/ai/camera_track(null, src)
using.screen_loc = ui_ai_track_with_camera
static_inventory += using
//VOX
- using = new /atom/movable/screen/ai/announcement()
+ using = new /atom/movable/screen/ai/announcement(null, src)
using.screen_loc = ui_ai_announcement
static_inventory += using
//VOX Help
- using = new /atom/movable/screen/ai/announcement_help()
+ using = new /atom/movable/screen/ai/announcement_help(null, src)
using.screen_loc = ui_ai_announcement_help
static_inventory += using
//Camera light
- using = new /atom/movable/screen/ai/camera_light()
+ using = new /atom/movable/screen/ai/camera_light(null, src)
using.screen_loc = ui_ai_camera_light
static_inventory += using
+//Supply Interface
+ using = new /atom/movable/screen/ai/supply_interface(null, src)
+ using.screen_loc = ui_ai_supply
+ static_inventory += using
+
//Multicamera mode
- using = new /atom/movable/screen/ai/multicam()
+ using = new /atom/movable/screen/ai/multicam(null, src)
using.screen_loc = ui_ai_multicam
static_inventory += using
//Add multicamera camera
- using = new /atom/movable/screen/ai/add_multicam()
+ using = new /atom/movable/screen/ai/add_multicam(null, src)
using.screen_loc = ui_ai_add_multicam
static_inventory += using
//bioscan
- using = new /atom/movable/screen/ai/bioscan()
+ using = new /atom/movable/screen/ai/bioscan(null, src)
using.screen_loc = ui_ai_bioscan
static_inventory += using
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index 6ba4e208684e4..b536cc0c682ef 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -46,7 +46,7 @@
. = ..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/ghost/follow_ghosts()
+ using = new /atom/movable/screen/ghost/follow_ghosts(null, src)
using.screen_loc = ui_ghost_slot2
static_inventory += using
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 4c222ac915c71..0df65aa09be5b 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -32,7 +32,7 @@
var/atom/movable/screen/toggle_firemode
var/atom/movable/screen/unique_action
- var/atom/movable/screen/zone_sel
+ var/atom/movable/screen/zone_sel/zone_sel
var/atom/movable/screen/pull_icon
var/atom/movable/screen/throw_icon
var/atom/movable/screen/rest_icon
@@ -59,8 +59,16 @@
var/atom/movable/screen/action_button/hide_toggle/hide_actions_toggle
var/action_buttons_hidden = 0
- var/list/atom/movable/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
+ /// Assoc list of key => "plane master groups"
+ /// This is normally just the main window, but it'll occasionally contain things like spyglasses windows
+ var/list/datum/plane_master_group/master_groups = list()
+ /// see "appearance_flags" in the ref, assoc list of "[plane]" = object
+ var/list/atom/movable/screen/plane_master/plane_masters = list()
+ // List of weakrefs to objects that we add to our screen that we don't expect to DO anything
+ // They typically use * in their render target. They exist solely so we can reuse them,
+ // and avoid needing to make changes to all idk 300 consumers if we want to change the appearance
+ var/list/asset_refs_for_reuse = list()
/datum/hud/New(mob/owner)
mymob = owner
@@ -71,6 +79,15 @@
plane_masters["[instance.plane]"] = instance
instance.backdrop(mymob)
+ var/datum/plane_master_group/main/main_group = new(PLANE_GROUP_MAIN)
+ main_group.attach_to(src)
+
+/datum/hud/proc/should_use_scale()
+ return should_sight_scale(mymob.sight)
+
+/datum/hud/proc/should_sight_scale(sight_flags)
+ return (sight_flags & (SEE_TURFS | SEE_OBJS)) != SEE_TURFS
+
/datum/hud/Destroy()
if(mymob.hud_used == src)
mymob.hud_used = null
@@ -135,6 +152,24 @@
return ..()
+/// Creates the required plane masters to fill out new z layers (because each "level" of multiz gets its own plane master set)
+/datum/hud/proc/build_plane_groups(starting_offset, ending_offset)
+ for(var/group_key in master_groups)
+ var/datum/plane_master_group/group = master_groups[group_key]
+ group.build_plane_masters(starting_offset, ending_offset)
+
+/// Returns the plane master that matches the input plane from the passed in group
+/datum/hud/proc/get_plane_master(plane, group_key = PLANE_GROUP_MAIN)
+ var/plane_key = "[plane]"
+ var/datum/plane_master_group/group = master_groups[group_key]
+ return group.plane_masters[plane_key]
+
+/// Returns a list of all plane masters that match the input true plane, drawn from the passed in group (ignores z layer offsets)
+/datum/hud/proc/get_true_plane_masters(true_plane, group_key = PLANE_GROUP_MAIN)
+ var/list/atom/movable/screen/plane_master/masters = list()
+ for(var/plane in TRUE_PLANE_TO_OFFSETS(true_plane))
+ masters += get_plane_master(plane, group_key)
+ return masters
/mob/proc/create_mob_hud()
if(!client || hud_used)
@@ -146,13 +181,11 @@
update_sight()
SEND_SIGNAL(src, COMSIG_MOB_HUD_CREATED)
-
-/datum/hud/proc/plane_masters_update()
- // Plane masters are always shown to OUR mob, never to observers
- for(var/thing in plane_masters)
- var/atom/movable/screen/plane_master/PM = plane_masters[thing]
- PM.backdrop(mymob)
- mymob.client.screen += PM
+/mob/living/carbon/xenomorph/create_mob_hud()
+ . = ..()
+ //Some parts require hud_used to already be set
+ med_hud_set_health()
+ hud_set_plasma()
//Version denotes which style should be displayed. blank or 0 means "next version"
/datum/hud/proc/show_hud(version = 0, mob/viewmob)
@@ -221,6 +254,7 @@
persistent_inventory_update(screenmob)
mymob.update_action_buttons(TRUE)
reorganize_alerts(screenmob)
+ update_interactive_emotes()
mymob.reload_fullscreens()
update_parallax_pref(screenmob)
@@ -234,6 +268,12 @@
return TRUE
+/datum/hud/proc/plane_masters_update()
+ // Plane masters are always shown to OUR mob, never to observers
+ for(var/thing in plane_masters)
+ var/atom/movable/screen/plane_master/PM = plane_masters[thing]
+ PM.backdrop(mymob)
+ mymob.client.screen += PM
/datum/hud/human/show_hud(version = 0, mob/viewmob)
. = ..()
@@ -293,6 +333,21 @@
return
closeToolTip(usr)
+/datum/hud/proc/register_reuse(atom/movable/screen/reuse)
+ asset_refs_for_reuse += WEAKREF(reuse)
+ mymob?.client?.screen += reuse
+
+/datum/hud/proc/unregister_reuse(atom/movable/screen/reuse)
+ asset_refs_for_reuse -= WEAKREF(reuse)
+ mymob?.client?.screen -= reuse
+
+/datum/hud/proc/update_reuse(mob/show_to)
+ for(var/datum/weakref/screen_ref as anything in asset_refs_for_reuse)
+ var/atom/movable/screen/reuse = screen_ref.resolve()
+ if(isnull(reuse))
+ asset_refs_for_reuse -= screen_ref
+ continue
+ show_to.client?.screen += reuse
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
/mob/verb/button_pressed_F12()
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 3f7de74995864..c34578f12cf24 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -5,8 +5,6 @@
layer = ABOVE_HUD_LAYER
/atom/movable/screen/human/equip/Click()
- if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech
- return TRUE
SEND_SIGNAL(usr, COMSIG_CLICK_QUICKEQUIP)
@@ -30,7 +28,7 @@
var/has_hidden_gear
for(var/gear_slot in hud_data.gear)
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.icon = ui_style
inv_box.color = ui_color
inv_box.alpha = ui_alpha
@@ -48,7 +46,7 @@
static_inventory += inv_box
if(has_hidden_gear)
- using = new /atom/movable/screen/toggle_inv()
+ using = new /atom/movable/screen/toggle_inv(null, src)
using.icon = ui_style
using.color = ui_color
using.alpha = ui_alpha
@@ -57,7 +55,7 @@
// Draw the attack intent dialogue.
if(hud_data.has_a_intent)
- using = new /atom/movable/screen/act_intent/corner()
+ using = new /atom/movable/screen/act_intent/corner(null, src)
using.icon_state = owner.a_intent
using.alpha = ui_alpha
static_inventory += using
@@ -66,7 +64,7 @@
if(hud_data.has_m_intent)
- using = new /atom/movable/screen/mov_intent()
+ using = new /atom/movable/screen/mov_intent(null, src)
using.icon = ui_style
using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
using.color = ui_color
@@ -75,7 +73,7 @@
move_intent = using
if(hud_data.has_drop)
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.color = ui_color
using.alpha = ui_alpha
@@ -83,119 +81,108 @@
if(hud_data.has_hands)
- using = new /atom/movable/screen/human/equip
+ using = new /atom/movable/screen/human/equip(null, src)
using.icon = ui_style
using.plane = ABOVE_HUD_PLANE
using.color = ui_color
using.alpha = ui_alpha
static_inventory += using
- inv_box = new /atom/movable/screen/inventory/hand/right()
+ inv_box = new /atom/movable/screen/inventory/hand/right(null, src)
inv_box.icon = ui_style
- if(owner && !owner.hand) //This being 0 or null means the right hand is in use
- inv_box.add_overlay("hand_active")
inv_box.slot_id = SLOT_R_HAND
inv_box.color = ui_color
inv_box.alpha = ui_alpha
+ inv_box.update_icon()
r_hand_hud_object = inv_box
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory/hand()
+ inv_box = new /atom/movable/screen/inventory/hand/left(null, src)
inv_box.setDir(EAST)
inv_box.icon = ui_style
- if(owner?.hand) //This being 1 means the left hand is in use
- inv_box.add_overlay("hand_active")
inv_box.slot_id = SLOT_L_HAND
inv_box.color = ui_color
inv_box.alpha = ui_alpha
+ inv_box.update_icon()
l_hand_hud_object = inv_box
static_inventory += inv_box
- using = new /atom/movable/screen/swap_hand/human()
+ using = new /atom/movable/screen/swap_hand/human(null, src)
using.icon = ui_style
using.color = ui_color
using.alpha = ui_alpha
static_inventory += using
- using = new /atom/movable/screen/swap_hand/right()
+ using = new /atom/movable/screen/swap_hand/right(null, src)
using.icon = ui_style
using.color = ui_color
using.alpha = ui_alpha
static_inventory += using
if(hud_data.has_resist)
- using = new /atom/movable/screen/resist()
+ using = new /atom/movable/screen/resist(null, src)
using.icon = ui_style
using.color = ui_color
using.alpha = ui_alpha
hotkeybuttons += using
if(hud_data.has_throw)
- throw_icon = new /atom/movable/screen/throw_catch()
+ throw_icon = new /atom/movable/screen/throw_catch(null, src)
throw_icon.icon = ui_style
throw_icon.color = ui_color
throw_icon.alpha = ui_alpha
hotkeybuttons += throw_icon
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.update_icon(owner)
+ pull_icon.update_icon()
hotkeybuttons += pull_icon
if(hud_data.has_warnings)
- oxygen_icon = new /atom/movable/screen/oxygen()
+ oxygen_icon = new /atom/movable/screen/oxygen(null, src)
infodisplay += oxygen_icon
- toxin_icon = new /atom/movable/screen()
- toxin_icon.icon_state = "tox0"
- toxin_icon.name = "toxin"
- toxin_icon.screen_loc = ui_toxin
+ toxin_icon = new /atom/movable/screen/toxin(null, src)
infodisplay += toxin_icon
- fire_icon = new /atom/movable/screen/fire()
+ fire_icon = new /atom/movable/screen/fire(null, src)
infodisplay += fire_icon
- healths = new /atom/movable/screen/healths()
+ healths = new /atom/movable/screen/healths(null, src)
infodisplay += healths
- staminas = new
+ staminas = new /atom/movable/screen/stamina_hud(null, src)
infodisplay += staminas
if(hud_data.has_pressure)
- pressure_icon = new /atom/movable/screen()
- pressure_icon.icon_state = "pressure0"
- pressure_icon.name = "pressure"
- pressure_icon.screen_loc = ui_pressure
+ pressure_icon = new /atom/movable/screen/pressure(null, src)
infodisplay += pressure_icon
if(hud_data.has_bodytemp)
- bodytemp_icon = new /atom/movable/screen/bodytemp()
+ bodytemp_icon = new /atom/movable/screen/bodytemp(null, src)
infodisplay += bodytemp_icon
if(hud_data.has_nutrition)
- nutrition_icon = new /atom/movable/screen()
- nutrition_icon.icon_state = "nutrition0"
- nutrition_icon.name = "nutrition"
- nutrition_icon.screen_loc = ui_nutrition
+ nutrition_icon = new /atom/movable/screen/nutrition(null, src)
infodisplay += nutrition_icon
- rest_icon = new /atom/movable/screen/rest()
+ rest_icon = new /atom/movable/screen/rest(null, src)
rest_icon.icon = ui_style
rest_icon.color = ui_color
rest_icon.alpha = ui_alpha
- rest_icon.update_icon(owner)
+ rest_icon.update_icon()
static_inventory += rest_icon
//squad leader locator
- SL_locator = new /atom/movable/screen/SL_locator
+ SL_locator = new /atom/movable/screen/SL_locator(null, src)
infodisplay += SL_locator
- zone_sel = new /atom/movable/screen/zone_sel()
+ zone_sel = new /atom/movable/screen/zone_sel(null, src)
zone_sel.icon = ui_style
zone_sel.color = ui_color
zone_sel.alpha = ui_alpha
- zone_sel.update_icon(owner)
+ zone_sel.set_selected_zone(BODY_ZONE_CHEST, owner)
static_inventory += zone_sel
diff --git a/code/_onclick/hud/interactive_emotes.dm b/code/_onclick/hud/interactive_emotes.dm
new file mode 100644
index 0000000000000..f52cfdcdaace5
--- /dev/null
+++ b/code/_onclick/hud/interactive_emotes.dm
@@ -0,0 +1,274 @@
+///All in one function to begin interactions
+/mob/proc/interaction_emote(mob/target)
+ if(!target || target == src)
+ return
+
+ var/list/interactions_list = list("Headbutt" = /atom/movable/screen/interaction/headbutt) //Universal interactions
+ if(isxeno(src)) //Benos don't high five each other, they slap tails! A beno cannot initiate a high five, but can recieve one if prompted by a human
+ interactions_list["Tail Slap"] = /atom/movable/screen/interaction/fist_bump
+ else
+ interactions_list["High Five"] = /atom/movable/screen/interaction
+ interactions_list["Fist Bump"] = /atom/movable/screen/interaction/fist_bump
+
+ var/atom/movable/screen/interaction/interaction = interactions_list[tgui_input_list(src, "Select an interaction type", "Interactive Emotes", interactions_list)]
+
+ if(!interaction)
+ return
+
+ if(LAZYLEN(target.queued_interactions))
+ for(var/atom/movable/screen/interaction/element AS in target.queued_interactions)
+ if(element.initiator == src)
+ balloon_alert(src, "Slow your roll!")
+ return
+
+ interaction = new interaction()
+ interaction.owner = target
+ interaction.initiator = src
+ interaction.register_movement_signals()
+ LAZYADD(target.queued_interactions, interaction)
+
+ if(target.client && target.hud_used)
+ target.hud_used.update_interactive_emotes()
+
+ interaction.transform = matrix(32, 6, MATRIX_TRANSLATE)
+ animate(interaction, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
+
+ interaction.timer_id = addtimer(CALLBACK(interaction, TYPE_PROC_REF(/atom/movable/screen/interaction, end_interaction), FALSE), interaction.timeout, TIMER_STOPPABLE|TIMER_UNIQUE)
+
+//Mob interactions
+/atom/movable/screen/interaction
+ name = "high five"
+ desc = "You gonna leave them hanging?"
+ icon = 'icons/mob/screen_alert.dmi'
+ icon_state = "drunk2" //It looks jolly
+ ///Sound filed played when interaction is successful
+ var/interaction_sound = 'sound/effects/snap.ogg'
+ ///Who this offer for interaction is being made to
+ var/mob/owner
+ ///The mob that initiated the interaction
+ var/mob/initiator
+ ///Clear itself after a certain amount of time
+ var/timeout = 10 SECONDS
+ ///The reference to the existing timer
+ var/timer_id
+
+/atom/movable/screen/interaction/Initialize(mob/user)
+ . = ..()
+ desc += "\nLeft-click to accept interaction. Right-click or SHIFT + left-click to decline."
+
+///Separate proc to register signals; not on Initialize because owner and initiator are not set yet
+/atom/movable/screen/interaction/proc/register_movement_signals()
+ RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(interactees_moved))
+ RegisterSignal(initiator, COMSIG_MOVABLE_MOVED, PROC_REF(interactees_moved))
+
+///What to do when either the owner or the initiating mob moves
+/atom/movable/screen/interaction/proc/interactees_moved()
+ SIGNAL_HANDLER
+ if(!owner.Adjacent(initiator))
+ end_interaction(FALSE)
+
+///Functions to end the interaction
+/atom/movable/screen/interaction/proc/end_interaction(success = TRUE)
+ if(!success)
+ owner.visible_message(failure_message())
+ qdel(src)
+
+//Delete itself from the owner's hud and list of queued interactions
+/atom/movable/screen/interaction/Destroy()
+ deltimer(timer_id)
+ LAZYREMOVE(owner.queued_interactions, src)
+ if(owner.client && owner.hud_used)
+ owner.client.screen -= src
+ owner.hud_used.update_interactive_emotes()
+
+ return ..()
+
+/atom/movable/screen/interaction/RightClick(mob/user)
+ . = ..()
+ end_interaction(FALSE)
+
+/atom/movable/screen/interaction/ShiftClick(mob/user)
+ . = ..()
+ end_interaction(FALSE)
+
+/atom/movable/screen/interaction/Click(location, control, params)
+ var/list/modifiers = params2list(params)
+ if(modifiers[SHIFT_CLICK] || modifiers[RIGHT_CLICK]) //These modifiers will deny the interaction
+ return ..()
+
+ if(usr != owner || !can_interact(owner))
+ end_interaction(FALSE)
+ return FALSE
+
+ //Begin interaction functions
+ interaction_animation()
+
+ owner.visible_message(success_message())
+ playsound(owner, interaction_sound, 50, TRUE)
+ end_interaction()
+
+///Seperate proc meant to be overriden for unique animations
+/atom/movable/screen/interaction/proc/interaction_animation()
+ owner.face_atom(initiator)
+ initiator.face_atom(owner)
+
+ //Calculate the distances between the two mobs
+ var/x_distance = owner.x - initiator.x
+ var/y_distance = owner.y - initiator.y
+
+ animate(owner, pixel_x = owner.pixel_x - x_distance * 8, pixel_y = owner.pixel_y - y_distance * 8, time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(owner.pixel_x), pixel_y = initial(owner.pixel_y), time = 0.1 SECONDS)
+ animate(initiator, pixel_x = initiator.pixel_x + x_distance * 8, pixel_y = initiator.pixel_y + y_distance * 8, time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(initiator.pixel_x), pixel_y = initial(initiator.pixel_y), time = 0.1 SECONDS)
+
+///Returns a string for successful interactions
+/atom/movable/screen/interaction/proc/success_message()
+ return "[owner] high fives [initiator]!"
+
+///Returns a string for unsuccessful interactions
+/atom/movable/screen/interaction/proc/failure_message()
+ return "[owner] left [initiator] hanging in the air..."
+
+//Following 2 procs are for tooltip functionality; taken from action buttons
+/atom/movable/screen/interaction/MouseEntered(location, control, params)
+ if(!usr.client?.prefs?.tooltips)
+ return
+ openToolTip(usr, src, params, title = name, content = desc)
+
+/atom/movable/screen/interaction/MouseExited()
+ if(!usr.client?.prefs?.tooltips)
+ return
+ closeToolTip(usr)
+
+/atom/movable/screen/interaction/fist_bump
+ name = "fist bump"
+ desc = "Bro."
+ interaction_sound = 'sound/weapons/throwtap.ogg'
+
+//Benos turn around and slap with their tail instead of a fist bump
+/atom/movable/screen/interaction/fist_bump/interaction_animation()
+ owner.face_atom(initiator)
+ initiator.face_atom(owner)
+
+ var/x_distance = owner.x - initiator.x
+ var/y_distance = owner.y - initiator.y
+
+ if(isxeno(owner))
+ animate(owner, pixel_x = owner.pixel_x - x_distance * 8, pixel_y = owner.pixel_y - y_distance * 8, dir = initiator.dir,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ owner.face_atom(initiator)
+ else
+ animate(owner, pixel_x = owner.pixel_x - x_distance * 8, pixel_y = owner.pixel_y - y_distance * 8,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(owner.pixel_x), pixel_y = initial(owner.pixel_y), time = 0.1 SECONDS)
+
+ if(isxeno(initiator))
+ animate(initiator, pixel_x = initiator.pixel_x + x_distance * 8, pixel_y = initiator.pixel_y + y_distance * 8, dir = owner.dir,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ initiator.face_atom(owner)
+ else
+ animate(initiator, pixel_x = initiator.pixel_x + x_distance * 8, pixel_y = initiator.pixel_y + y_distance * 8,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(initiator.pixel_x), pixel_y = initial(initiator.pixel_y), time = 0.1 SECONDS)
+
+//We support interspecies bumping of fists and tails!
+/atom/movable/screen/interaction/fist_bump/success_message()
+ var/owner_xeno = isxeno(owner)
+ var/initiator_xeno = isxeno(initiator)
+ if(owner_xeno && initiator_xeno)
+ return "[owner] and [initiator] slap tails together!"
+ if(owner_xeno)
+ return "[owner] slaps [initiator]'s fist!"
+ if(initiator_xeno)
+ return "[owner] fist bumps [initiator]'s tail!"
+ return "[owner] fist bumps [initiator]!"
+
+/atom/movable/screen/interaction/fist_bump/failure_message()
+ return "[owner] left [initiator] hanging. Not cool!"
+
+/atom/movable/screen/interaction/headbutt
+ name = "head bump"
+ desc = "Touch skulls."
+ interaction_sound = 'sound/weapons/throwtap.ogg'
+
+/atom/movable/screen/interaction/headbutt/interaction_animation()
+ owner.face_atom(initiator)
+ initiator.face_atom(owner)
+
+ var/x_distance = owner.x - initiator.x
+ var/y_distance = owner.y - initiator.y
+
+ var/matrix/owner_matrix = owner.transform
+ var/matrix/initiator_matrix = initiator.transform
+ var/rotation_angle
+ //This was so much pain, maintainers forgive me
+ if(owner.dir & (EAST | WEST))
+ if(isxenorunner(owner)) //Rounies get special upwards headbutts
+ rotation_angle = owner.dir & EAST ? -15 : 15
+ else
+ rotation_angle = owner.dir & EAST ? 15 : -15
+
+ //The animation if the mobs face east/west is to rotate their heads together
+ animate(owner, pixel_x = owner.pixel_x - x_distance * 8, pixel_y = owner.pixel_y - y_distance * 8,
+ transform = owner_matrix.Turn(rotation_angle), time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(owner.pixel_x), pixel_y = initial(owner.pixel_y),
+ transform = owner_matrix.Turn(-rotation_angle), time = 0.1 SECONDS)
+ else
+ //If facing north or south, basically the same animation as the high five but move even closer
+ animate(owner, pixel_x = owner.pixel_x - x_distance * 8, pixel_y = owner.pixel_y - y_distance * 16,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(owner.pixel_x), pixel_y = initial(owner.pixel_y), time = 0.1 SECONDS)
+
+ if(initiator.dir & (EAST | WEST))
+ if(isxenorunner(initiator))
+ rotation_angle = initiator.dir & EAST ? -15 : 15
+ else
+ rotation_angle = initiator.dir & EAST ? 15 : -15
+
+ animate(initiator, pixel_x = initiator.pixel_x + x_distance * 8, pixel_y = initiator.pixel_y + y_distance * 8,
+ transform = initiator_matrix.Turn(rotation_angle), time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(initiator.pixel_x), pixel_y = initial(initiator.pixel_y),
+ transform = initiator_matrix.Turn(-rotation_angle), time = 0.1 SECONDS)
+ else
+ animate(initiator, pixel_x = initiator.pixel_x + x_distance * 8, pixel_y = initiator.pixel_y + y_distance * 16,
+ time = 0.5 SECONDS, easing = BACK_EASING, flags = ANIMATION_PARALLEL)
+ animate(pixel_x = initial(initiator.pixel_x), pixel_y = initial(initiator.pixel_y), time = 0.1 SECONDS)
+
+/atom/movable/screen/interaction/headbutt/success_message()
+ return "[owner] and [initiator] bonk heads together!!"
+
+/atom/movable/screen/interaction/headbutt/failure_message()
+ return "[owner] did not headbutt [initiator]..."
+
+/* HUD code */
+///Update the hud; taken from how alerts do it, but slimmed down
+/datum/hud/proc/update_interactive_emotes()
+ var/mob/viewer = mymob
+ if(!viewer.client)
+ return
+
+ var/list/queued_interactions = LAZYLISTDUPLICATE(mymob.queued_interactions)
+ if(!LAZYLEN(queued_interactions)) //No interactions to show
+ return FALSE
+
+ if(!hud_shown) //Clear the hud of interaction button(s)
+ for(var/atom/movable/screen/interaction/interaction AS in queued_interactions)
+ viewer.client.screen -= interaction
+ return TRUE
+
+ //I don't want to mess with screen real estate so it will only show the first interaction in the list until it's dismissed/expired
+ var/atom/movable/screen/interaction/interaction = LAZYACCESS(queued_interactions, 1)
+ interaction.screen_loc = "EAST-1:28,TOP-1:28"
+ viewer.client.screen |= interaction
+ return TRUE
+
+//If anyone wants to add more interactions, here is an easy test item to use, just be sure to comment out any can_interact checks and to use the target tgui input list
+/obj/item/interaction_tester
+ name = "interaction tester"
+ icon_state = "coin"
+
+/obj/item/interaction_tester/attack_self(mob/user)
+ var/mob/target = tgui_input_list(user, "Select a target", "Select a target", GLOB.alive_living_list)
+ if(!target)
+ return
+ target.interaction_emote(user)
diff --git a/code/_onclick/map_popups.dm b/code/_onclick/hud/map_popups.dm
similarity index 93%
rename from code/_onclick/map_popups.dm
rename to code/_onclick/hud/map_popups.dm
index 7c40f654ffd94..45e26576b239d 100644
--- a/code/_onclick/map_popups.dm
+++ b/code/_onclick/hud/map_popups.dm
@@ -1,12 +1,3 @@
-/**
- * A screen object, which acts as a container for turfs and other things
- * you want to show on the map, which you usually attach to "vis_contents".
- */
-/atom/movable/screen/map_view
- // Map view has to be on the lowest plane to enable proper lighting
- layer = GAME_PLANE
- plane = GAME_PLANE
-
/**
* A generic background object.
* It is also implicitly used to allocate a rectangle on the map, which will
diff --git a/code/_onclick/hud/map_view.dm b/code/_onclick/hud/map_view.dm
new file mode 100644
index 0000000000000..55d3be626c823
--- /dev/null
+++ b/code/_onclick/hud/map_view.dm
@@ -0,0 +1,11 @@
+/**
+ * A screen object, which acts as a container for turfs and other things
+ * you want to show on the map, which you usually attach to "vis_contents".
+ */
+INITIALIZE_IMMEDIATE(/atom/movable/screen/map_view)
+/atom/movable/screen/map_view
+ name = "screen"
+ // Map view has to be on the lowest plane to enable proper lighting
+ layer = GAME_PLANE
+ plane = GAME_PLANE
+ del_on_map_removal = FALSE
diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
index 55c108e6e6720..8e2b8525b8ac9 100644
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -7,12 +7,12 @@
if(!length(C.parallax_layers_cached))
C.parallax_layers_cached = list()
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, C.view)
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, C.view)
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, C.view)
+ C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, src, C.view)
+ C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, src, C.view)
+ C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, src, C.view)
if(SSparallax.random_layer)
- C.parallax_layers_cached += new SSparallax.random_layer
- C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, C.view)
+ C.parallax_layers_cached += new SSparallax.random_layer(null, src, C.view)
+ C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, src, C.view)
C.parallax_layers = C.parallax_layers_cached.Copy()
@@ -238,7 +238,7 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-/atom/movable/screen/parallax_layer/Initialize(mapload, view)
+/atom/movable/screen/parallax_layer/Initialize(mapload, datum/hud/hud_owner, view)
. = ..()
if (!view)
view = world.view
@@ -289,7 +289,7 @@
/atom/movable/screen/parallax_layer/random/space_gas
icon_state = "space_gas"
-/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, view)
+/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, datum/hud/hud_owner, view)
. = ..()
src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY)
diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm
index e5f96dbf3b5a8..3f47c2d6bb27d 100644
--- a/code/_onclick/hud/picture_in_picture.dm
+++ b/code/_onclick/hud/picture_in_picture.dm
@@ -15,7 +15,7 @@
var/const/max_dimensions = 10
-/atom/movable/screen/movable/pic_in_pic/Initialize(mapload)
+/atom/movable/screen/movable/pic_in_pic/Initialize(mapload, datum/hud/hud_owner)
. = ..()
make_backgrounds()
@@ -60,7 +60,7 @@
add_overlay(move_tab)
if(!button_x)
- button_x = new /atom/movable/screen/component_button(null, src)
+ button_x = new /atom/movable/screen/component_button(null, null, src)
var/mutable_appearance/MA = new /mutable_appearance()
MA.name = "close"
MA.icon = 'icons/misc/pic_in_pic.dmi'
@@ -73,7 +73,7 @@
vis_contents += button_x
if(!button_expand)
- button_expand = new /atom/movable/screen/component_button(null, src)
+ button_expand = new /atom/movable/screen/component_button(null, null, src)
var/mutable_appearance/MA = new /mutable_appearance()
MA.name = "expand"
MA.icon = 'icons/misc/pic_in_pic.dmi'
@@ -86,7 +86,7 @@
vis_contents += button_expand
if(!button_shrink)
- button_shrink = new /atom/movable/screen/component_button(null, src)
+ button_shrink = new /atom/movable/screen/component_button(null, null, src)
var/mutable_appearance/MA = new /mutable_appearance()
MA.name = "shrink"
MA.icon = 'icons/misc/pic_in_pic.dmi'
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 94a0e95b7a8cf..9822401ebea53 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
if(length(elements) < max_elements)
var/elements_to_add = max_elements - length(elements)
for(var/i in 1 to elements_to_add) //Create all elements
- var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice
+ var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice()
new_element.tooltips = use_tooltips
new_element.parent = src
elements += new_element
diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/_plane_master.dm
similarity index 55%
rename from code/_onclick/hud/rendering/plane_master.dm
rename to code/_onclick/hud/rendering/_plane_master.dm
index 4b62945149386..570e12b650f62 100644
--- a/code/_onclick/hud/rendering/plane_master.dm
+++ b/code/_onclick/hud/rendering/_plane_master.dm
@@ -17,12 +17,142 @@
///reference to render relay screen object to avoid backdropping multiple times
var/atom/movable/render_plane_relay/relay
+ /// If our plane master allows for offsetting
+ /// Mostly used for planes that really don't need to be duplicated, like the hud planes
+ var/allows_offsetting = TRUE
+ /// Our offset from our "true" plane, see below
+ var/offset
+ /// When rendering multiz, lower levels get their own set of plane masters
+ /// Real plane here represents the "true" plane value of something, ignoring the offset required to handle lower levels
+ var/real_plane
+
+ /// list of current relays this plane is utilizing to render
+ var/list/atom/movable/render_plane_relay/relays = list()
+
+ /// If this plane master should be hidden from the player at roundstart
+ /// We do this so PMs can opt into being temporary, to reduce load on clients
+ var/start_hidden = FALSE
+ /// If this plane master is being forced to hide.
+ /// Hidden PMs will dump ANYTHING relayed or drawn onto them. Be careful with this
+ /// Remember: a hidden plane master will dump anything drawn directly to it onto the output render. It does NOT hide its contents
+ /// Use alpha for that
+ var/force_hidden = FALSE
+
+ /// If this plane should be scaled by multiz
+ /// Planes with this set should NEVER be relay'd into each other, as that will cause visual fuck
+ var/multiz_scaled = TRUE
+
+ /// Bitfield that describes how this plane master will render if its z layer is being "optimized"
+ /// If a plane master is NOT critical, it will be completely dropped if we start to render outside a client's multiz boundary prefs
+ /// Of note: most of the time we will relay renders to non critical planes in this stage. so the plane master will end up drawing roughly "in order" with its friends
+ /// This is NOT done for parallax and other problem children, because the rules of BLEND_MULTIPLY appear to not behave as expected :(
+ /// This will also just make debugging harder, because we do fragile things in order to ensure things operate as epected. I'm sorry
+ /// Compile time
+ /// See [code\__DEFINES\layers.dm] for our bitflags
+ var/critical = NONE
+
+ /// If this plane master is outside of our visual bounds right now
+ var/is_outside_bounds = FALSE
+
/atom/movable/screen/plane_master/proc/Show(override)
alpha = override || show_alpha
+/// Shows a plane master to the passed in mob
+/// Override this to apply unique effects and such
+/// Returns TRUE if the call is allowed, FALSE otherwise
+/atom/movable/screen/plane_master/proc/show_to(mob/mymob)
+ SHOULD_CALL_PARENT(TRUE)
+ if(force_hidden)
+ return FALSE
+
+ var/client/our_client = mymob?.canon_client
+ // Alright, let's get this out of the way
+ // Mobs can move z levels without their client. If this happens, we need to ensure critical display settings are respected
+ // This is done here. Mild to severe pain but it's nessesary
+ if(check_outside_bounds())
+ if(!(critical & PLANE_CRITICAL_DISPLAY))
+ return FALSE
+ if(!our_client)
+ return TRUE
+ our_client.screen += src
+
+ if(!(critical & PLANE_CRITICAL_NO_RELAY))
+ our_client.screen += relays
+ return TRUE
+ return TRUE
+
+ if(!our_client)
+ return TRUE
+
+ our_client.screen += src
+ our_client.screen += relays
+ return TRUE
+
+/// Hook to allow planes to work around is_outside_bounds
+/// Return false to allow a show, true otherwise
+/atom/movable/screen/plane_master/proc/check_outside_bounds()
+ return is_outside_bounds
+
/atom/movable/screen/plane_master/proc/Hide(override)
alpha = override || hide_alpha
+/// Hides a plane master from the passeed in mob
+/// Do your effect cleanup here
+/atom/movable/screen/plane_master/proc/hide_from(mob/oldmob)
+ SHOULD_CALL_PARENT(TRUE)
+ var/client/their_client = oldmob?.client
+ if(!their_client)
+ return
+ their_client.screen -= src
+ their_client.screen -= relays
+
+/// Forces this plane master to hide, until unhide_plane is called
+/// This allows us to disable unused PMs without breaking anything else
+/atom/movable/screen/plane_master/proc/hide_plane(mob/cast_away)
+ force_hidden = TRUE
+ hide_from(cast_away)
+
+/// Disables any forced hiding, allows the plane master to be used as normal
+/atom/movable/screen/plane_master/proc/unhide_plane(mob/enfold)
+ force_hidden = FALSE
+ show_to(enfold)
+
+/atom/movable/screen/plane_master/proc/outside_bounds(mob/relevant)
+ if(force_hidden || is_outside_bounds)
+ return
+ is_outside_bounds = TRUE
+ // If we're of critical importance, AND we're below the rendering layer
+ if(critical & PLANE_CRITICAL_DISPLAY)
+ // We here assume that your render target starts with *
+ if(critical & PLANE_CRITICAL_CUT_RENDER && render_target)
+ render_target = copytext_char(render_target, 2)
+ if(!(critical & PLANE_CRITICAL_NO_RELAY))
+ return
+ var/client/our_client = relevant.client
+ if(our_client)
+ for(var/atom/movable/render_plane_relay/relay as anything in relays)
+ our_client.screen -= relay
+
+ return
+ hide_from(relevant)
+
+/atom/movable/screen/plane_master/proc/inside_bounds(mob/relevant)
+ is_outside_bounds = FALSE
+ if(critical & PLANE_CRITICAL_DISPLAY)
+ // We here assume that your render target starts with *
+ if(critical & PLANE_CRITICAL_CUT_RENDER && render_target)
+ render_target = "*[render_target]"
+
+ if(!(critical & PLANE_CRITICAL_NO_RELAY))
+ return
+ var/client/our_client = relevant.client
+ if(our_client)
+ for(var/atom/movable/render_plane_relay/relay as anything in relays)
+ our_client.screen += relay
+
+ return
+ show_to(relevant)
+
//Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928
//Trust me, you need one. Period. If you don't think you do, you're doing something extremely wrong.
/atom/movable/screen/plane_master/proc/backdrop(mob/mymob)
@@ -45,7 +175,7 @@
appearance_flags = PLANE_MASTER
render_relay_plane = RENDER_PLANE_GAME
-/atom/movable/screen/plane_master/openspace/Initialize(mapload)
+/atom/movable/screen/plane_master/openspace/Initialize(mapload, datum/hud/hud_owner)
. = ..()
add_filter("first_stage_openspace", 1, drop_shadow_filter(color = "#04080FAA", size = -10))
add_filter("second_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -15))
@@ -80,6 +210,13 @@
return
add_filter("eye_blur", 1, gauss_blur_filter(clamp(mymob.eye_blurry * 0.1, 0.6, 3)))
+//Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them.
+/atom/movable/screen/plane_master/seethrough
+ name = "Seethrough"
+ plane = SEETHROUGH_PLANE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ render_relay_plane = RENDER_PLANE_GAME
+
/**
* Plane master handling byond internal blackness
* vars are set as to replicate behavior when rendering to other planes
@@ -118,7 +255,7 @@
mymob.overlay_fullscreen("lighting_backdrop", /atom/movable/screen/fullscreen/lighting_backdrop/backplane)
mymob.overlay_fullscreen("lighting_backdrop_lit_secondary", /atom/movable/screen/fullscreen/lighting_backdrop/lit_secondary)
-/atom/movable/screen/plane_master/lighting/Initialize(mapload)
+/atom/movable/screen/plane_master/lighting/Initialize(mapload, datum/hud/hud_owner)
. = ..()
add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
@@ -133,7 +270,7 @@
render_target = EMISSIVE_RENDER_TARGET
render_relay_plane = null
-/atom/movable/screen/plane_master/emissive/Initialize(mapload)
+/atom/movable/screen/plane_master/emissive/Initialize(mapload, datum/hud/hud_owner)
. = ..()
add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix))
diff --git a/code/_onclick/hud/rendering/plane_master_group.dm b/code/_onclick/hud/rendering/plane_master_group.dm
new file mode 100644
index 0000000000000..322b1c3f62b57
--- /dev/null
+++ b/code/_onclick/hud/rendering/plane_master_group.dm
@@ -0,0 +1,205 @@
+/// Datum that represents one "group" of plane masters
+/// So all the main window planes would be in one, all the spyglass planes in another
+/// Etc
+/datum/plane_master_group
+ /// Our key in the group list on /datum/hud
+ /// Should be unique for any group of plane masters in the world
+ var/key
+ /// Our parent hud
+ var/datum/hud/our_hud
+ /// List in the form "[plane]" = object, the plane masters we own
+ var/list/atom/movable/screen/plane_master/plane_masters = list()
+ /// The visual offset we are currently using
+ var/active_offset = 0
+ /// What, if any, submap we render onto
+ var/map = ""
+ /// Controls the screen_loc that owned plane masters will use when generating relays. Due to a Byond bug, relays using the CENTER positional loc
+ /// Will be improperly offset
+ var/relay_loc = "CENTER"
+
+/datum/plane_master_group/New(key, map = "")
+ . = ..()
+ src.key = key
+ src.map = map
+ build_plane_masters(0, SSmapping.max_plane_offset)
+
+/datum/plane_master_group/Destroy()
+ orphan_hud()
+ QDEL_LIST_ASSOC_VAL(plane_masters)
+ return ..()
+
+/// Display a plane master group to some viewer, so show all our planes to it
+/datum/plane_master_group/proc/attach_to(datum/hud/viewing_hud)
+ if(viewing_hud.master_groups[key])
+ stack_trace("Hey brother, our key [key] is already in use by a plane master group on the passed in hud, belonging to [viewing_hud.mymob]. Ya fucked up, why are there dupes")
+ return
+
+ our_hud = viewing_hud
+ our_hud.master_groups[key] = src
+ show_hud()
+ transform_lower_turfs(our_hud, active_offset)
+
+/// Hide the plane master from its current hud, fully clear it out
+/datum/plane_master_group/proc/orphan_hud()
+ if(our_hud)
+ our_hud.master_groups -= key
+ hide_hud()
+ our_hud = null
+
+/// Well, refresh our group, mostly useful for plane specific updates
+/datum/plane_master_group/proc/refresh_hud()
+ hide_hud()
+ show_hud()
+
+/// Fully regenerate our group, resetting our planes to their compile time values
+/datum/plane_master_group/proc/rebuild_hud()
+ hide_hud()
+ rebuild_plane_masters()
+ show_hud()
+ transform_lower_turfs(our_hud, active_offset)
+
+/// Regenerate our plane masters, this is useful if we don't have a mob but still want to rebuild. Such in the case of changing the screen_loc of relays
+/datum/plane_master_group/proc/rebuild_plane_masters()
+ QDEL_LIST_ASSOC_VAL(plane_masters)
+ build_plane_masters(0, SSmapping.max_plane_offset)
+
+/datum/plane_master_group/proc/hide_hud()
+ for(var/thing in plane_masters)
+ var/atom/movable/screen/plane_master/plane = plane_masters[thing]
+ plane.hide_from(our_hud.mymob)
+
+/datum/plane_master_group/proc/show_hud()
+ for(var/thing in plane_masters)
+ var/atom/movable/screen/plane_master/plane = plane_masters[thing]
+ show_plane(plane)
+
+/// This is mostly a proc so it can be overriden by popups, since they have unique behavior they want to do
+/datum/plane_master_group/proc/show_plane(atom/movable/screen/plane_master/plane)
+ plane.show_to(our_hud.mymob)
+
+/// Nice wrapper for the "[]"ing
+/datum/plane_master_group/proc/get_plane(plane)
+ return plane_masters["[plane]"]
+
+/// Returns a list of all the plane master types we want to create
+/datum/plane_master_group/proc/get_plane_types()
+ return subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/rendering_plate
+
+/// Actually generate our plane masters, in some offset range (where offset is the z layers to render to, because each "layer" in a multiz stack gets its own plane master cube)
+/datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset)
+ for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types())
+ for(var/plane_offset in starting_offset to ending_offset)
+ if(plane_offset != 0 && !initial(mytype.allows_offsetting))
+ continue
+ var/atom/movable/screen/plane_master/instance = new mytype(null, null, src, plane_offset)
+ plane_masters["[instance.plane]"] = instance
+ prep_plane_instance(instance)
+
+/// Similarly, exists so subtypes can do unique behavior to planes on creation
+/datum/plane_master_group/proc/prep_plane_instance(atom/movable/screen/plane_master/instance)
+ return
+
+// It would be nice to setup parallaxing for stairs and things when doing this
+// So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work
+// It's hard, and potentially expensive. be careful
+/datum/plane_master_group/proc/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
+ // Check if this feature is disabled for the client, in which case don't use scale.
+ var/mob/our_mob = our_hud?.mymob
+
+ // No offset? piss off
+ if(!SSmapping.max_plane_offset)
+ return
+
+ active_offset = new_offset
+
+ // Each time we go "down" a visual z level, we'll reduce the scale by this amount
+ // Chosen because mothblocks liked it, didn't cause motion sickness while also giving a sense of height
+ var/scale_by = 0.965
+ scale_by = 1
+
+ var/list/offsets = list()
+
+ // We accept negatives so going down "zooms" away the drop above as it goes
+ for(var/offset in -SSmapping.max_plane_offset to SSmapping.max_plane_offset)
+
+ // No transformations if we're landing ON you
+ if(offset == 0)
+ offsets += null
+ continue
+
+ var/scale = scale_by ** (offset)
+ var/matrix/multiz_shrink = matrix()
+ multiz_shrink.Scale(scale)
+ offsets += multiz_shrink
+
+ // So we can talk in 1 -> max_offset * 2 + 1, rather then -max_offset -> max_offset
+ var/offset_offset = SSmapping.max_plane_offset + 1
+
+ for(var/plane_key in plane_masters)
+ var/atom/movable/screen/plane_master/plane = plane_masters[plane_key]
+ if(!plane.allows_offsetting)
+ continue
+
+ var/visual_offset = plane.offset - new_offset
+
+ // Basically uh, if we're showing something down X amount of levels, or up any amount of levels
+ if(plane.is_outside_bounds)
+ plane.inside_bounds(our_mob)
+
+ if(!plane.multiz_scaled)
+ continue
+
+ if(plane.force_hidden || plane.is_outside_bounds || visual_offset < 0)
+ // We don't animate here because it should be invisble, but we do mark because it'll look nice
+ plane.transform = offsets[visual_offset + offset_offset]
+ continue
+
+ animate(plane, transform = offsets[visual_offset + offset_offset], 0.05 SECONDS, easing = LINEAR_EASING)
+
+/// Holds plane masters for popups, like camera windows
+/// Note: We do not scale this plane, even though we could
+/// This is because it's annoying to get turfs to position inside it correctly
+/// If you wanna try someday feel free, but I can't manage it
+/datum/plane_master_group/popup
+
+/// This is janky as hell but since something changed with CENTER positioning after build 1614 we have to switch to the bandaid LEFT,TOP positioning
+/// using LEFT,TOP *at* or *before* 1614 will result in another broken offset for cameras
+#define MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS 1614
+
+/datum/plane_master_group/popup/attach_to(datum/hud/viewing_hud)
+ // If we're about to display this group to a mob who's client is more recent than the last known version with working CENTER, then we need to remake the relays
+ // with the correct screen_loc using the relay override
+ if(viewing_hud.mymob?.client?.byond_build > MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS)
+ relay_loc = "LEFT,TOP"
+ rebuild_plane_masters()
+ return ..()
+
+#undef MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS
+
+/datum/plane_master_group/popup/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
+ return ..(source, new_offset, FALSE)
+
+/// Holds the main plane master
+/datum/plane_master_group/main
+
+/datum/plane_master_group/main/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
+ if(use_scale)
+ return ..(source, new_offset, source.should_use_scale())
+ return ..()
+
+/// Hudless group. Exists for testing
+/datum/plane_master_group/hudless
+ var/mob/our_mob
+
+/datum/plane_master_group/hudless/Destroy()
+ . = ..()
+ our_mob = null
+
+/datum/plane_master_group/hudless/hide_hud()
+ for(var/thing in plane_masters)
+ var/atom/movable/screen/plane_master/plane = plane_masters[thing]
+ plane.hide_from(our_mob)
+
+/// This is mostly a proc so it can be overriden by popups, since they have unique behavior they want to do
+/datum/plane_master_group/hudless/show_plane(atom/movable/screen/plane_master/plane)
+ plane.show_to(our_mob)
diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm
index d3e67e40f65ec..b4b45b512f996 100644
--- a/code/_onclick/hud/rendering/render_plate.dm
+++ b/code/_onclick/hud/rendering/render_plate.dm
@@ -40,7 +40,7 @@
plane = RENDER_PLANE_GAME
render_relay_plane = RENDER_PLANE_MASTER
-/atom/movable/screen/plane_master/rendering_plate/game_world/Initialize(mapload)
+/atom/movable/screen/plane_master/rendering_plate/game_world/Initialize(mapload, datum/hud/hud_owner)
. = ..()
add_filter("displacer", 1, displacement_map_filter(render_source = GRAVITY_PULSE_RENDER_TARGET, size = 10))
diff --git a/code/_onclick/hud/screen_objects/menu_text_objects.dm b/code/_onclick/hud/screen_objects/menu_text_objects.dm
index 1b2db453df4ac..234358dfbc85f 100644
--- a/code/_onclick/hud/screen_objects/menu_text_objects.dm
+++ b/code/_onclick/hud/screen_objects/menu_text_objects.dm
@@ -33,7 +33,7 @@
/atom/movable/screen/text/lobby/clickable/MouseEntered(location, control, params)
. = ..()
- if(!(flags_atom & INITIALIZED)) //yes this can happen, fuck me
+ if(!(atom_flags & INITIALIZED)) //yes this can happen, fuck me
return
color = COLOR_ORANGE
var/mob/new_player/player = usr
@@ -44,7 +44,7 @@
color = initial(color)
/atom/movable/screen/text/lobby/clickable/Click()
- if(!(flags_atom & INITIALIZED)) //yes this can happen, fuck me
+ if(!(atom_flags & INITIALIZED)) //yes this can happen, fuck me
to_chat(usr, span_warning("The game is still setting up, please try again later."))
return
var/mob/new_player/player = usr
@@ -159,6 +159,6 @@
/atom/movable/screen/text/lobby/clickable/polls/Click()
. = ..()
var/mob/new_player/player = hud.mymob
- player.handle_playeR_DBRANKSing()
+ player.handle_playeR_POLLSing()
fetch_polls()
diff --git a/code/_onclick/hud/screen_objects/screen_objects.dm b/code/_onclick/hud/screen_objects/screen_objects.dm
index 163705af29ae2..9749d77840203 100644
--- a/code/_onclick/hud/screen_objects/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects/screen_objects.dm
@@ -23,6 +23,11 @@
*/
var/del_on_map_removal = TRUE
+/atom/movable/screen/Initialize(mapload, datum/hud/hud_owner)
+ . = ..()
+ if(hud_owner && istype(hud_owner))
+ hud = hud_owner
+
/atom/movable/screen/Destroy()
master = null
hud = null
@@ -80,9 +85,6 @@
if(isobserver(usr) || usr.incapacitated(TRUE))
return TRUE
- if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank
- return TRUE
-
//If there is an item in the slot you are clicking on, this will relay the click to the item within the slot
var/atom/item_in_slot = usr.get_item_by_slot(slot_id)
if(item_in_slot)
@@ -94,15 +96,20 @@
return TRUE
/atom/movable/screen/inventory/hand
+ ///The tag used by this hand, used for activate_hand()
+ var/hand_tag = ""
+
+/atom/movable/screen/inventory/hand/left
name = "l_hand"
icon_state = "hand_l"
screen_loc = ui_lhand
- var/hand_tag = "l"
+ hand_tag = "l"
-/atom/movable/screen/inventory/hand/update_icon(active = FALSE)
- cut_overlays()
- if(active)
- add_overlay("hand_active")
+/atom/movable/screen/inventory/hand/left/update_overlays()
+ . = ..()
+ if(!hud?.mymob?.hand)
+ return
+ . += "hand_active"
/atom/movable/screen/inventory/hand/Click(location, control, params)
. = ..()
@@ -116,6 +123,12 @@
screen_loc = ui_rhand
hand_tag = "r"
+/atom/movable/screen/inventory/hand/right/update_overlays()
+ . = ..()
+ if(!hud?.mymob || hud.mymob.hand)
+ return
+ . += "hand_active"
+
/atom/movable/screen/close
name = "close"
layer = ABOVE_HUD_LAYER
@@ -168,11 +181,12 @@
usr.toggle_move_intent()
-/atom/movable/screen/mov_intent/update_icon(mob/user)
- if(!user)
+/atom/movable/screen/mov_intent/update_icon_state()
+ . = ..()
+ if(!hud?.mymob)
return
- switch(user.m_intent)
+ switch(hud.mymob.m_intent)
if(MOVE_INTENT_RUN)
icon_state = "running"
if(MOVE_INTENT_WALK)
@@ -191,12 +205,13 @@
if(!isliving(usr))
return
var/mob/living/L = usr
- L.lay_down()
+ L.toggle_resting()
-/atom/movable/screen/rest/update_icon(mob/mymob)
- if(!isliving(mymob))
+/atom/movable/screen/rest/update_icon_state()
+ . = ..()
+ if(!isliving(hud?.mymob))
return
- var/mob/living/L = mymob
+ var/mob/living/L = hud?.mymob
icon_state = "act_rest[L.resting ? "0" : ""]"
/atom/movable/screen/pull
@@ -212,10 +227,11 @@
usr.stop_pulling()
-/atom/movable/screen/pull/update_icon(mob/user)
- if(!user)
+/atom/movable/screen/pull/update_icon_state()
+ . = ..()
+ if(!hud?.mymob)
return
- if(user.pulling)
+ if(hud.mymob.pulling)
icon_state = "pull"
else
icon_state = "pull0"
@@ -370,19 +386,19 @@
return BODY_ZONE_PRECISE_EYES
return BODY_ZONE_HEAD
-/atom/movable/screen/zone_sel/proc/set_selected_zone(choice, mob/user)
+/atom/movable/screen/zone_sel/proc/set_selected_zone(choice = BODY_ZONE_CHEST, mob/user)
if(isobserver(user))
return
if(choice != selecting)
selecting = choice
- update_icon(user)
+ user.zone_selected = selecting
+ update_icon()
return TRUE
-/atom/movable/screen/zone_sel/update_icon(mob/user)
- cut_overlays()
- add_overlay(mutable_appearance('icons/mob/screen/zone_sel.dmi', "[z_prefix][selecting]"))
- user.zone_selected = selecting
+/atom/movable/screen/zone_sel/update_overlays()
+ . = ..()
+ . += mutable_appearance('icons/mob/screen/zone_sel.dmi', "[z_prefix][selecting]")
/atom/movable/screen/zone_sel/alien
icon = 'icons/mob/screen/alien.dmi'
@@ -401,10 +417,25 @@
/atom/movable/screen/stamina_hud
icon = 'icons/mob/screen/health.dmi'
name = "stamina"
- icon_state = "staminaloss0"
+ icon_state = "stamloss-14"
screen_loc = UI_STAMINA
mouse_opacity = MOUSE_OPACITY_ICON
+/atom/movable/screen/stamina_hud/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/mymob_human = hud.mymob
+ if(mymob_human.stat == DEAD)
+ icon_state = "stamloss200"
+ return
+ var/relative_stamloss = mymob_human.getStaminaLoss()
+ if(relative_stamloss < 0 && mymob_human.max_stamina)
+ relative_stamloss = round(((relative_stamloss * 14) / mymob_human.max_stamina), 1)
+ else
+ relative_stamloss = round(((relative_stamloss * 7) / (mymob_human.maxHealth * 2)), 1)
+ icon_state = "stamloss[relative_stamloss]"
+
/atom/movable/screen/stamina_hud/Click(location, control, params)
if(!isliving(usr))
return
@@ -418,7 +449,7 @@
/atom/movable/screen/component_button
var/atom/movable/screen/parent
-/atom/movable/screen/component_button/Initialize(mapload, atom/movable/screen/parent)
+/atom/movable/screen/component_button/Initialize(mapload, datum/hud/hud_owner, atom/movable/screen/parent)
. = ..()
src.parent = parent
@@ -498,18 +529,139 @@
icon_state = "temp0"
screen_loc = ui_temp
+/atom/movable/screen/bodytemp/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ if(!human_mymob.species)
+ switch(human_mymob.bodytemperature) //310.055 optimal body temp
+ if(370 to INFINITY)
+ icon_state = "temp4"
+ if(350 to 370)
+ icon_state = "temp3"
+ if(335 to 350)
+ icon_state = "temp2"
+ if(320 to 335)
+ icon_state = "temp1"
+ if(300 to 320)
+ icon_state = "temp0"
+ if(295 to 300)
+ icon_state = "temp-1"
+ if(280 to 295)
+ icon_state = "temp-2"
+ if(260 to 280)
+ icon_state = "temp-3"
+ else
+ icon_state = "temp-4"
+ return
+
+ var/temp_step
+ if(human_mymob.bodytemperature >= human_mymob.species.body_temperature)
+ temp_step = (human_mymob.species.heat_level_1 - human_mymob.species.body_temperature) / 4
+
+ if(human_mymob.bodytemperature >= human_mymob.species.heat_level_1)
+ icon_state = "temp4"
+ else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 3)
+ icon_state = "temp3"
+ else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 2)
+ icon_state = "temp2"
+ else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 1)
+ icon_state = "temp1"
+ else
+ icon_state = "temp0"
+ return
+
+ if(human_mymob.bodytemperature < human_mymob.species.body_temperature)
+ temp_step = (human_mymob.species.body_temperature - human_mymob.species.cold_level_1)/4
+
+ if(human_mymob.bodytemperature <= human_mymob.species.cold_level_1)
+ icon_state = "temp-4"
+ else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 3)
+ icon_state = "temp-3"
+ else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 2)
+ icon_state = "temp-2"
+ else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 1)
+ icon_state = "temp-1"
+ else
+ icon_state = "temp0"
/atom/movable/screen/oxygen
name = "oxygen"
icon_state = "oxy0"
screen_loc = ui_oxygen
+/atom/movable/screen/oxygen/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ if(human_mymob.hal_screwyhud == 3 || human_mymob.oxygen_alert)
+ icon_state = "oxy1"
+ else
+ icon_state = "oxy0"
+
+/atom/movable/screen/toxin
+ name = "toxin"
+ icon_state = "tox0"
+ screen_loc = ui_toxin
+
+/atom/movable/screen/toxin/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ if(human_mymob.hal_screwyhud == 4)
+ icon_state = "tox1"
+ else
+ icon_state = "tox0"
+
+/atom/movable/screen/pressure
+ name = "pressure"
+ icon_state = "pressure0"
+ screen_loc = ui_pressure
+
+/atom/movable/screen/pressure/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ icon_state = "pressure[human_mymob.pressure_alert]"
+
+/atom/movable/screen/nutrition
+ name = "nutrition"
+ icon_state = "nutrition1"
+ screen_loc = ui_nutrition
+
+/atom/movable/screen/nutrition/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ switch(human_mymob.nutrition)
+ if(NUTRITION_OVERFED to INFINITY)
+ icon_state = "nutrition0"
+ if(NUTRITION_HUNGRY to NUTRITION_OVERFED) //Not-hungry.
+ icon_state = "nutrition1" //Empty icon.
+ if(NUTRITION_STARVING to NUTRITION_HUNGRY)
+ icon_state = "nutrition3"
+ else
+ icon_state = "nutrition4"
/atom/movable/screen/fire
- name = "fire"
+ name = "body temperature"
icon_state = "fire0"
screen_loc = ui_fire
+/atom/movable/screen/fire/update_icon_state()
+ . = ..()
+ if(!ishuman(hud?.mymob))
+ return
+ var/mob/living/carbon/human/human_mymob = hud.mymob
+ if(human_mymob.fire_alert)
+ icon_state = "fire[human_mymob.fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat.
+ else
+ icon_state = "fire0"
/atom/movable/screen/toggle_inv
name = "toggle"
@@ -547,7 +699,7 @@
///List of possible screen locs
var/static/list/ammo_screen_loc_list = list(ui_ammo1, ui_ammo2, ui_ammo3, ui_ammo4)
-/atom/movable/screen/ammo/Initialize(mapload)
+/atom/movable/screen/ammo/Initialize(mapload, datum/hud/hud_owner)
. = ..()
flash_holder = new
flash_holder.icon_state = "frame"
@@ -565,7 +717,7 @@
/atom/movable/screen/ammo/proc/add_hud(mob/living/user, datum/ammo_owner)
if(isnull(ammo_owner))
CRASH("/atom/movable/screen/ammo/proc/add_hud() has been called from [src] without the required param of ammo_owner")
- user?.client.screen += src
+ user?.client?.screen += src
///wrapper to removing this ammo hud from the users screen
/atom/movable/screen/ammo/proc/remove_hud(mob/living/user)
@@ -643,7 +795,7 @@
deltimer(del_timer)
qdel(src)
-/atom/movable/screen/arrow/Initialize(mapload) //Self-deletes
+/atom/movable/screen/arrow/Initialize(mapload, datum/hud/hud_owner) //Self-deletes
. = ..()
START_PROCESSING(SSprocessing, src)
del_timer = addtimer(CALLBACK(src, PROC_REF(kill_arrow)), duration, TIMER_STOPPABLE)
diff --git a/code/_onclick/hud/screen_objects/text_objects.dm b/code/_onclick/hud/screen_objects/text_objects.dm
index f717461f715db..3ef7cb80696d2 100644
--- a/code/_onclick/hud/screen_objects/text_objects.dm
+++ b/code/_onclick/hud/screen_objects/text_objects.dm
@@ -25,6 +25,7 @@
/atom/movable/screen/text/screen_timer/Initialize(
mapload,
+ datum/hud/hud_owner,
list/mobs,
timer,
text,
diff --git a/code/_onclick/hud/xeno/hivemind.dm b/code/_onclick/hud/xeno/hivemind.dm
index 1bc7fa6bc1225..5d8b0b0ccf2f0 100644
--- a/code/_onclick/hud/xeno/hivemind.dm
+++ b/code/_onclick/hud/xeno/hivemind.dm
@@ -2,18 +2,18 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/alien/nightvision()
+ using = new /atom/movable/screen/alien/nightvision(null, src)
using.alpha = ui_alpha
infodisplay += using
- alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay()
+ alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay(null, src)
alien_plasma_display.alpha = ui_alpha
infodisplay += alien_plasma_display
- healths = new /atom/movable/screen/healths/alien()
+ healths = new /atom/movable/screen/healths/alien(null, src)
healths.alpha = ui_alpha
infodisplay += healths
- locate_leader = new /atom/movable/screen/alien/queen_locator()
+ locate_leader = new /atom/movable/screen/alien/queen_locator(null, src)
locate_leader.alpha = ui_alpha
infodisplay += locate_leader
diff --git a/code/_onclick/hud/xeno/larva.dm b/code/_onclick/hud/xeno/larva.dm
index f62626f522602..4db8f9b5445c8 100644
--- a/code/_onclick/hud/xeno/larva.dm
+++ b/code/_onclick/hud/xeno/larva.dm
@@ -3,21 +3,21 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/mov_intent/alien()
+ using = new /atom/movable/screen/mov_intent/alien(null, src)
using.alpha = ui_alpha
using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
static_inventory += using
move_intent = using
- using = new /atom/movable/screen/alien/nightvision()
+ using = new /atom/movable/screen/alien/nightvision(null, src)
using.alpha = ui_alpha
infodisplay += using
- healths = new /atom/movable/screen/healths/alien()
+ healths = new /atom/movable/screen/healths/alien(null, src)
healths.alpha = ui_alpha
infodisplay += healths
- locate_leader = new /atom/movable/screen/alien/queen_locator()
+ locate_leader = new /atom/movable/screen/alien/queen_locator(null, src)
locate_leader.alpha = ui_alpha
infodisplay += locate_leader
*/
diff --git a/code/_onclick/hud/xeno/xeno.dm b/code/_onclick/hud/xeno/xeno.dm
index efe2f6183c38f..4380d1f191772 100644
--- a/code/_onclick/hud/xeno/xeno.dm
+++ b/code/_onclick/hud/xeno/xeno.dm
@@ -50,88 +50,86 @@
var/atom/movable/screen/using
var/atom/movable/screen/inventory/inv_box
- using = new /atom/movable/screen/act_intent/corner()
+ using = new /atom/movable/screen/act_intent/corner(null, src)
using.alpha = ui_alpha
using.icon_state = owner.a_intent
static_inventory += using
action_intent = using
- using = new /atom/movable/screen/mov_intent/alien()
+ using = new /atom/movable/screen/mov_intent/alien(null, src)
using.alpha = ui_alpha
using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
static_inventory += using
move_intent = using
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = 'icons/mob/screen/alien.dmi'
using.alpha = ui_alpha
static_inventory += using
- inv_box = new /atom/movable/screen/inventory/hand/right()
+ inv_box = new /atom/movable/screen/inventory/hand/right(null, src)
inv_box.icon = 'icons/mob/screen/alien.dmi'
using.alpha = ui_alpha
- if(owner && !owner.hand) //This being 0 or null means the right hand is in use
- using.add_overlay("hand_active")
inv_box.slot_id = SLOT_R_HAND
+ inv_box.update_icon()
r_hand_hud_object = inv_box
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory/hand()
+ inv_box = new /atom/movable/screen/inventory/hand/left(null, src)
inv_box.icon = 'icons/mob/screen/alien.dmi'
using.alpha = ui_alpha
- if(owner?.hand) //This being 1 means the left hand is in use
- inv_box.add_overlay("hand_active")
inv_box.slot_id = SLOT_L_HAND
+ inv_box.update_icon()
l_hand_hud_object = inv_box
static_inventory += inv_box
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = 'icons/mob/screen/alien.dmi'
using.alpha = ui_alpha
static_inventory += using
- using = new /atom/movable/screen/swap_hand/right()
+ using = new /atom/movable/screen/swap_hand/right(null, src)
using.icon = 'icons/mob/screen/alien.dmi'
using.alpha = ui_alpha
static_inventory += using
- using = new /atom/movable/screen/resist()
+ using = new /atom/movable/screen/resist(null, src)
using.icon = 'icons/mob/screen/alien.dmi'
using.screen_loc = ui_above_movement
using.alpha = ui_alpha
hotkeybuttons += using
- throw_icon = new /atom/movable/screen/throw_catch()
+ throw_icon = new /atom/movable/screen/throw_catch(null, src)
throw_icon.icon = 'icons/mob/screen/alien.dmi'
throw_icon.alpha = ui_alpha
hotkeybuttons += throw_icon
- healths = new /atom/movable/screen/healths/alien()
+ healths = new /atom/movable/screen/healths/alien(null, src)
healths.alpha = ui_alpha
infodisplay += healths
- using = new /atom/movable/screen/alien/nightvision()
+ using = new /atom/movable/screen/alien/nightvision(null, src)
using.alpha = ui_alpha
infodisplay += using
- alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay()
+ alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay(null, src)
alien_plasma_display.alpha = ui_alpha
infodisplay += alien_plasma_display
- locate_leader = new /atom/movable/screen/alien/queen_locator()
+ locate_leader = new /atom/movable/screen/alien/queen_locator(null, src)
locate_leader.alpha = ui_alpha
infodisplay += locate_leader
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = 'icons/mob/screen/alien.dmi'
pull_icon.screen_loc = ui_above_movement
pull_icon.alpha = ui_alpha
- pull_icon.update_icon(owner)
+ pull_icon.update_icon()
hotkeybuttons += pull_icon
- zone_sel = new /atom/movable/screen/zone_sel/alien()
- zone_sel.update_icon(owner)
+ zone_sel = new /atom/movable/screen/zone_sel/alien(null, src)
+ zone_sel.update_icon()
static_inventory += zone_sel
/datum/hud/alien/persistent_inventory_update()
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 873b0dcda3f32..3279e91364bf2 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -46,14 +46,22 @@
return
interact(user)
+///Called when the item is in the active hand, and RIGHT clicked;
+/obj/item/proc/attack_self_alternate(mob/user)
+ SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF_ALTERNATE, user)
+ add_fingerprint(user, "attack_self_alternate")
+
/atom/proc/attackby(obj/item/I, mob/user, params)
SIGNAL_HANDLER_DOES_SLEEP
add_fingerprint(user, "attackby", I)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACKBY, I, user, params) & COMPONENT_NO_AFTERATTACK)
return TRUE
+ if(isgrabitem(I) && grab_interact(I, user))
+ user.changeNext_move(GRAB_SLAM_DELAY)
+ return TRUE
return FALSE
-
/obj/attackby(obj/item/I, mob/user, params)
. = ..()
if(.)
@@ -68,7 +76,7 @@
/obj/item/proc/attack_obj(obj/O, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
return
- if(flags_item & NOBLUDGEON)
+ if(item_flags & NOBLUDGEON)
return
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(O, used_item = src)
@@ -84,7 +92,7 @@
span_warning("You hit [src] with [I]!"), visible_message_flags = COMBAT_MESSAGE)
log_combat(user, src, "attacked", I)
var/power = I.force + round(I.force * MELEE_SKILL_DAM_BUFF * user.skills.getRating(SKILL_MELEE_WEAPONS))
- take_damage(power, I.damtype, MELEE)
+ take_damage(power, I.damtype, MELEE, blame_mob = user)
return TRUE
@@ -185,7 +193,7 @@
if(M.can_be_operated_on() && do_surgery(M, user, src)) //Checks if mob is lying down on table for surgery
return TRUE
- if(flags_item & NOBLUDGEON)
+ if(item_flags & NOBLUDGEON)
return FALSE
if(!force)
@@ -322,7 +330,7 @@
if(SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_ALTERNATE, M, src) & COMPONENT_ITEM_NO_ATTACK)
return FALSE
- if(flags_item & NOBLUDGEON)
+ if(item_flags & NOBLUDGEON)
return FALSE
if(!force)
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index 84cb76ea4514d..563d8cedd19f0 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -84,7 +84,7 @@ Redefine as needed.
desc = "Magic"
icon = 'icons/obj/magic.dmi'
icon_state = "2"
- flags_item = NOBLUDGEON | ITEM_ABSTRACT | DELONDROP
+ item_flags = NOBLUDGEON | ITEM_ABSTRACT | DELONDROP
w_class = WEIGHT_CLASS_GIGANTIC
layer = ABOVE_HUD_LAYER
plane = ABOVE_HUD_PLANE
@@ -206,16 +206,15 @@ Redefine as needed.
return
new /obj/effect/temp_visual/telekinesis(get_turf(focus))
-
-/obj/item/tk_grab/update_icon()
- cut_overlays()
+/obj/item/tk_grab/update_overlays()
+ . = ..()
if(!focus)
return
var/old_layer = focus.layer
var/old_plane = focus.plane
focus.layer = layer+0.01
focus.plane = ABOVE_HUD_PLANE
- add_overlay(focus) //this is kind of ick, but it's better than using icon()
+ . += focus
focus.layer = old_layer
focus.plane = old_plane
diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm
index f5b3d560a7d0f..51f156d593b6a 100644
--- a/code/_onclick/xeno.dm
+++ b/code/_onclick/xeno.dm
@@ -15,7 +15,7 @@
SSblackbox.record_feedback("tally", "round_statistics", 1, "xeno_unarmed_attacks")
-/atom/proc/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/atom/proc/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
return
diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm
index 5838c3d6287d0..4e6d484380dc4 100644
--- a/code/controllers/configuration/config_entry.dm
+++ b/code/controllers/configuration/config_entry.dm
@@ -118,6 +118,22 @@
config_entry_value = text2num(trim(str_val)) != 0
return TRUE
+/// List config entry, used for configuring a list of strings
+/datum/config_entry/str_list
+ abstract_type = /datum/config_entry/str_list
+ default = list()
+ dupes_allowed = TRUE
+ /// whether the string elements will be lowercased on ValidateAndSet or not.
+ var/lowercase = FALSE
+
+/datum/config_entry/str_list/ValidateAndSet(str_val)
+ if (!VASProcCallGuard(str_val))
+ return FALSE
+ str_val = trim(str_val)
+ if (str_val != "")
+ config_entry_value += lowercase ? lowertext(str_val) : str_val
+ return TRUE
+
/datum/config_entry/number_list
abstract_type = /datum/config_entry/number_list
config_entry_value = list()
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index 5758429a6491a..b8851195288ee 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -18,9 +18,6 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
controller_vars["vars"] = null
gvars_datum_in_built_vars = controller_vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order))
-#if DM_VERSION >= 515 && DM_BUILD > 1620
- #warn datum.vars hanging a ref should now be fixed, there should be no reason to remove the vars list from our controller's vars list anymore
-#endif
QDEL_IN(exclude_these, 1) //signal logging isn't ready
log_world("[length(vars) - length(gvars_datum_in_built_vars)] global variables")
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 46fcbe5a56c6c..16bfb65ba3741 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -254,7 +254,7 @@ GLOBAL_REAL(Master, /datum/controller/master)
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
- to_chat(world, span_boldannounce("[msg]"))
+ to_chat(world, span_boldwarning("[msg]"))
log_world(msg)
@@ -341,7 +341,7 @@ GLOBAL_REAL(Master, /datum/controller/master)
chat_warning = TRUE
var/message = "[message_prefix] [seconds] second[seconds == 1 ? "" : "s"]!"
- var/chat_message = chat_warning ? span_boldwarning(message) : span_boldannounce(message)
+ var/chat_message = chat_warning ? span_boldwarning(message) : span_alert("[message]")
to_chat(world, chat_message)
log_world(message)
diff --git a/code/controllers/subsystem/advanced_pathfinding.dm b/code/controllers/subsystem/advanced_pathfinding.dm
index b6918c219bca5..bfd0dc50319e0 100644
--- a/code/controllers/subsystem/advanced_pathfinding.dm
+++ b/code/controllers/subsystem/advanced_pathfinding.dm
@@ -1,5 +1,5 @@
SUBSYSTEM_DEF(advanced_pathfinding)
- name = "Advanced_pathfinding"
+ name = "Advanced Pathfinding"
priority = FIRE_PRIORITY_ADVANCED_PATHFINDING
wait = 1 SECONDS
///List of ai_behaviour datum asking for a tile pathfinding
@@ -113,7 +113,7 @@ GLOBAL_LIST_EMPTY(goal_nodes)
atom_to_check = current_node.adjacent_nodes[direction]
if(TILE_PATHING)
var/turf/turf_to_check = get_step(current_atom, direction)
- if(turf_to_check.density || turf_to_check.flags_atom & AI_BLOCKED)
+ if(turf_to_check.density || turf_to_check.atom_flags & AI_BLOCKED)
continue
atom_to_check = turf_to_check
if(paths_to_check[atom_to_check] || paths_checked[atom_to_check] || !atom_to_check) //We already found a better path to get to this atom
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index efdaab4d38e2c..1c55f98e015bd 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -89,7 +89,7 @@ SUBSYSTEM_DEF(atoms)
count = length(atoms)
for(var/I in 1 to count)
var/atom/A = atoms[I]
- if(!(A.flags_atom & INITIALIZED))
+ if(!(A.atom_flags & INITIALIZED))
CHECK_TICK
PROFILE_INIT_ATOM_BEGIN()
InitAtom(A, TRUE, mapload_arg)
@@ -97,7 +97,7 @@ SUBSYSTEM_DEF(atoms)
else
count = 0
for(var/atom/A in world)
- if(!(A.flags_atom & INITIALIZED))
+ if(!(A.atom_flags & INITIALIZED))
PROFILE_INIT_ATOM_BEGIN()
InitAtom(A, FALSE, mapload_arg)
PROFILE_INIT_ATOM_END(A)
@@ -141,7 +141,7 @@ SUBSYSTEM_DEF(atoms)
if(!A) //possible harddel
qdeleted = TRUE
- else if(!(A.flags_atom & INITIALIZED))
+ else if(!(A.atom_flags & INITIALIZED))
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
else
SEND_SIGNAL(A,COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE)
diff --git a/code/controllers/subsystem/autofire.dm b/code/controllers/subsystem/autofire.dm
index 09aae3a27a9ec..a5f4ac3006776 100644
--- a/code/controllers/subsystem/autofire.dm
+++ b/code/controllers/subsystem/autofire.dm
@@ -16,7 +16,7 @@
* Doesn't support any event scheduled for more than 100 ticks in the future, as it has no secondary queue by design
*/
SUBSYSTEM_DEF(automatedfire)
- name = "Automated fire"
+ name = "Autofire"
flags = SS_TICKER | SS_NO_INIT
wait = 1
priority = FIRE_PRIORITY_AUTOFIRE
@@ -180,7 +180,7 @@ SUBSYSTEM_DEF(automatedfire)
SIGNAL_HANDLER
var/obj/projectile/newshot = new(loc)
newshot.generate_bullet(ammo)
- newshot.fire_at(target, src, null, ammo.max_range, ammo.shell_speed)
+ newshot.fire_at(target, null, src, ammo.max_range, ammo.shell_speed)
/datum/component/automatedfire/xeno_turret_autofire
///Delay between two shots
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
index ddcdf8674136c..48fe275b34e80 100644
--- a/code/controllers/subsystem/chat.dm
+++ b/code/controllers/subsystem/chat.dm
@@ -5,39 +5,93 @@
SUBSYSTEM_DEF(chat)
name = "Chat"
- flags = SS_TICKER
+ flags = SS_TICKER|SS_NO_INIT
wait = 1
priority = FIRE_PRIORITY_CHAT
init_order = INIT_ORDER_CHAT
- var/list/payload_by_client = list()
+ /// Assosciates a ckey with a list of messages to send to them.
+ var/list/list/datum/chat_payload/client_to_payloads = list()
-/datum/controller/subsystem/chat/Initialize()
- // Just used by chat system to know that initialization is nearly finished.
- // The to_chat checks could probably check the runlevel instead, but would require testing.
- return SS_INIT_SUCCESS
+ /// Associates a ckey with an assosciative list of their last CHAT_RELIABILITY_HISTORY_SIZE messages.
+ var/list/list/datum/chat_payload/client_to_reliability_history = list()
+
+ /// Assosciates a ckey with their next sequence number.
+ var/list/client_to_sequence_number = list()
+
+/datum/controller/subsystem/chat/proc/generate_payload(client/target, message_data)
+ var/sequence = client_to_sequence_number[target.ckey]++
+
+ var/datum/chat_payload/payload = new
+ payload.sequence = sequence
+ payload.content = message_data
+
+ var/list/client_history = client_to_reliability_history[target.ckey]
+ if(!islist(client_history))
+ client_history = (client_to_reliability_history[target.ckey] = list())
+ client_history["[sequence]"] = payload
+
+ if(length(client_history) > CHAT_RELIABILITY_HISTORY_SIZE)
+ var/oldest = text2num(client_history[1])
+ for(var/index in 2 to length(client_history))
+ var/test = text2num(client_history[index])
+ if(test < oldest)
+ oldest = test
+ client_history -= "[oldest]"
+ return payload
+
+/datum/controller/subsystem/chat/proc/send_payload_to_client(client/target, datum/chat_payload/payload)
+ target.tgui_panel.window.send_message("chat/message", payload.into_message())
+ SEND_TEXT(target, payload.get_content_as_html())
/datum/controller/subsystem/chat/fire()
- for(var/key in payload_by_client)
- var/client/client = key
- var/payload = payload_by_client[key]
- payload_by_client -= key
- if(client)
- // Send to tgchat
- client.tgui_panel?.window.send_message("chat/message", payload)
- // Send to old chat
- for(var/message in payload)
- SEND_TEXT(client, message_to_html(message))
+ for(var/ckey in client_to_payloads)
+ var/client/target = GLOB.directory[ckey]
+ if(isnull(target)) // verify client still exists
+ LAZYREMOVE(client_to_payloads, ckey)
+ continue
+
+ for(var/datum/chat_payload/payload as anything in client_to_payloads[ckey])
+ send_payload_to_client(target, payload)
+ LAZYREMOVE(client_to_payloads, ckey)
+
if(MC_TICK_CHECK)
return
-/datum/controller/subsystem/chat/proc/queue(target, message)
- if(islist(target))
- for(var/_target in target)
- var/client/client = CLIENT_FROM_VAR(_target)
- if(client)
- LAZYADD(payload_by_client[client], list(message))
+/datum/controller/subsystem/chat/proc/queue(queue_target, list/message_data)
+ var/list/targets = islist(queue_target) ? queue_target : list(queue_target)
+ for(var/target in targets)
+ var/client/client = CLIENT_FROM_VAR(target)
+ if(isnull(client))
+ continue
+ LAZYADDASSOCLIST(client_to_payloads, client.ckey, generate_payload(client, message_data))
+
+/datum/controller/subsystem/chat/proc/send_immediate(send_target, list/message_data)
+ var/list/targets = islist(send_target) ? send_target : list(send_target)
+ for(var/target in targets)
+ var/client/client = CLIENT_FROM_VAR(target)
+ if(isnull(client))
+ continue
+ send_payload_to_client(client, generate_payload(client, message_data))
+
+/datum/controller/subsystem/chat/proc/handle_resend(client/client, sequence)
+ var/list/client_history = client_to_reliability_history[client.ckey]
+ sequence = "[sequence]"
+ if(isnull(client_history) || !(sequence in client_history))
return
- var/client/client = CLIENT_FROM_VAR(target)
- if(client)
- LAZYADD(payload_by_client[client], list(message))
+
+ var/datum/chat_payload/payload = client_history[sequence]
+ if(payload.resends > CHAT_RELIABILITY_MAX_RESENDS)
+ return // we tried but byond said no
+
+ payload.resends += 1
+ send_payload_to_client(client, client_history[sequence])
+ SSblackbox.record_feedback(
+ "nested tally",
+ "chat_resend_byond_version",
+ 1,
+ list(
+ "[client.byond_version]",
+ "[client.byond_build]",
+ ),
+ )
diff --git a/code/controllers/subsystem/evacuation.dm b/code/controllers/subsystem/evacuation.dm
index 3e9c7d3c79477..837975f6d0ee9 100644
--- a/code/controllers/subsystem/evacuation.dm
+++ b/code/controllers/subsystem/evacuation.dm
@@ -15,7 +15,7 @@ SUBSYSTEM_DEF(evacuation)
var/dest_index = 1
var/dest_status = NUKE_EXPLOSION_INACTIVE
- var/flags_scuttle = FLAGS_SDEVAC_TIMELOCK
+ var/scuttle_flags = FLAGS_SDEVAC_TIMELOCK
///How many marines were on ship when the dropship crashed
var/initial_human_on_ship = 0
///How many marines escaped
@@ -80,13 +80,13 @@ SUBSYSTEM_DEF(evacuation)
/datum/controller/subsystem/evacuation/proc/initiate_evacuation(override)
if(evac_status != EVACUATION_STATUS_STANDING_BY)
return FALSE
- if(!override && flags_scuttle & (FLAGS_EVACUATION_DENY|FLAGS_SDEVAC_TIMELOCK))
+ if(!override && scuttle_flags & (FLAGS_EVACUATION_DENY|FLAGS_SDEVAC_TIMELOCK))
return FALSE
GLOB.enter_allowed = FALSE
evac_time = world.time
evac_status = EVACUATION_STATUS_INITIATING
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EVACUATION_STARTED)
- priority_announce("Emergency evacuation has been triggered. Please proceed to the escape pods. Evacuation in [EVACUATION_AUTOMATIC_DEPARTURE/600] minutes.", "Priority Alert", sound = 'sound/AI/evacuate.ogg')
+ priority_announce("Emergency evacuation has been triggered. Please proceed to the escape pods. Evacuation in [EVACUATION_AUTOMATIC_DEPARTURE/600] minutes.", title = "Emergency Evacuation", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/evacuate.ogg', color_override = "orange")
xeno_message("A wave of adrenaline ripples through the hive. The fleshy creatures are trying to escape!")
pod_list = SSshuttle.escape_pods.Copy()
for(var/obj/docking_port/mobile/escape_pod/pod AS in pod_list)
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(evacuation)
if(evac_status != EVACUATION_STATUS_INITIATING)
return FALSE
evac_status = EVACUATION_STATUS_IN_PROGRESS
- priority_announce("WARNING: Evacuation order confirmed. Launching escape pods.", "Priority Alert", sound = 'sound/AI/evacuation_confirmed.ogg')
+ priority_announce("WARNING: Evacuation order confirmed. Launching escape pods.", title = "Emergency Evacuation", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/evacuation_confirmed.ogg', color_override = "orange")
return TRUE
@@ -108,7 +108,7 @@ SUBSYSTEM_DEF(evacuation)
GLOB.enter_allowed = TRUE
evac_time = null
evac_status = EVACUATION_STATUS_STANDING_BY
- priority_announce("Evacuation has been cancelled.", "Priority Alert", sound = 'sound/AI/evacuate_cancelled.ogg')
+ priority_announce("Evacuation has been cancelled.", title = "Emergency Evacuation", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/evacuate_cancelled.ogg', color_override = "orange")
for(var/obj/docking_port/mobile/escape_pod/pod AS in pod_list)
pod.unprep_for_launch()
return TRUE
@@ -123,14 +123,14 @@ SUBSYSTEM_DEF(evacuation)
. = "NOW"
/datum/controller/subsystem/evacuation/proc/announce_evac_completion()
- priority_announce("ATTENTION: Evacuation complete.", "Priority Alert", sound = 'sound/AI/evacuation_complete.ogg')
+ priority_announce("ATTENTION: Evacuation complete.", title = "Emergency Evacuation", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/evacuation_complete.ogg', color_override = "orange")
evac_status = EVACUATION_STATUS_COMPLETE
/datum/controller/subsystem/evacuation/proc/enable_self_destruct(override)
if(dest_status != NUKE_EXPLOSION_INACTIVE)
return FALSE
- if(!override && flags_scuttle & (FLAGS_SELF_DESTRUCT_DENY|FLAGS_SDEVAC_TIMELOCK))
+ if(!override && scuttle_flags & (FLAGS_SELF_DESTRUCT_DENY|FLAGS_SDEVAC_TIMELOCK))
return FALSE
dest_status = NUKE_EXPLOSION_ACTIVE
dest_master.toggle()
@@ -158,7 +158,7 @@ SUBSYSTEM_DEF(evacuation)
I.toggle(TRUE)
dest_master.toggle(TRUE)
dest_index = 1
- priority_announce("The emergency destruct system has been deactivated.", "Priority Alert", sound = 'sound/AI/selfdestruct_deactivated.ogg')
+ priority_announce("The emergency destruct system has been deactivated.", title = "Self Destruct System", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/selfdestruct_deactivated.ogg', color_override = "purple")
if(evac_status == EVACUATION_STATUS_STANDING_BY)
GLOB.marine_main_ship.set_security_level(SEC_LEVEL_RED, TRUE)
for(var/obj/machinery/floor_warn_light/self_destruct/light AS in alarm_lights)
@@ -177,7 +177,7 @@ SUBSYSTEM_DEF(evacuation)
dest_master.visible_message(span_warning("WARNING: Unable to trigger detonation. Please arm all control rods."))
return FALSE
- priority_announce("DANGER. DANGER. Self destruct system activated. DANGER. DANGER. Self destruct in progress. DANGER. DANGER.", "Priority Alert")
+ priority_announce("DANGER. DANGER. Self destruct system activated. DANGER. DANGER. Self destruct in progress. DANGER. DANGER.", title = "Self Destruct System", type = ANNOUNCEMENT_PRIORITY, color_override = "purple")
GLOB.enter_allowed = FALSE
dest_status = NUKE_EXPLOSION_IN_PROGRESS
playsound(dest_master, 'sound/machines/alarm.ogg', 75, 0, 30)
diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm
index 893663b1575d0..4227f43f4d134 100644
--- a/code/controllers/subsystem/explosions.dm
+++ b/code/controllers/subsystem/explosions.dm
@@ -196,14 +196,19 @@ SUBSYSTEM_DEF(explosions)
)
)
+ var/throw_strength //used here for epicenter and also later for every other turf
if(devastation_range > 0)
highTurf[epicenter] += list(epicenter)
+ throw_strength = MOVE_FORCE_EXCEPTIONALLY_STRONG
else if(heavy_impact_range > 0)
medTurf[epicenter] += list(epicenter)
+ throw_strength = MOVE_FORCE_EXTREMELY_STRONG
else if(light_impact_range > 0)
lowTurf[epicenter] += list(epicenter)
+ throw_strength = MOVE_FORCE_VERY_STRONG
else if(weak_impact_range > 0)
weakTurf[epicenter] += list(epicenter)
+ throw_strength = MOVE_FORCE_WEAK
else
if(flame_range > 0) //this proc shouldn't be used for flames only, but here we are
if(usr)
@@ -215,7 +220,7 @@ SUBSYSTEM_DEF(explosions)
for(var/t in turfs_in_range)
var/turf/throw_turf = t
throwTurf[throw_turf] += list(epicenter)
- throwTurf[throw_turf][epicenter] = list(throw_range, get_dir(epicenter, throw_turf))
+ throwTurf[throw_turf][epicenter] = list(throw_range, get_dir(epicenter, throw_turf), MOVE_FORCE_EXTREMELY_STRONG)
return //Our job here is done.
if(flame_range)
@@ -232,17 +237,16 @@ SUBSYSTEM_DEF(explosions)
turfs_in_range[epicenter] = current_exp_block
throwTurf[epicenter] += list(epicenter)
- throwTurf[epicenter][epicenter] = list(max_range, 0) //Random direction.
+ throwTurf[epicenter][epicenter] = list(max_range, null, throw_strength) //Random direction, strength scales with severity
/*
We'll store how much each turf blocks the explosion's movement in turfs_in_range[turf] and how much movement is needed to reach it in turfs_by_dist[turf].
This way we'll be able to draw the explosion's expansion path without having to waste time processing the edge turfs, scanning their contents.
*/
- for(var/t in (turfs_in_range - epicenter))
- if(turfs_by_dist[t]) //Already processed.
+ for(var/turf/affected_turf AS in (turfs_in_range - epicenter))
+ if(turfs_by_dist[affected_turf]) //Already processed.
continue
- var/turf/affected_turf = t
var/dist = turfs_in_range[epicenter]
var/turf/expansion_wave_loc = epicenter
@@ -304,17 +308,21 @@ This way we'll be able to draw the explosion's expansion path without having to
var/dist = turfs_by_dist[t]
if(devastation_range > dist)
highTurf[t] += list(epicenter)
+ throw_strength = MOVE_FORCE_EXCEPTIONALLY_STRONG
else if(heavy_impact_range > dist)
medTurf[t] += list(epicenter)
+ throw_strength = MOVE_FORCE_EXTREMELY_STRONG
else if(light_impact_range > dist)
lowTurf[t] += list(epicenter)
+ throw_strength = MOVE_FORCE_VERY_STRONG
else if(weak_impact_range > dist)
weakTurf[t] += list(epicenter)
+ throw_strength = MOVE_FORCE_WEAK
if(flame_range > dist)
flameturf += t
if(throw_range > dist)
throwTurf[t] += list(epicenter)
- throwTurf[t][epicenter] = list(max_range - dist, get_dir(epicenter, t))
+ throwTurf[t][epicenter] = list(max_range - dist, get_dir(epicenter, t), throw_strength)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPLOSION, epicenter, devastation_range, heavy_impact_range, light_impact_range, weak_impact_range, (REALTIMEOFDAY - started_at) * 0.1)
@@ -338,8 +346,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/weak_turf = weakTurf
weakTurf = list()
- for(var/t in weak_turf)
- var/turf/turf_to_explode = t
+ for(var/turf/turf_to_explode AS in weak_turf)
if(QDELETED(turf_to_explode))
continue
for(var/explosion_source in weak_turf[turf_to_explode])
@@ -351,8 +358,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/low_turf = lowTurf
lowTurf = list()
- for(var/t in low_turf)
- var/turf/turf_to_explode = t
+ for(var/turf/turf_to_explode AS in low_turf)
if(QDELETED(turf_to_explode))
continue
for(var/explosion_source in low_turf[turf_to_explode])
@@ -364,8 +370,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/med_turf = medTurf
medTurf = list()
- for(var/t in med_turf)
- var/turf/turf_to_explode = t
+ for(var/turf/turf_to_explode AS in med_turf)
if(QDELETED(turf_to_explode))
continue
for(var/explosion_source in med_turf[turf_to_explode])
@@ -377,8 +382,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/high_turf = highTurf
highTurf = list()
- for(var/t in high_turf)
- var/turf/turf_to_explode = t
+ for(var/turf/turf_to_explode AS in high_turf)
if(QDELETED(turf_to_explode))
continue
for(var/explosion_source in high_turf[turf_to_explode])
@@ -405,8 +409,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/high_mov_atom = highMovAtom
highMovAtom = list()
- for(var/o in high_mov_atom)
- var/obj/object_to_explode = o
+ for(var/obj/object_to_explode AS in high_mov_atom)
if(QDELETED(object_to_explode))
continue
for(var/explosion_source in high_mov_atom[object_to_explode])
@@ -418,8 +421,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/med_mov_atom = medMovAtom
medMovAtom = list()
- for(var/o in med_mov_atom)
- var/obj/object_to_explode = o
+ for(var/obj/object_to_explode AS in med_mov_atom)
if(QDELETED(object_to_explode))
continue
for(var/explosion_source in med_mov_atom[object_to_explode])
@@ -431,8 +433,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/low_mov_atom = lowMovAtom
lowMovAtom = list()
- for(var/o in low_mov_atom)
- var/obj/object_to_explode = o
+ for(var/obj/object_to_explode AS in low_mov_atom)
if(QDELETED(object_to_explode))
continue
for(var/explosion_source in low_mov_atom[object_to_explode])
@@ -444,8 +445,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/weak_mov_atom = weakMovAtom
weakMovAtom = list()
- for(var/o in weak_mov_atom)
- var/obj/object_to_explode = o
+ for(var/obj/object_to_explode AS in weak_mov_atom)
if(QDELETED(object_to_explode))
continue
for(var/explosion_source in weak_mov_atom[object_to_explode])
@@ -460,8 +460,7 @@ This way we'll be able to draw the explosion's expansion path without having to
timer = TICK_USAGE_REAL
var/list/throw_turf = throwTurf
throwTurf = list()
- for(var/t in throw_turf)
- var/turf/affected_turf = t
+ for(var/turf/affected_turf AS in throw_turf)
if(QDELETED(affected_turf))
continue
for(var/am in affected_turf)
@@ -470,6 +469,8 @@ This way we'll be able to draw the explosion's expansion path without having to
continue
for(var/throw_source in throw_turf[affected_turf])
+ if(throw_turf[affected_turf][throw_source][3] < (thing_to_throw.move_resist * MOVE_FORCE_THROW_RATIO))
+ continue
thing_to_throw.throw_at(
get_ranged_target_turf(
thing_to_throw,
diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm
index d4ddfeff7e058..725c1b925528f 100644
--- a/code/controllers/subsystem/icon_smooth.dm
+++ b/code/controllers/subsystem/icon_smooth.dm
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(icon_smooth)
cached.len--
if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED))
continue
- if(smoothing_atom.flags_atom & INITIALIZED)
+ if(smoothing_atom.atom_flags & INITIALIZED)
smoothing_atom.smooth_icon()
else
deferred += smoothing_atom
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 11f17edc545d3..14dd4d614ba50 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -209,7 +209,7 @@ SUBSYSTEM_DEF(job)
if(PopcapReached())
RejectPlayer(player)
//Choose a faction in advance if needed
- if(SSticker.mode?.flags_round_type & MODE_TWO_HUMAN_FACTIONS) //Alternates between the two factions
+ if(SSticker.mode?.round_type_flags & MODE_TWO_HUMAN_FACTIONS) //Alternates between the two factions
faction_rejected = faction_rejected == FACTION_TERRAGOV ? FACTION_SOM : FACTION_TERRAGOV
// Loop through all jobs
for(var/datum/job/job AS in occupations_to_assign)
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index a44bef29fcac4..9e3030d152f8b 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -23,6 +23,31 @@ SUBSYSTEM_DEF(mapping)
var/list/reservation_ready = list()
var/clearing_reserved_turfs = FALSE
+ /// List of z level (as number) -> plane offset of that z level
+ /// Used to maintain the plane cube
+ var/list/z_level_to_plane_offset = list()
+ /// List of z level (as number) -> list of all z levels vertically connected to ours
+ /// Useful for fast grouping lookups and such
+ var/list/z_level_to_stack = list()
+ /// List of z level (as number) -> The lowest plane offset in that z stack
+ var/list/z_level_to_lowest_plane_offset = list()
+ // This pair allows for easy conversion between an offset plane, and its true representation
+ // Both are in the form "input plane" -> output plane(s)
+ /// Assoc list of string plane values to their true, non offset representation
+ var/list/plane_offset_to_true
+ /// Assoc list of true string plane values to a list of all potential offset planess
+ var/list/true_to_offset_planes
+ /// Assoc list of string plane to the plane's offset value
+ var/list/plane_to_offset
+ /// List of planes that do not allow for offsetting
+ var/list/plane_offset_blacklist
+ /// List of render targets that do not allow for offsetting
+ var/list/render_offset_blacklist
+ /// List of plane masters that are of critical priority
+ var/list/critical_planes
+ /// The largest plane offset we've generated so far
+ var/max_plane_offset = 0
+
// Z-manager stuff
var/ground_start // should only be used for maploading-related tasks
var/list/z_list
@@ -133,7 +158,7 @@ SUBSYSTEM_DEF(mapping)
z_list = SSmapping.z_list
-#define INIT_ANNOUNCE(X) to_chat(world, span_notice("[X]")); log_world(X)
+#define INIT_ANNOUNCE(X) to_chat(world, span_alert("[X]")); log_world(X)
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE)
. = list()
var/start_time = REALTIMEOFDAY
@@ -344,7 +369,7 @@ SUBSYSTEM_DEF(mapping)
// No need to empty() these, because it's world init and they're
// already /turf/open/space/basic.
var/turf/T = t
- T.flags_atom |= UNUSED_RESERVATION_TURF_1
+ T.atom_flags |= UNUSED_RESERVATION_TURF_1
unused_turfs["[z]"] = block
reservation_ready["[z]"] = TRUE
clearing_reserved_turfs = FALSE
@@ -355,7 +380,7 @@ SUBSYSTEM_DEF(mapping)
T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
LAZYINITLIST(unused_turfs["[T.z]"])
unused_turfs["[T.z]"] |= T
- T.flags_atom |= UNUSED_RESERVATION_TURF_1
+ T.atom_flags |= UNUSED_RESERVATION_TURF_1
GLOB.areas_by_type[world.area].contents += T
CHECK_TICK
diff --git a/code/controllers/subsystem/minimaps.dm b/code/controllers/subsystem/minimaps.dm
index 83e60b714b2f1..3884550f0aff4 100644
--- a/code/controllers/subsystem/minimaps.dm
+++ b/code/controllers/subsystem/minimaps.dm
@@ -322,7 +322,7 @@ SUBSYSTEM_DEF(minimaps)
if(mover != src)
return
var/image/blip = SSminimaps.images_by_source[src]
- blip?.UnregisterSignal(source, COMSIG_MOVABLE_MOVED) // RUTGMC ADDITION, added "?"
+ blip?.UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
UnregisterSignal(source, COMSIG_ATOM_EXITED)
@@ -353,7 +353,7 @@ SUBSYSTEM_DEF(minimaps)
var/hash = "[zlevel]-[flags]"
if(hashed_minimaps[hash])
return hashed_minimaps[hash]
- var/atom/movable/screen/minimap/map = new(null, zlevel, flags)
+ var/atom/movable/screen/minimap/map = new(null, null, zlevel, flags)
if (!map.icon) //Don't wanna save an unusable minimap for a z-level.
CRASH("Empty and unusable minimap generated for '[zlevel]-[flags]'") //Can be caused by atoms calling this proc before minimap subsystem initializing.
hashed_minimaps[hash] = map
@@ -381,7 +381,7 @@ SUBSYSTEM_DEF(minimaps)
///assoc list of mob choices by clicking on coords. only exists fleetingly for the wait loop in [/proc/get_coords_from_click]
var/list/mob/choices_by_mob
-/atom/movable/screen/minimap/Initialize(mapload, target, flags)
+/atom/movable/screen/minimap/Initialize(mapload, datum/hud/hud_owner, target, flags)
. = ..()
if(!SSminimaps.minimaps_by_z["[target]"])
return
@@ -516,20 +516,20 @@ SUBSYSTEM_DEF(minimaps)
var/atom/movable/tracking = locator_override ? locator_override : owner
var/atom/movable/new_track = to_track ? to_track : owner
if(locator_override)
- UnregisterSignal(locator_override, COMSIG_QDELETING)
+ clear_locator_override()
if(owner)
UnregisterSignal(tracking, COMSIG_MOVABLE_Z_CHANGED)
if(!minimap_displayed)
locator_override = to_track
if(to_track)
RegisterSignal(to_track, COMSIG_QDELETING, TYPE_PROC_REF(/datum/action/minimap, clear_locator_override))
- if(owner?.loc == to_track) // RUTGMC ADDITION, added "?"
+ if(owner && owner.loc == to_track)
RegisterSignal(to_track, COMSIG_ATOM_EXITED, TYPE_PROC_REF(/datum/action/minimap, on_exit_check))
if(owner)
RegisterSignal(new_track, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change))
var/turf/old_turf = get_turf(tracking)
- if(!old_turf.z || old_turf.z != new_track.z)
- on_owner_z_change(new_track, old_turf.z, new_track.z)
+ if(!old_turf || !old_turf.z || old_turf.z != new_track.z)
+ on_owner_z_change(new_track, old_turf?.z, new_track?.z)
return
locator.UnregisterSignal(tracking, COMSIG_MOVABLE_MOVED)
locator_override = to_track
diff --git a/code/controllers/subsystem/modularmapping.dm b/code/controllers/subsystem/modularmapping.dm
index 75904f4aeed6f..017de18c4253f 100644
--- a/code/controllers/subsystem/modularmapping.dm
+++ b/code/controllers/subsystem/modularmapping.dm
@@ -1,5 +1,5 @@
SUBSYSTEM_DEF(modularmapping)
- name = "Modularmapping"
+ name = "Modular Mapping"
init_order = INIT_ORDER_MODULARMAPPING
flags = SS_NO_FIRE
var/list/obj/effect/spawner/modularmap/markers = list()
diff --git a/code/controllers/subsystem/monitor.dm b/code/controllers/subsystem/monitor.dm
index b61246c03a7a3..2bd946a92b04b 100644
--- a/code/controllers/subsystem/monitor.dm
+++ b/code/controllers/subsystem/monitor.dm
@@ -68,7 +68,7 @@ SUBSYSTEM_DEF(monitor)
GLOB.xeno_stat_multiplicator_buff = proposed_balance_buff
apply_balance_changes()
- if(SSticker.mode?.flags_round_type & MODE_SILOS_SPAWN_MINIONS)
+ if(SSticker.mode?.round_type_flags & MODE_SILOS_SPAWN_MINIONS)
//Balance spawners output
for(var/silo in GLOB.xeno_resin_silos_by_hive[XENO_HIVE_NORMAL])
SSspawning.spawnerdata[silo].required_increment = 2 * max(45 SECONDS, 3 MINUTES - SSmonitor.maximum_connected_players_count * SPAWN_RATE_PER_PLAYER) / SSspawning.wait
@@ -137,7 +137,7 @@ SUBSYSTEM_DEF(monitor)
var/area/myarea = TU.loc
if(is_ground_level(TU.z))
human_on_ground++
- if(myarea.flags_area & NEAR_FOB)
+ if(myarea.area_flags & NEAR_FOB)
human_in_FOB++
else if(is_mainship_level(TU.z))
human_on_ship++
diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm
index b3f4066a314ea..b187a731bfce4 100644
--- a/code/controllers/subsystem/persistence.dm
+++ b/code/controllers/subsystem/persistence.dm
@@ -42,6 +42,7 @@ SUBSYSTEM_DEF(persistence)
/datum/season_datum/weapons/guns/heavy_ff,
/datum/season_datum/weapons/guns/heavy_autorail,
/datum/season_datum/weapons/guns/heavy_shock,
+ /datum/season_datum/weapons/guns/heavy_explosions,
),
)
///The saved list of custom outfits names
@@ -355,5 +356,20 @@ SUBSYSTEM_DEF(persistence)
/obj/item/ammo_magazine/rocket/recoilless/smoke = 16,
/obj/item/ammo_magazine/rocket/recoilless/plasmaloss = 16,
/obj/structure/closet/crate/mortar_ammo/mlrs_kit = 2,
- /obj/item/storage/box/mlrs_rockets_gas = 4,
+ /obj/item/storage/box/mlrs_rockets/gas = 4,
+ )
+
+/datum/season_datum/weapons/guns/heavy_explosions
+ name = "Explosive Heavy Weapons"
+ description = "Flak cannon and Recoilless guns for roundstart vendors."
+ item_list = list(
+ /obj/structure/largecrate/supply/weapons/heavy_flakgun = 1,
+ /obj/item/ammo_magazine/heavy_isg/he = 8,
+ /obj/item/ammo_magazine/heavy_isg/sabot = 5,
+ /obj/item/storage/holster/backholster/rpg/full = 2,
+ /obj/item/ammo_magazine/rocket/recoilless = 4,
+ /obj/item/ammo_magazine/rocket/recoilless/light = 4,
+ /obj/item/ammo_magazine/rocket/recoilless/heat = 16,
+ /obj/item/ammo_magazine/rocket/recoilless/cloak = 16,
+ /obj/item/ammo_magazine/rocket/recoilless/smoke = 16,
)
diff --git a/code/controllers/subsystem/points.dm b/code/controllers/subsystem/points.dm
index 9f9168436deb2..f64166e8e45fd 100644
--- a/code/controllers/subsystem/points.dm
+++ b/code/controllers/subsystem/points.dm
@@ -12,8 +12,10 @@ SUBSYSTEM_DEF(points)
var/dropship_points = 0
///Assoc list of supply points
var/supply_points = list()
- ///Assoc list of xeno points: xeno_points_by_hive["hivenum"]
- var/list/xeno_points_by_hive = list()
+ ///Assoc list of xeno strategic points: xeno_strategic_points_by_hive["hivenum"]
+ var/list/xeno_strategic_points_by_hive = list()
+ ///Assoc list of xeno tactical points: xeno_tactical_points_by_hive["hivenum"]
+ var/list/xeno_tactical_points_by_hive = list()
var/ordernum = 1 //order number given to next order
@@ -78,12 +80,17 @@ SUBSYSTEM_DEF(points)
for(var/key in supply_points)
supply_points[key] += SUPPLY_POINT_RATE / (1 MINUTES / wait)
-///Add amount of psy points to the selected hive only if the gamemode support psypoints
-/datum/controller/subsystem/points/proc/add_psy_points(hivenumber, amount)
- if(!CHECK_BITFIELD(SSticker.mode.flags_round_type, MODE_PSY_POINTS))
+///Add amount of strategic psy points to the selected hive only if the gamemode support psypoints
+/datum/controller/subsystem/points/proc/add_strategic_psy_points(hivenumber, amount)
+ if(!CHECK_BITFIELD(SSticker.mode.round_type_flags, MODE_PSY_POINTS))
return
- xeno_points_by_hive[hivenumber] += amount
+ xeno_strategic_points_by_hive[hivenumber] += amount
+///Add amount of tactical psy points to the selected hive only if the gamemode support psypoints
+/datum/controller/subsystem/points/proc/add_tactical_psy_points(hivenumber, amount)
+ if(!CHECK_BITFIELD(SSticker.mode.round_type_flags, MODE_PSY_POINTS))
+ return
+ xeno_tactical_points_by_hive[hivenumber] += amount
/datum/controller/subsystem/points/proc/approve_request(datum/supply_order/O, mob/living/user)
var/cost = 0
diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm
index 3786348ba556a..1ae502ef1ff2c 100644
--- a/code/controllers/subsystem/server_maint.dm
+++ b/code/controllers/subsystem/server_maint.dm
@@ -17,6 +17,8 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/Initialize()
+ if (fexists("tmp/"))
+ fdel("tmp/")
if(CONFIG_GET(flag/hub))
world.update_hub_visibility(TRUE)
return SS_INIT_SUCCESS
@@ -105,6 +107,8 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/Shutdown()
+ if (fexists("tmp/"))
+ fdel("tmp/")
var/server = CONFIG_GET(string/server)
for(var/thing in GLOB.clients)
if(!thing)
diff --git a/code/controllers/subsystem/silo.dm b/code/controllers/subsystem/silo.dm
index a14126b04258c..672f8cb5a8853 100644
--- a/code/controllers/subsystem/silo.dm
+++ b/code/controllers/subsystem/silo.dm
@@ -27,7 +27,9 @@ SUBSYSTEM_DEF(silo)
current_larva_spawn_rate *= SSmonitor.gamestate == SHIPSIDE ? 3 : 1
current_larva_spawn_rate *= SSticker.mode.silo_scaling
//We scale the rate based on the current ratio of humans to xenos
- current_larva_spawn_rate *= clamp(round((active_humans / active_xenos) / (LARVA_POINTS_REGULAR / xeno_job.job_points_needed), 0.01), 0.5, 1)
+ var/current_human_to_xeno_ratio = active_humans / active_xenos
+ var/optimal_human_to_xeno_ratio = xeno_job.job_points_needed / LARVA_POINTS_REGULAR
+ current_larva_spawn_rate *= clamp(current_human_to_xeno_ratio / optimal_human_to_xeno_ratio , 0.7, 1)
current_larva_spawn_rate += larva_spawn_rate_temporary_buff
@@ -42,5 +44,5 @@ SUBSYSTEM_DEF(silo)
/datum/controller/subsystem/silo/proc/start_spawning()
SIGNAL_HANDLER
UnregisterSignal(SSdcs, list(COMSIG_GLOB_OPEN_TIMED_SHUTTERS_LATE, COMSIG_GLOB_OPEN_TIMED_SHUTTERS_XENO_HIVEMIND, COMSIG_GLOB_OPEN_SHUTTERS_EARLY, COMSIG_GLOB_TADPOLE_LAUNCHED))
- if(SSticker.mode?.flags_round_type & MODE_SILO_RESPAWN)
+ if(SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN)
can_fire = TRUE
diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm
index a818038be2ccb..038991401dda2 100644
--- a/code/controllers/subsystem/tgui.dm
+++ b/code/controllers/subsystem/tgui.dm
@@ -19,10 +19,8 @@ SUBSYSTEM_DEF(tgui)
/// A list of UIs scheduled to process
var/list/current_run = list()
- /// A list of open UIs
- var/list/open_uis = list()
- /// A list of open UIs, grouped by src_object.
- var/list/open_uis_by_src = list()
+ /// A list of all open UIs
+ var/list/all_uis = list()
/// The HTML base used for all UIs.
var/basehtml
@@ -37,12 +35,12 @@ SUBSYSTEM_DEF(tgui)
close_all_uis()
/datum/controller/subsystem/tgui/stat_entry(msg)
- msg = "P:[length(open_uis)]"
+ msg = "P:[length(all_uis)]"
return ..()
/datum/controller/subsystem/tgui/fire(resumed = FALSE)
if(!resumed)
- src.current_run = open_uis.Copy()
+ src.current_run = all_uis.Copy()
// Cache for sanic speed (lists are references anyways)
var/list/current_run = src.current_run
while(length(current_run))
@@ -52,7 +50,7 @@ SUBSYSTEM_DEF(tgui)
if(ui?.user && ui.src_object)
ui.process(wait * 0.1)
else
- open_uis.Remove(ui)
+ ui.close(0)
if(MC_TICK_CHECK)
return
@@ -171,11 +169,10 @@ SUBSYSTEM_DEF(tgui)
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object)
- var/key = "[REF(src_object)]"
// No UIs opened for this src_object
- if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
+ if(!LAZYLEN(src_object?.open_uis))
return null
- for(var/datum/tgui/ui in open_uis_by_src[key])
+ for(var/datum/tgui/ui in src_object.open_uis)
// Make sure we have the right user
if(ui.user == user)
return ui
@@ -191,12 +188,11 @@ SUBSYSTEM_DEF(tgui)
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
- var/count = 0
- var/key = "[REF(src_object)]"
// No UIs opened for this src_object
- if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
- return count
- for(var/datum/tgui/ui in open_uis_by_src[key])
+ if(!LAZYLEN(src_object?.open_uis))
+ return 0
+ var/count = 0
+ for(var/datum/tgui/ui in src_object.open_uis)
// Check if UI is valid.
if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.process(wait * 0.1, force = 1)
@@ -213,12 +209,11 @@ SUBSYSTEM_DEF(tgui)
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
- var/count = 0
- var/key = "[REF(src_object)]"
// No UIs opened for this src_object
- if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
- return count
- for(var/datum/tgui/ui in open_uis_by_src[key])
+ if(!LAZYLEN(src_object?.open_uis))
+ return 0
+ var/count = 0
+ for(var/datum/tgui/ui in src_object.open_uis)
// Check if UI is valid.
if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.close()
@@ -234,12 +229,11 @@ SUBSYSTEM_DEF(tgui)
*/
/datum/controller/subsystem/tgui/proc/close_all_uis()
var/count = 0
- for(var/key in open_uis_by_src)
- for(var/datum/tgui/ui in open_uis_by_src[key])
- // Check if UI is valid.
- if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
- ui.close()
- count++
+ for(var/datum/tgui/ui in all_uis)
+ // Check if UI is valid.
+ if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user))
+ ui.close()
+ count++
return count
/**
@@ -290,13 +284,9 @@ SUBSYSTEM_DEF(tgui)
* required ui datum/tgui The UI to be added.
*/
/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
- var/key = "[REF(ui.src_object)]"
- if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
- open_uis_by_src[key] = list()
- ui.user.tgui_open_uis |= ui
- var/list/uis = open_uis_by_src[key]
- uis |= ui
- open_uis |= ui
+ ui.user?.tgui_open_uis |= ui
+ LAZYOR(ui.src_object.open_uis, ui)
+ all_uis |= ui
/**
* private
@@ -308,18 +298,14 @@ SUBSYSTEM_DEF(tgui)
* return bool If the UI was removed or not.
*/
/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
- var/key = "[REF(ui.src_object)]"
- if(isnull(open_uis_by_src[key]) || !istype(open_uis_by_src[key], /list))
- return FALSE
// Remove it from the list of processing UIs.
- open_uis.Remove(ui)
+ all_uis -= ui
+ current_run -= ui
// If the user exists, remove it from them too.
if(ui.user)
- ui.user.tgui_open_uis.Remove(ui)
- var/list/uis = open_uis_by_src[key]
- uis.Remove(ui)
- if(length(uis) == 0)
- open_uis_by_src.Remove(key)
+ ui.user.tgui_open_uis -= ui
+ if(ui.src_object)
+ LAZYREMOVE(ui.src_object.open_uis, ui)
return TRUE
/**
@@ -354,7 +340,7 @@ SUBSYSTEM_DEF(tgui)
for(var/datum/tgui/ui in source.tgui_open_uis)
// Inform the UIs of their new owner.
ui.user = target
- target.tgui_open_uis.Add(ui)
+ target.tgui_open_uis += ui
// Clear the old list.
source.tgui_open_uis.Cut()
return TRUE
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 76812a33fe4e8..d92c066d73947 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -179,6 +179,7 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
PostSetup()
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GAMEMODE_LOADED)
return TRUE
diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm
new file mode 100644
index 0000000000000..1afe1c62100c8
--- /dev/null
+++ b/code/controllers/subsystem/vis_overlays.dm
@@ -0,0 +1,77 @@
+SUBSYSTEM_DEF(vis_overlays)
+ name = "Vis contents overlays"
+ wait = 1 MINUTES
+ priority = FIRE_PRIORITY_VIS
+ init_order = INIT_ORDER_VIS
+
+ var/list/vis_overlay_cache
+ var/list/currentrun
+
+/datum/controller/subsystem/vis_overlays/Initialize()
+ vis_overlay_cache = list()
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
+ if(!resumed)
+ currentrun = vis_overlay_cache.Copy()
+ var/list/current_run = currentrun
+
+ while(current_run.len)
+ var/key = current_run[current_run.len]
+ var/obj/effect/overlay/vis/overlay = current_run[key]
+ current_run.len--
+ if(!overlay.unused && !length(overlay.vis_locs))
+ overlay.unused = world.time
+ else if(overlay.unused && overlay.unused + overlay.cache_expiration < world.time)
+ vis_overlay_cache -= key
+ qdel(overlay)
+ if(MC_TICK_CHECK)
+ return
+
+//the "thing" var can be anything with vis_contents which includes images - in the future someone should totally allow vis overlays to be passed in as an arg instead of all this bullshit
+/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE)
+ var/obj/effect/overlay/vis/overlay
+ if(!unique)
+ . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
+ overlay = vis_overlay_cache[.]
+ if(!overlay)
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ vis_overlay_cache[.] = overlay
+ else
+ overlay.unused = 0
+ else
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ overlay.cache_expiration = -1
+ var/cache_id = "[text_ref(overlay)]@{[world.time]}"
+ vis_overlay_cache[cache_id] = overlay
+ . = overlay
+ thing.vis_contents += overlay
+
+ if(!isatom(thing)) // Automatic rotation is not supported on non atoms
+ return overlay
+
+ if(!thing.managed_vis_overlays)
+ thing.managed_vis_overlays = list(overlay)
+ else
+ thing.managed_vis_overlays += overlay
+ return overlay
+
+/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ var/obj/effect/overlay/vis/overlay = new
+ overlay.icon = icon
+ overlay.icon_state = iconstate
+ overlay.layer = layer
+ overlay.plane = plane
+ overlay.dir = dir
+ overlay.alpha = alpha
+ overlay.appearance_flags |= add_appearance_flags
+ return overlay
+
+
+/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
+ thing.vis_contents -= overlays
+ if(!isatom(thing))
+ return
+ thing.managed_vis_overlays -= overlays
+ if(!length(thing.managed_vis_overlays))
+ thing.managed_vis_overlays = null
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index b6d4001c1a830..505ab205d1991 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -273,10 +273,12 @@ SUBSYSTEM_DEF(vote)
var/datum/map_config/VM = config.maplist[GROUND_MAP][map]
if(!VM.voteweight)
continue
+ if(VM.map_name == SSmapping.configs[GROUND_MAP].map_name) //Current map is not votable
+ continue
if(next_gamemode.whitelist_ground_maps)
if(!(VM.map_name in next_gamemode.whitelist_ground_maps))
continue
- else if(next_gamemode.blacklist_ground_maps) //can't blacklist and whitelist for the same map
+ else if(next_gamemode.blacklist_ground_maps) //Can't blacklist and whitelist for the same map
if(VM.map_name in next_gamemode.blacklist_ground_maps)
continue
if(VM.config_max_users || VM.config_min_users)
diff --git a/code/datums/actions/ability_actions.dm b/code/datums/actions/ability_actions.dm
index fb5e2129d3701..95437b3ad91b6 100644
--- a/code/datums/actions/ability_actions.dm
+++ b/code/datums/actions/ability_actions.dm
@@ -17,15 +17,20 @@
var/target_flags = NONE
/// flags to restrict an ability to certain gamemode
var/gamemode_flags = ABILITY_ALL_GAMEMODE
+ ///Cooldown map text holder
+ var/obj/effect/countdown/action_cooldown/countdown
/datum/action/ability/New(Target)
. = ..()
if(ability_cost)
name = "[name] ([ability_cost])"
- var/image/cooldown_image = image('icons/effects/progressicons.dmi', null, "busy_clock", ACTION_LAYER_CLOCK)
- cooldown_image.pixel_y = 7
- cooldown_image.appearance_flags = RESET_COLOR|RESET_ALPHA
- visual_references[VREF_IMAGE_XENO_CLOCK] = cooldown_image
+ countdown = new(button, src)
+
+/datum/action/ability/Destroy()
+ if(cooldown_timer)
+ deltimer(cooldown_timer)
+ QDEL_NULL(countdown)
+ return ..()
/datum/action/ability/give_action(mob/living/L)
. = ..()
@@ -33,8 +38,6 @@
carbon_owner.mob_abilities += src
/datum/action/ability/remove_action(mob/living/L)
- if(cooldown_timer)
- deltimer(cooldown_timer)
var/mob/living/carbon/carbon_owner = L
if(!istype(carbon_owner))
stack_trace("/datum/action/ability/remove_action called with [L], expecting /mob/living/carbon.")
@@ -53,49 +56,49 @@
var/mob/living/carbon/carbon_owner = owner
if(!carbon_owner)
return FALSE
- var/flags_to_check = use_state_flags|override_flags
+ var/to_check_flags = use_state_flags|override_flags
- if(!(flags_to_check & ABILITY_IGNORE_COOLDOWN) && !action_cooldown_check())
+ if(!(to_check_flags & ABILITY_IGNORE_COOLDOWN) && !action_cooldown_check())
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Wait [cooldown_remaining()] sec")
return FALSE
- if(!(flags_to_check & ABILITY_USE_INCAP) && carbon_owner.incapacitated())
+ if(!(to_check_flags & ABILITY_USE_INCAP) && carbon_owner.incapacitated())
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot while incapacitated")
return FALSE
- if(!(flags_to_check & ABILITY_USE_LYING) && carbon_owner.lying_angle)
+ if(!(to_check_flags & ABILITY_USE_LYING) && carbon_owner.lying_angle)
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot while lying down")
return FALSE
- if(!(flags_to_check & ABILITY_USE_BUCKLED) && carbon_owner.buckled)
+ if(!(to_check_flags & ABILITY_USE_BUCKLED) && carbon_owner.buckled)
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot while buckled")
return FALSE
- if(!(flags_to_check & ABILITY_USE_STAGGERED) && carbon_owner.IsStaggered())
+ if(!(to_check_flags & ABILITY_USE_STAGGERED) && carbon_owner.IsStaggered())
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot while staggered")
return FALSE
- if(!(flags_to_check & ABILITY_USE_NOTTURF) && !isturf(carbon_owner.loc))
+ if(!(to_check_flags & ABILITY_USE_NOTTURF) && !isturf(carbon_owner.loc))
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot do this here")
return FALSE
- if(!(flags_to_check & ABILITY_USE_BUSY) && carbon_owner.do_actions)
+ if(!(to_check_flags & ABILITY_USE_BUSY) && carbon_owner.do_actions)
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot, busy")
return FALSE
- if(!(flags_to_check & ABILITY_USE_BURROWED) && HAS_TRAIT(carbon_owner, TRAIT_BURROWED))
+ if(!(to_check_flags & ABILITY_USE_BURROWED) && HAS_TRAIT(carbon_owner, TRAIT_BURROWED))
if(!silent)
carbon_owner.balloon_alert(carbon_owner, "Cannot while burrowed")
return FALSE
- if(!(flags_to_check & ABILITY_USE_CLOSEDTURF) && isclosedturf(get_turf(carbon_owner)))
+ if(!(to_check_flags & ABILITY_USE_CLOSEDTURF) && isclosedturf(get_turf(carbon_owner)))
if(!silent)
//Not converted to balloon alert as xeno.dm's balloon alert is simultaneously called and will overlap.
to_chat(owner, span_warning("We can't do this while in a solid object!"))
@@ -141,7 +144,8 @@
if(cooldown_timer || !cooldown_length) // stop doubling up or waiting on zero
return
cooldown_timer = addtimer(CALLBACK(src, PROC_REF(on_cooldown_finish)), cooldown_length, TIMER_STOPPABLE)
- button.add_overlay(visual_references[VREF_IMAGE_XENO_CLOCK])
+ countdown.start()
+ update_button_icon()
///Time remaining on cooldown
/datum/action/ability/proc/cooldown_remaining()
@@ -150,9 +154,10 @@
///override this for cooldown completion
/datum/action/ability/proc/on_cooldown_finish()
cooldown_timer = null
+ countdown.stop()
if(!button)
- CRASH("no button object on finishing ability action cooldown")
- button.cut_overlay(visual_references[VREF_IMAGE_XENO_CLOCK])
+ return
+ update_button_icon()
///Any changes when a xeno with this ability evolves
/datum/action/ability/proc/on_xeno_upgrade()
@@ -163,10 +168,22 @@
/datum/action/ability/activable/Destroy()
var/mob/living/carbon/carbon_owner = owner
- if(carbon_owner.selected_ability == src)
+ if(carbon_owner?.selected_ability == src)
deselect()
return ..()
+/datum/action/ability/activable/set_toggle(value)
+ . = ..()
+ if(!.)
+ return
+ if(!owner)
+ return
+ if(toggled)
+ SEND_SIGNAL(owner, COMSIG_ACTION_EXCLUSIVE_TOGGLE, owner)
+ RegisterSignal(owner, COMSIG_ACTION_EXCLUSIVE_TOGGLE, PROC_REF(deselect))
+ else
+ UnregisterSignal(owner, COMSIG_ACTION_EXCLUSIVE_TOGGLE)
+
/datum/action/ability/activable/alternate_action_activate()
INVOKE_ASYNC(src, PROC_REF(action_activate))
@@ -192,6 +209,7 @@
action_activate()
/datum/action/ability/activable/remove_action(mob/living/carbon/carbon_owner)
+ deselect()
if(carbon_owner.selected_ability == src)
carbon_owner.selected_ability = null
return ..()
@@ -206,13 +224,13 @@
if(QDELETED(owner))
return FALSE
- var/flags_to_check = use_state_flags|override_flags
+ var/to_check_flags = use_state_flags|override_flags
var/mob/living/carbon/carbon_owner = owner
- if(!CHECK_BITFIELD(flags_to_check, ABILITY_IGNORE_SELECTED_ABILITY) && carbon_owner.selected_ability != src)
+ if(!CHECK_BITFIELD(to_check_flags, ABILITY_IGNORE_SELECTED_ABILITY) && carbon_owner.selected_ability != src)
return FALSE
. = can_use_action(silent, override_flags)
- if(!CHECK_BITFIELD(flags_to_check, ABILITY_TARGET_SELF) && A == owner)
+ if(!CHECK_BITFIELD(to_check_flags, ABILITY_TARGET_SELF) && A == owner)
return FALSE
///the thing to do when the selected action ability is selected and triggered by middle_click
@@ -220,17 +238,18 @@
return
///Setting this ability as the active ability
-/datum/action/ability/activable/proc/select()
+/datum/action/ability/activable/select()
+ . = ..()
var/mob/living/carbon/carbon_owner = owner
- set_toggle(TRUE)
carbon_owner.selected_ability = src
on_selection()
///Deselecting this ability for use
-/datum/action/ability/activable/proc/deselect()
- var/mob/living/carbon/carbon_owner = owner
- set_toggle(FALSE)
- carbon_owner.selected_ability = null
+/datum/action/ability/activable/deselect()
+ . = ..()
+ if(owner)
+ var/mob/living/carbon/carbon_owner = owner
+ carbon_owner.selected_ability = null
on_deselection()
///Any effects on selecting this ability
@@ -254,7 +273,7 @@
/mob/living/carbon/proc/add_ability(datum/action/ability/new_ability)
if(!new_ability)
return
- new_ability = new new_ability
+ new_ability = new new_ability(src)
new_ability.give_action(src)
///Removes an ability from a mob
diff --git a/code/datums/actions/action.dm b/code/datums/actions/action.dm
index 6ccb7b23b09b6..9427574dfaf3c 100644
--- a/code/datums/actions/action.dm
+++ b/code/datums/actions/action.dm
@@ -61,8 +61,10 @@ KEYBINDINGS
target = null
return ..()
+/// Cleans up the action if the owner is deleted
/datum/action/proc/clean_action()
SIGNAL_HANDLER
+ SHOULD_CALL_PARENT(TRUE)
qdel(src)
/datum/action/proc/should_show()
@@ -71,21 +73,19 @@ KEYBINDINGS
///Depending on the action type , toggles the selected/active frame to show without allowing stacking multiple overlays
/datum/action/proc/set_toggle(value)
if(value == toggled)
- return
- if(value)
- switch(action_type)
- if(ACTION_SELECT)
- button.add_overlay(visual_references[VREF_MUTABLE_SELECTED_FRAME])
- if(ACTION_TOGGLE)
- button.add_overlay(visual_references[VREF_MUTABLE_ACTIVE_FRAME])
- toggled = TRUE
- return
- switch(action_type)
- if(ACTION_SELECT)
- button.cut_overlay(visual_references[VREF_MUTABLE_SELECTED_FRAME])
- if(ACTION_TOGGLE)
- button.cut_overlay(visual_references[VREF_MUTABLE_ACTIVE_FRAME])
- toggled = FALSE
+ return FALSE
+ toggled = value
+ update_button_icon()
+ return TRUE
+
+///Setting this action as the active action
+/datum/action/proc/select()
+ set_toggle(TRUE)
+
+///Deselecting this action for use
+/datum/action/proc/deselect()
+ SIGNAL_HANDLER
+ set_toggle(FALSE)
///A handler used to update the maptext and show the change immediately.
/datum/action/proc/update_map_text(key_string, key_signal)
@@ -120,6 +120,17 @@ KEYBINDINGS
button.add_overlay(action_appearence)
if(background_icon_state != button.icon_state)
button.icon_state = background_icon_state
+ switch(action_type)
+ if(ACTION_SELECT)
+ button.cut_overlay(visual_references[VREF_MUTABLE_SELECTED_FRAME])
+ if(ACTION_TOGGLE)
+ button.cut_overlay(visual_references[VREF_MUTABLE_ACTIVE_FRAME])
+ if(toggled)
+ switch(action_type)
+ if(ACTION_SELECT)
+ button.add_overlay(visual_references[VREF_MUTABLE_SELECTED_FRAME])
+ if(ACTION_TOGGLE)
+ button.add_overlay(visual_references[VREF_MUTABLE_ACTIVE_FRAME])
handle_button_status_visuals()
return TRUE
diff --git a/code/datums/actions/item_action.dm b/code/datums/actions/item_action.dm
index f903661917cd5..a278e9a73b27d 100644
--- a/code/datums/actions/item_action.dm
+++ b/code/datums/actions/item_action.dm
@@ -25,9 +25,10 @@
return ..()
/datum/action/item_action/action_activate()
- if(target)
- var/obj/item/I = target
- I.ui_action_click(owner, src, holder_item)
+ if(!target)
+ return FALSE
+ var/obj/item/I = target
+ return I.ui_action_click(owner, src, holder_item)
/datum/action/item_action/can_use_action()
if(QDELETED(owner) || owner.incapacitated() || owner.lying_angle)
@@ -55,17 +56,15 @@
name = "Toggle [target]"
button.name = name
+/datum/action/item_action/toggle/action_activate()
+ . = ..()
+ if(!.)
+ return
+ set_toggle(!toggled)
+
/datum/action/item_action/toggle/suit_toggle
keybinding_signals = list(KEYBINDING_NORMAL = COMSIG_KB_SUITLIGHT)
-/datum/action/item_action/toggle/suit_toggle/update_button_icon()
- set_toggle(holder_item.light_on)
- return ..()
-
-/datum/action/item_action/toggle/motion_detector/action_activate()
- . = ..()
- update_button_icon()
-
/datum/action/item_action/firemode
// just here so players see what key is it bound to
keybinding_signals = list(
@@ -81,6 +80,12 @@
holder_gun = holder_item
update_button_icon()
+/datum/action/item_action/firemode/action_activate()
+ . = ..()
+ if(!.)
+ return
+ update_button_icon()
+
/datum/action/item_action/firemode/update_button_icon()
if(holder_gun.gun_firemode == action_firemode)
diff --git a/code/datums/actions/item_toggles.dm b/code/datums/actions/item_toggles.dm
new file mode 100644
index 0000000000000..9804364b42162
--- /dev/null
+++ b/code/datums/actions/item_toggles.dm
@@ -0,0 +1,40 @@
+/datum/action/ability/activable/item_toggle
+ name = ""
+ /**
+ *the item that has this action in its list of actions. Is not necessarily the target
+ * e.g. gun attachment action: target = attachment, holder = gun.
+ */
+ var/obj/item/holder_item
+ /// Defines wheter we overlay the image of the obj we are linked to
+ var/use_obj_appeareance = TRUE
+
+/datum/action/ability/activable/item_toggle/New(Target, obj/item/holder)
+ . = ..()
+ if(!holder)
+ holder = target
+ holder_item = holder
+ if(!name)
+ name = "Use [target]"
+ button.name = name
+
+/datum/action/ability/activable/item_toggle/Destroy()
+ holder_item = null
+ return ..()
+
+/datum/action/ability/activable/item_toggle/use_ability(atom/target)
+ holder_item.ui_action_click(owner, src, target)
+ succeed_activate()
+ add_cooldown()
+
+/datum/action/ability/activable/item_toggle/update_button_icon()
+ if(visual_references[VREF_MUTABLE_LINKED_OBJ])
+ button.cut_overlay(visual_references[VREF_MUTABLE_LINKED_OBJ])
+ if(use_obj_appeareance)
+ var/obj/item/I = target
+ // -0.5 so its below maptext and above the selected frames
+ var/item_image = mutable_appearance(I.icon, I.icon_state, ACTION_LAYER_IMAGE_ONTOP, FLOAT_PLANE)
+ visual_references[VREF_MUTABLE_LINKED_OBJ] = item_image
+ button.add_overlay(item_image)
+ else
+ visual_references[VREF_MUTABLE_LINKED_OBJ] = null
+ return ..()
diff --git a/code/datums/actions/order_action.dm b/code/datums/actions/order_action.dm
index 1b34232d0f75e..35dfb086e9eab 100644
--- a/code/datums/actions/order_action.dm
+++ b/code/datums/actions/order_action.dm
@@ -9,7 +9,7 @@
///What skill is needed to have this action
var/skill_name = SKILL_LEADERSHIP
///What minimum level in that skill is needed to have that action
- var/skill_min = SKILL_LEAD_EXPERT
+ var/skill_min = SKILL_LEAD_TRAINED
/datum/action/innate/order/give_action(mob/M)
. = ..()
diff --git a/code/datums/actions/species_actions/sectoid_action.dm b/code/datums/actions/species_actions/sectoid_action.dm
new file mode 100644
index 0000000000000..1ca81e912aff1
--- /dev/null
+++ b/code/datums/actions/species_actions/sectoid_action.dm
@@ -0,0 +1,563 @@
+
+/datum/action/ability/activable/sectoid
+ action_icon = 'icons/mob/psionic_icons.dmi'
+
+// ***************************************
+// *********** Mindmeld
+// ***************************************
+/datum/action/ability/activable/sectoid/mindmeld
+ name = "Mindmeld"
+ action_icon_state = "mindmeld"
+ desc = "Merge minds with the target, empowering both."
+ cooldown_duration = 60 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_MINDMELD,
+ )
+ var/mob/living/carbon/melded_mob
+ ///Range the linkees must be to each other to benefit
+ var/max_range = 6
+ ///Projectile accuracy buff
+ var/accuracy_mod = 25
+ ///Max health buff
+ var/health_mod = 50
+ ///Movement speed buff
+ var/speed_mod = -0.4
+ ///% chance to ignore stuns
+ var/stun_resistance = 0
+
+/datum/action/ability/activable/sectoid/mindmeld/remove_action(mob/living/carbon/carbon_owner)
+ end_ability()
+ return ..()
+
+/datum/action/ability/activable/sectoid/mindmeld/can_use_action()
+ . = ..()
+ if(!.)
+ return
+ var/mob/living/carbon/carbon_owner = owner
+ if(melded_mob)
+ return FALSE
+ if(HAS_TRAIT(carbon_owner, TRAIT_MINDMELDED))
+ return FALSE
+ return TRUE
+
+/datum/action/ability/activable/sectoid/mindmeld/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if(!iscarbon(A))
+ if(!silent)
+ A.balloon_alert(owner, "not living")
+ return FALSE
+ var/mob/living/carbon/carbon_target = A
+ if(owner.faction != carbon_target.faction)
+ if(!silent)
+ A.balloon_alert(owner, "hostile!")
+ return FALSE
+ if(HAS_TRAIT(carbon_target, TRAIT_MINDMELDED))
+ if(!silent)
+ A.balloon_alert(owner, "already melded!")
+ return FALSE
+ if((A.z != owner.z) || !line_of_sight(owner, A, max_range))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+ if(carbon_target.stat == DEAD)
+ if(!silent)
+ carbon_target.balloon_alert(owner, "already dead")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/mindmeld/use_ability(atom/target)
+ var/mob/living/carbon/carbon_owner = owner
+ melded_mob = target
+ melded_mob.balloon_alert_to_viewers("mindmelded")
+ owner.balloon_alert_to_viewers("mindmelded")
+ playsound(melded_mob, 'sound/effects/off_guard_ability.ogg', 50)
+
+ melded_mob.apply_status_effect(STATUS_EFFECT_MINDMEND, carbon_owner, max_range, accuracy_mod, health_mod, speed_mod, stun_resistance)
+ carbon_owner.apply_status_effect(STATUS_EFFECT_MINDMEND, carbon_owner, max_range, accuracy_mod, health_mod, speed_mod, stun_resistance)
+ RegisterSignal(melded_mob, COMSIG_MOB_DEATH, PROC_REF(end_ability))
+ RegisterSignal(carbon_owner, COMSIG_MOB_DEATH, PROC_REF(end_ability))
+
+ succeed_activate()
+ add_cooldown()
+
+/// Ends the ability if the Enhancement buff is removed.
+/datum/action/ability/activable/sectoid/mindmeld/proc/end_ability()
+ SIGNAL_HANDLER
+ UnregisterSignal(owner, COMSIG_MOB_DEATH)
+ var/mob/living/carbon/carbon_owner = owner
+ carbon_owner.remove_status_effect(STATUS_EFFECT_MINDMEND)
+ if(!melded_mob)
+ return
+ UnregisterSignal(melded_mob, COMSIG_MOB_DEATH)
+ melded_mob.remove_status_effect(STATUS_EFFECT_MINDMEND)
+ melded_mob = null
+
+/datum/action/ability/activable/sectoid/mindmeld/greater
+ name = "Greater Mindmeld"
+ desc = "Merge minds with the target, greatly empowering both."
+ max_range = 12
+ accuracy_mod = 40
+ health_mod = 70
+ speed_mod = -0.5
+ stun_resistance = 50
+
+#define MINDFRAY_RANGE 8
+/datum/action/ability/activable/sectoid/mindfray
+ name = "Mindfray"
+ action_icon_state = "mindfray"
+ desc = "Muddles the mind of an enemy, making it harder for them to focus their aim for a while."
+ cooldown_duration = 20 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_MINDFRAY,
+ )
+ ///damage of this ability
+ var/damage = 20
+
+/datum/action/ability/activable/sectoid/mindfray/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if(!iscarbon(A))
+ if(!silent)
+ A.balloon_alert(owner, "not living")
+ return FALSE
+ if(!line_of_sight(owner, A, 9))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+ if((A.z != owner.z) || get_dist(owner, A) > MINDFRAY_RANGE)
+ if(!silent)
+ A.balloon_alert(owner, "too far")
+ return FALSE
+ var/mob/living/carbon/carbon_target = A
+ if(carbon_target.stat == DEAD)
+ if(!silent)
+ carbon_target.balloon_alert(owner, "already dead")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/mindfray/use_ability(atom/target)
+ var/mob/living/carbon/carbon_target = target
+ carbon_target.apply_status_effect(STATUS_EFFECT_GUN_SKILL_SCATTER_DEBUFF, 10 SECONDS)
+ carbon_target.apply_status_effect(STATUS_EFFECT_CONFUSED, 40)
+ carbon_target.apply_damage(damage, BURN, updating_health = TRUE)
+ carbon_target.log_message("has been mindfrayed by [owner]", LOG_ATTACK, color="pink")
+ carbon_target.balloon_alert_to_viewers("confused")
+ playsound(carbon_target, 'sound/effects/off_guard_ability.ogg', 50)
+
+ add_cooldown()
+ succeed_activate()
+ update_button_icon()
+
+// ***************************************
+// *********** Stasis
+// ***************************************
+
+#define SECTOID_STASIS_RANGE 7
+/datum/action/ability/activable/sectoid/stasis
+ name = "stasis"
+ action_icon_state = "stasis"
+ desc = "We surround a living thing with a powerful psionic field, temporarily disabling them and protecting them from all harm."
+ cooldown_duration = 20 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ use_state_flags = ABILITY_TARGET_SELF
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_STASIS,
+ )
+ ///Duration of effect
+ var/stasis_duration = 5 SECONDS
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+
+/datum/action/ability/activable/sectoid/stasis/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if(!iscarbon(A))
+ if(!silent)
+ A.balloon_alert(owner, "not living")
+ return FALSE
+ if((A.z != owner.z) || get_dist(owner, A) > SECTOID_STASIS_RANGE)
+ if(!silent)
+ A.balloon_alert(owner, "too far")
+ return FALSE
+ if(!line_of_sight(owner, A, SECTOID_STASIS_RANGE))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+ var/mob/living/carbon/carbon_target = A
+ if(carbon_target.stat == DEAD)
+ if(!silent)
+ carbon_target.balloon_alert(owner, "already dead")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/stasis/use_ability(atom/target)
+ particle_holder = new(owner, /particles/drone_enhancement)
+ particle_holder.pixel_x = 0
+ particle_holder.pixel_y = -3
+ particle_holder.particles.velocity = list(0, 1.5)
+ particle_holder.particles.gravity = list(0, 2)
+
+ if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, target, BUSY_ICON_DANGER) || !can_use_ability(target))
+ owner.balloon_alert(owner, "Our focus is disrupted")
+ QDEL_NULL(particle_holder)
+ return fail_activate()
+
+ var/mob/living/carbon/carbon_target = target
+ playsound(owner, 'sound/effects/petrify_activate.ogg', 50)
+
+ carbon_target.notransform = TRUE
+ carbon_target.status_flags |= GODMODE
+ ADD_TRAIT(carbon_target, TRAIT_HANDS_BLOCKED, REF(src))
+ carbon_target.move_resist = MOVE_FORCE_OVERPOWERING
+ carbon_target.add_atom_colour(COLOR_GRAY, TEMPORARY_COLOUR_PRIORITY)
+ carbon_target.log_message("has been petrified by [owner] for [stasis_duration] ticks", LOG_ATTACK, color="pink")
+
+ var/image/stone_overlay = image('icons/effects/64x64.dmi', null, "stasis_overlay", pixel_y = -4)
+ stone_overlay.filters += filter(arglist(alpha_mask_filter(render_source="*[REF(carbon_target)]",flags=MASK_INVERSE)))
+
+ var/mutable_appearance/mask = mutable_appearance()
+ mask.appearance = carbon_target.appearance
+ mask.render_target = "*[REF(carbon_target)]"
+ mask.alpha = 125
+ mask.pixel_y = 4
+ stone_overlay.overlays += mask
+
+ carbon_target.overlays += stone_overlay
+ addtimer(CALLBACK(src, PROC_REF(end_effects), carbon_target, stone_overlay), stasis_duration)
+ QDEL_NULL(particle_holder)
+ add_cooldown()
+ update_button_icon()
+ succeed_activate()
+
+///ends all combat-relazted effects
+/datum/action/ability/activable/sectoid/stasis/proc/end_effects(mob/living/carbon/carbon_target, image/stone_overlay)
+ carbon_target.notransform = FALSE
+ carbon_target.status_flags &= ~GODMODE
+ REMOVE_TRAIT(carbon_target, TRAIT_HANDS_BLOCKED, REF(src))
+ carbon_target.move_resist = initial(carbon_target.move_resist)
+ carbon_target.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_GRAY)
+ carbon_target.overlays -= stone_overlay
+
+// ***************************************
+// *********** Reknit form
+// ***************************************
+
+#define SECTOID_REKNIT_RANGE 4
+/datum/action/ability/activable/sectoid/reknit_form
+ name = "Reknit Form"
+ action_icon_state = "reknit_form"
+ desc = "Flesh and bone runs like water at our will, healing horrendous damage with the power of our mind."
+ cooldown_duration = 60 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ use_state_flags = ABILITY_TARGET_SELF
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_REKNIT_FORM,
+ )
+ ///damage of this ability
+ var/reknit_duration = 3 SECONDS
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+
+/datum/action/ability/activable/sectoid/reknit_form/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if(!isliving(A))
+ if(!silent)
+ A.balloon_alert(owner, "not living")
+ return FALSE
+ if((A.z != owner.z) || get_dist(owner, A) > SECTOID_REKNIT_RANGE)
+ if(!silent)
+ A.balloon_alert(owner, "too far")
+ return FALSE
+ if(!line_of_sight(owner, A, SECTOID_REKNIT_RANGE))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/reknit_form/use_ability(atom/target)
+ particle_holder = new(owner, /particles/drone_enhancement)
+ particle_holder.pixel_x = 0
+ particle_holder.pixel_y = -3
+ particle_holder.particles.velocity = list(0, 1.5)
+ particle_holder.particles.gravity = list(0, 2)
+
+ if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, target, BUSY_ICON_DANGER) || !can_use_ability(target))
+ owner.balloon_alert(owner, "Our focus is disrupted")
+ QDEL_NULL(particle_holder)
+ return fail_activate()
+
+ var/mob/living/living_target = target
+ living_target.apply_status_effect(STATUS_EFFECT_REKNIT_FORM, reknit_duration)
+ QDEL_NULL(particle_holder)
+ playsound(owner, 'sound/effects/petrify_activate.ogg', 50)
+ add_cooldown()
+ update_button_icon()
+ succeed_activate()
+
+/datum/action/ability/activable/sectoid/reknit_form/greater
+ name = "Greater Reknit Form"
+ action_icon_state = "greater_reknit_form"
+ reknit_duration = 6 SECONDS
+
+// ***************************************
+// *********** Fuse
+// ***************************************
+
+#define SECTOID_FUSE_RANGE 6
+/datum/action/ability/activable/sectoid/fuse
+ name = "Fuse"
+ action_icon_state = "fuse"
+ desc = "We reach out with our mind to trigger an explosive device."
+ cooldown_duration = 45 SECONDS
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_FUSE,
+ )
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+
+/datum/action/ability/activable/sectoid/fuse/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if((A.z != owner.z) || get_dist(owner, A) > SECTOID_FUSE_RANGE)
+ if(!silent)
+ A.balloon_alert(owner, "too far")
+ return FALSE
+ if(!line_of_sight(owner, A, SECTOID_FUSE_RANGE))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/fuse/use_ability(atom/target)
+ particle_holder = new(owner, /particles/drone_enhancement)
+ particle_holder.pixel_x = 0
+ particle_holder.pixel_y = -3
+ particle_holder.particles.velocity = list(0, 1.5)
+ particle_holder.particles.gravity = list(0, 2)
+
+ if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, target, BUSY_ICON_DANGER) || !can_use_ability(target))
+ owner.balloon_alert(owner, "Our focus is disrupted")
+ QDEL_NULL(particle_holder)
+ return fail_activate()
+
+ QDEL_NULL(particle_holder)
+ var/obj/item/explosive/grenade/grenade_target
+ if(isgrenade(target))
+ grenade_target = target
+ else
+ grenade_target = locate(/obj/item/explosive/grenade) in target.GetAllContents()
+ if(!grenade_target)
+ target.balloon_alert(owner, "no grenade found")
+ return fail_activate()
+
+ grenade_target.activate(owner)
+ playsound(owner, 'sound/effects/petrify_activate.ogg', 50)
+ add_cooldown()
+ update_button_icon()
+ succeed_activate()
+
+// ***************************************
+// *********** Psionic Interact
+// ***************************************
+
+/datum/action/ability/activable/psionic_interact
+ name = "Telekinesis"
+ action_icon_state = "telekinesis"
+ action_icon = 'icons/mob/psionic_icons.dmi'
+ desc = "We manipulate things from a distance."
+ cooldown_duration = 20 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ use_state_flags = ABILITY_TARGET_SELF
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_TELEKINESIS,
+ )
+ ///Ability range
+ var/range = 9
+ ///Power of psi interactions
+ var/psi_strength = 2
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+
+/datum/action/ability/activable/psionic_interact/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ if((A.z != owner.z) || get_dist(owner, A) > range)
+ if(!silent)
+ A.balloon_alert(owner, "too far")
+ return FALSE
+ if(!line_of_sight(owner, A, range))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+
+/datum/action/ability/activable/psionic_interact/use_ability(atom/target)
+ particle_holder = new(owner, /particles/drone_enhancement)
+ particle_holder.pixel_x = 0
+ particle_holder.pixel_y = -3
+ particle_holder.particles.velocity = list(0, 1.5)
+ particle_holder.particles.gravity = list(0, 2)
+
+ if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, target, BUSY_ICON_DANGER) || !can_use_ability(target))
+ owner.balloon_alert(owner, "Our focus is disrupted")
+ QDEL_NULL(particle_holder)
+ return fail_activate()
+
+ QDEL_NULL(particle_holder)
+ playsound(owner, 'sound/effects/petrify_activate.ogg', 50)
+
+ var/list/outcome = target.psi_act(psi_strength, owner)
+ if(!outcome)
+ return fail_activate()
+
+ add_cooldown(outcome[1])
+ succeed_activate(outcome[2])
+ update_button_icon()
+
+
+/obj/machinery/door/psi_act(psi_power, mob/living/user)
+ if(density)
+ open(TRUE)
+ else
+ close(TRUE)
+ return list(0.1 SECONDS, 5)
+
+/obj/machinery/door/airlock/psi_act(psi_power, mob/living/user)
+ if(operating)
+ to_chat(user, span_warning("The airlock is already in motion."))
+ return
+ if(welded)
+ to_chat(user, span_warning("The airlock is welded shut."))
+ return
+ if(locked)
+ to_chat(user, span_warning("The airlock's bolts prevent it from being forced."))
+ return
+ if(psi_power < PSIONIC_INTERACTION_STRENGTH_STANDARD && hasPower())
+ to_chat(user, span_warning("The airlock's motors resist your efforts to force it."))
+ return
+
+ return ..()
+
+/obj/machinery/door/firedoor/psi_act(psi_power, mob/living/user)
+ if(operating)
+ to_chat(user, span_warning("The firelock is already in motion."))
+ return
+ if(blocked)
+ to_chat(user, span_warning("The firelock is welded shut."))
+ return
+
+ return ..()
+
+/obj/machinery/button/psi_act(psi_power, mob/living/user)
+ pulsed()
+ return list(0.1 SECONDS, 1)
+
+/obj/item/psi_act(psi_power, mob/living/user)
+ if(user.a_intent == INTENT_HELP)
+ throw_at(user, 4 + psi_power, psi_power, user, TRUE)
+ else
+ var/target = get_turf_in_angle(Get_Angle(user, src), src, 7)
+ throw_at(target, 4 + psi_power, psi_power, user, TRUE)
+ return list(3 SECONDS, 10)
+
+// ***************************************
+// *********** Reanimate
+// ***************************************
+
+#define SECTOID_REANIMATE_RANGE 4
+#define SECTOID_REANIMATE_CHANNEL_TIME 1.5 SECONDS
+/datum/action/ability/activable/sectoid/reanimate
+ name = "Reanimate"
+ action_icon_state = "reanimate"
+ desc = "With our psionic strength we turn the dead into our puppet, or revive a fallen ally."
+ cooldown_duration = 60 SECONDS
+ target_flags = ABILITY_MOB_TARGET
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_ABILITY_REANIMATE,
+ )
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+ ///list of
+ var/list/zombie_list = list()
+
+/datum/action/ability/activable/sectoid/reanimate/give_action(mob/living/L)
+ . = ..()
+ RegisterSignal(owner, COMSIG_MOB_DEATH, PROC_REF(kill_zombies))
+
+/datum/action/ability/activable/sectoid/reanimate/remove_action(mob/living/carbon/carbon_owner)
+ kill_zombies()
+ return ..()
+
+/datum/action/ability/activable/sectoid/reanimate/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ var/mob/living/carbon/human/human_target = A
+ if(!istype(A))
+ if(!silent)
+ human_target.balloon_alert(owner, "Invalid target")
+ return FALSE
+ if(human_target.stat != DEAD)
+ if(!silent)
+ human_target.balloon_alert(owner, "Still alive!")
+ return FALSE
+ if((human_target.z != owner.z) || get_dist(owner, human_target) > SECTOID_REANIMATE_RANGE)
+ if(!silent)
+ human_target.balloon_alert(owner, "too far")
+ return FALSE
+ if(!line_of_sight(owner, human_target, SECTOID_REANIMATE_RANGE))
+ if(!silent)
+ owner.balloon_alert(owner, "Out of sight!")
+ return FALSE
+
+/datum/action/ability/activable/sectoid/reanimate/use_ability(atom/target)
+ particle_holder = new(owner, /particles/drone_enhancement)
+ particle_holder.pixel_x = 0
+ particle_holder.pixel_y = -3
+ particle_holder.particles.velocity = list(0, 1.5)
+ particle_holder.particles.gravity = list(0, 2)
+
+ target.beam(owner, "drain_life", time = SECTOID_REANIMATE_CHANNEL_TIME, maxdistance = 10)
+ target.add_filter("psi_reanimation", 3, outline_filter(1, COLOR_STRONG_MAGENTA))
+
+ if(!do_after(owner, SECTOID_REANIMATE_CHANNEL_TIME, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, target, BUSY_ICON_DANGER) || !can_use_ability(target))
+ owner.balloon_alert(owner, "Our focus is disrupted")
+ QDEL_NULL(particle_holder)
+ return fail_activate()
+
+ var/mob/living/carbon/human/human_target = target
+ if(human_target.faction == owner.faction && !(HAS_TRAIT(human_target, TRAIT_UNDEFIBBABLE)))
+ human_target.revive_to_crit(TRUE)
+ target.remove_filter("psi_reanimation")
+ else if(ishumanbasic(human_target))
+ human_target.revive_to_crit(FALSE, FALSE)
+ human_target.set_species("Psi zombie")
+ human_target.faction = owner.faction
+ human_target.offer_mob()
+ zombie_list += human_target
+ RegisterSignal(human_target, COMSIG_MOB_DEATH, PROC_REF(remove_zombie))
+ var/obj/item/radio/headset/mainship/radio = human_target.wear_ear
+ if(istype(radio))
+ radio.safety_protocol(src)
+ else
+ owner.balloon_alert(owner, "Unrevivable")
+
+ QDEL_NULL(particle_holder)
+ playsound(owner, 'sound/effects/petrify_activate.ogg', 50)
+ add_cooldown()
+ update_button_icon()
+ succeed_activate()
+
+/datum/action/ability/activable/sectoid/reanimate/proc/remove_zombie(mob/living/carbon/human/source)
+ SIGNAL_HANDLER
+ zombie_list -= source
+
+/datum/action/ability/activable/sectoid/reanimate/proc/kill_zombies(mob/living/carbon/human/source)
+ SIGNAL_HANDLER
+ for(var/mob/living/carbon/human/zombie AS in zombie_list)
+ zombie.gib()
+ zombie_list = list()
diff --git a/code/datums/actions/weapon_actions.dm b/code/datums/actions/weapon_actions.dm
new file mode 100644
index 0000000000000..fe8e385fa0ae8
--- /dev/null
+++ b/code/datums/actions/weapon_actions.dm
@@ -0,0 +1,30 @@
+//Stamina using weapon based abilities
+/datum/action/ability/activable/weapon_skill
+ action_icon = 'icons/mob/actions.dmi'
+ ///Damage of this attack
+ var/damage
+ ///Penetration of this attack
+ var/penetration
+
+/datum/action/ability/activable/weapon_skill/New(Target, _damage, _penetration)
+ . = ..()
+ damage = _damage
+ penetration = _penetration
+
+/datum/action/ability/activable/weapon_skill/can_use_ability(atom/A, silent = FALSE, override_flags)
+ . = ..()
+ if(!.)
+ return
+ var/mob/living/carbon/carbon_owner = owner
+ if(carbon_owner.getStaminaLoss() > 0) //this specifically lets you use these abilities with no stamina, but not if you have actual stamina loss
+ if(!silent)
+ carbon_owner.balloon_alert(owner, "Catch your breath!")
+ return FALSE
+
+/datum/action/ability/activable/weapon_skill/succeed_activate(ability_cost_override)
+ if(QDELETED(owner))
+ return
+ ability_cost_override = ability_cost_override? ability_cost_override : ability_cost
+ if(ability_cost_override > 0)
+ var/mob/living/carbon/carbon_owner = owner
+ carbon_owner.adjustStaminaLoss(ability_cost_override)
diff --git a/code/datums/actions/xeno_action.dm b/code/datums/actions/xeno_action.dm
index 0b1aa86c113ba..b7d95cf0ad78c 100644
--- a/code/datums/actions/xeno_action.dm
+++ b/code/datums/actions/xeno_action.dm
@@ -25,24 +25,19 @@
var/mob/living/carbon/xenomorph/X = owner
if(!X)
return FALSE
- var/flags_to_check = use_state_flags|override_flags
+ var/to_check_flags = use_state_flags|override_flags
- if(!(flags_to_check & ABILITY_USE_FORTIFIED) && X.fortify)
+ if(!(to_check_flags & ABILITY_USE_FORTIFIED) && X.fortify)
if(!silent)
X.balloon_alert(X, "Cannot while fortified")
return FALSE
- if(!(flags_to_check & ABILITY_USE_CRESTED) && X.crest_defense)
+ if(!(to_check_flags & ABILITY_USE_CRESTED) && X.crest_defense)
if(!silent)
X.balloon_alert(X, "Cannot while in crest defense")
return FALSE
- if(!(flags_to_check & ABILITY_USE_ROOTED) && HAS_TRAIT_FROM(X, TRAIT_IMMOBILE, BOILER_ROOTED_TRAIT))
- if(!silent)
- X.balloon_alert(X, "Cannot while rooted")
- return FALSE
-
- if(!(flags_to_check & ABILITY_IGNORE_PLASMA) && X.plasma_stored < ability_cost)
+ if(!(to_check_flags & ABILITY_IGNORE_PLASMA) && X.plasma_stored < ability_cost)
if(!silent)
X.balloon_alert(X, "Need [ability_cost - X.plasma_stored] more plasma")
return FALSE
@@ -71,24 +66,19 @@
var/mob/living/carbon/xenomorph/X = owner
if(!X)
return FALSE
- var/flags_to_check = use_state_flags|override_flags
+ var/to_check_flags = use_state_flags|override_flags
- if(!(flags_to_check & ABILITY_USE_FORTIFIED) && X.fortify)
+ if(!(to_check_flags & ABILITY_USE_FORTIFIED) && X.fortify)
if(!silent)
X.balloon_alert(X, "Cannot while fortified")
return FALSE
- if(!(flags_to_check & ABILITY_USE_CRESTED) && X.crest_defense)
+ if(!(to_check_flags & ABILITY_USE_CRESTED) && X.crest_defense)
if(!silent)
X.balloon_alert(X, "Cannot while in crest defense")
return FALSE
- if(!(flags_to_check & ABILITY_USE_ROOTED) && HAS_TRAIT_FROM(X, TRAIT_IMMOBILE, BOILER_ROOTED_TRAIT))
- if(!silent)
- X.balloon_alert(X, "Cannot while rooted")
- return FALSE
-
- if(!(flags_to_check & ABILITY_IGNORE_PLASMA) && X.plasma_stored < ability_cost)
+ if(!(to_check_flags & ABILITY_IGNORE_PLASMA) && X.plasma_stored < ability_cost)
if(!silent)
X.balloon_alert(X, "Need [ability_cost - X.plasma_stored] more plasma")
return FALSE
diff --git a/code/datums/callback.dm b/code/datums/callback.dm
index ef07f58412000..af8ec8de82e76 100644
--- a/code/datums/callback.dm
+++ b/code/datums/callback.dm
@@ -231,5 +231,3 @@
else
datum.vars[var_name] = var_value
-/proc/___callbacknew(typepath, arguments)
- new typepath(arglist(arguments))
diff --git a/code/datums/chat_payload.dm b/code/datums/chat_payload.dm
new file mode 100644
index 0000000000000..fd35bbc4eecf6
--- /dev/null
+++ b/code/datums/chat_payload.dm
@@ -0,0 +1,16 @@
+/// Stores information about a chat payload
+/datum/chat_payload
+ /// Sequence number of this payload
+ var/sequence = 0
+ /// Message we are sending
+ var/list/content
+ /// Resend count
+ var/resends = 0
+
+/// Converts the chat payload into a JSON string
+/datum/chat_payload/proc/into_message()
+ return "{\"sequence\":[sequence],\"content\":[json_encode(content)]}"
+
+/// Returns an HTML-encoded message from our contents.
+/datum/chat_payload/proc/get_content_as_html()
+ return message_to_html(content)
diff --git a/code/datums/components/attachment_handler.dm b/code/datums/components/attachment_handler.dm
index f596eb821dab6..8de222f2432da 100644
--- a/code/datums/components/attachment_handler.dm
+++ b/code/datums/components/attachment_handler.dm
@@ -70,9 +70,10 @@
return
var/slot = attachment_data[SLOT]
- if(!attacher && (!(slot in slots) || !(attachment.type in attachables_allowed))) //No more black market attachment combos.
- QDEL_NULL(attachment)
- return
+ if(!CHECK_BITFIELD(attachment_data[FLAGS_ATTACH_FEATURES], ATTACH_BYPASS_ALLOWED_LIST))
+ if(!attacher && (!(slot in slots) || !(attachment.type in attachables_allowed))) //No more black market attachment combos.
+ QDEL_NULL(attachment)
+ return
var/obj/item/old_attachment = slots[slot]
@@ -103,11 +104,10 @@
var/obj/parent_obj = parent
///The gun has another gun attached to it
- if(isgun(attachment) && isgun(parent) )
+ if(isgun(attachment) && isgun(parent))
parent_obj:gunattachment = attachment
on_attach?.Invoke(attachment, attacker)
-
if(attachment_data[ON_ATTACH])
var/datum/callback/attachment_on_attach = CALLBACK(attachment, attachment_data[ON_ATTACH])
attachment_on_attach.Invoke(parent, attacker)
@@ -290,7 +290,7 @@
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(handle_attachment), attachment, null, TRUE)
-///This updates the overlays of the parent and apllies the right ones.
+///This updates the overlays of the parent and applies the right ones.
/datum/component/attachment_handler/proc/update_parent_overlay(datum/source)
SIGNAL_HANDLER
var/obj/item/parent_item = parent
@@ -307,10 +307,7 @@
var/icon = attachment_data[OVERLAY_ICON]
var/icon_state = attachment.icon_state
- if(attachment.greyscale_colors && attachment.greyscale_config)
- icon = attachment.icon
- icon_state = attachment.icon_state + "_a"
- else if(attachment_data[OVERLAY_ICON] == attachment.icon)
+ if(attachment_data[OVERLAY_ICON] == attachment.icon)
icon_state = attachment.icon_state + "_a"
if(CHECK_BITFIELD(attachment_data[FLAGS_ATTACH_FEATURES], ATTACH_SAME_ICON) || CHECK_BITFIELD(attachment_data[FLAGS_ATTACH_FEATURES], ATTACH_DIFFERENT_MOB_ICON_STATE))
icon_state = attachment.icon_state
diff --git a/code/datums/components/autofire.dm b/code/datums/components/autofire.dm
index 527f1838bf03d..b06b8f85fb301 100644
--- a/code/datums/components/autofire.dm
+++ b/code/datums/components/autofire.dm
@@ -32,8 +32,8 @@
RegisterSignal(parent, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, PROC_REF(modify_burst_shots_to_fire))
RegisterSignal(parent, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_burstfire_shot_delay))
RegisterSignal(parent, COMSIG_GUN_AUTO_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_autoburstfire_shot_delay))
- RegisterSignals(parent, list(COMSIG_GUN_FIRE, COMSIG_XENO_FIRE, COMSIG_MECH_FIRE), PROC_REF(initiate_shot))
- RegisterSignals(parent, list(COMSIG_GUN_STOP_FIRE, COMSIG_XENO_STOP_FIRE, COMSIG_MECH_STOP_FIRE), PROC_REF(stop_firing))
+ RegisterSignals(parent, list(COMSIG_GUN_FIRE, COMSIG_XENO_FIRE, COMSIG_MECH_FIRE, COMSIG_ARMORED_FIRE), PROC_REF(initiate_shot))
+ RegisterSignals(parent, list(COMSIG_GUN_STOP_FIRE, COMSIG_XENO_STOP_FIRE, COMSIG_MECH_STOP_FIRE, COMSIG_ARMORED_STOP_FIRE), PROC_REF(stop_firing))
auto_fire_shot_delay = _auto_fire_shot_delay
burstfire_shot_delay = _burstfire_shot_delay
diff --git a/code/datums/components/beacon.dm b/code/datums/components/beacon.dm
new file mode 100644
index 0000000000000..6727bbf9d14a4
--- /dev/null
+++ b/code/datums/components/beacon.dm
@@ -0,0 +1,225 @@
+///This component is used to give stuff beacon functionality.
+/datum/component/beacon
+ ///Is the beacon active?
+ var/active = FALSE
+ ///The reference to the beacon datum
+ var/datum/supply_beacon/beacon_datum
+ ///The camera attached to the beacon
+ var/obj/machinery/camera/beacon_cam
+ ///Should the parent anchor on activation?
+ var/anchor = FALSE
+ ///How long it takes for this item to activate it's signal/deploy
+ var/anchor_time = 0
+ ///The icon state when this beacon is active
+ var/active_icon_state = ""
+ ///The mob who activated this beacon
+ var/mob/activator
+
+/datum/component/beacon/Initialize(_anchor = FALSE, _anchor_time = 0, _active_icon_state = "")
+ . = ..()
+ if(_anchor && !_anchor_time || !_anchor && _anchor_time)
+ stack_trace("The beacon component has been added to [parent.type] and is missing either the anchor var or the time to anchor")
+ return COMPONENT_INCOMPATIBLE
+ if(!ismovableatom(parent)) //if some goober admin tries to add it to a turf or something
+ return COMPONENT_INCOMPATIBLE
+ anchor = _anchor
+ anchor_time = _anchor_time
+ active_icon_state = _active_icon_state
+
+/datum/component/beacon/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self))
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_NAME, PROC_REF(on_update_name))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand))
+ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON_STATE, PROC_REF(on_update_icon_state))
+ RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_change))
+
+/datum/component/beacon/UnregisterFromParent()
+ UnregisterSignal(parent, list(
+ COMSIG_ITEM_ATTACK_SELF,
+ COMSIG_ATOM_UPDATE_NAME,
+ COMSIG_ATOM_ATTACK_HAND,
+ COMSIG_ATOM_EXAMINE,
+ COMSIG_ATOM_UPDATE_ICON_STATE,
+ COMSIG_MOVABLE_Z_CHANGED,
+ ))
+ QDEL_NULL(beacon_datum)
+ QDEL_NULL(beacon_cam)
+ activator = null
+
+///Toggles the active state of the beacon
+/datum/component/beacon/proc/toggle_activation(atom/movable/source, mob/user)
+ active = !active
+
+ if(active)
+ INVOKE_ASYNC(src, PROC_REF(activate), source, user)
+ else
+ INVOKE_ASYNC(src, PROC_REF(deactivate), source, user)
+
+///The proc that gets called when the user uses the item in their hand
+/datum/component/beacon/proc/on_attack_self(atom/movable/source, mob/user)
+ SIGNAL_HANDLER
+
+ if(!ishuman(user))
+ return
+
+ if(length(user.do_actions))
+ user.balloon_alert(user, "Busy!")
+ return
+
+ INVOKE_ASYNC(src, PROC_REF(toggle_activation), source, user)
+
+///This will only get called when you want to deactivate a beacon, ie clicking a deployed beacon
+/datum/component/beacon/proc/on_attack_hand(atom/movable/source, mob/user)
+ if(!source.anchored || !ishuman(user))
+ return
+
+ if(length(user.do_actions))
+ user.balloon_alert(user, "Busy!")
+ return
+
+ INVOKE_ASYNC(src, PROC_REF(deactivate), source, user)
+
+///Activates the beacon
+/datum/component/beacon/proc/activate(atom/movable/source, mob/user)
+ var/turf/location = get_turf(source)
+ var/area/A = get_area(location)
+ if(A && istype(A) && A.ceiling >= CEILING_DEEP_UNDERGROUND)
+ to_chat(user, span_warning("This won't work if you're standing deep underground."))
+ active = FALSE
+ return FALSE
+
+ if(istype(A, /area/shuttle/dropship))
+ to_chat(user, span_warning("You have to be outside the dropship to use this or it won't transmit."))
+ active = FALSE
+ return FALSE
+
+ if(length(user.do_actions))
+ user.balloon_alert(user, "Busy!")
+ active = FALSE
+ return
+
+ if(anchor && anchor_time)
+ var/delay = max(1.5 SECONDS, anchor_time - 2 SECONDS * user.skills.getRating(SKILL_LEADERSHIP))
+ user.visible_message(span_notice("[user] starts setting up [source] on the ground."),
+ span_notice("You start setting up [source] on the ground and inputting all the data it needs."))
+ if(!do_after(user, delay, NONE, source))
+ user.balloon_alert(user, "Keep still!")
+ active = FALSE
+ return
+
+ activator = user
+
+ if(anchor) //Only anchored beacons have cameras and lights
+ var/obj/machinery/camera/beacon_cam/BC = new(source, "[user.get_paygrade()] [user.name] [source]")
+ user.dropItemToGround(source)
+ beacon_cam = BC
+ source.anchored = TRUE
+ source.layer = ABOVE_OBJ_LAYER
+ source.set_light(2, 1)
+ var/marker_flags = GLOB.faction_to_minimap_flag[user.faction]
+ if(!marker_flags)
+ marker_flags = MINIMAP_FLAG_MARINE
+ SSminimaps.add_marker(source, marker_flags, image('icons/UI_icons/map_blips.dmi', null, "supply", ABOVE_FLOAT_LAYER))
+
+ message_admins("[ADMIN_TPMONTY(user)] set up a supply beacon.") //do something with this
+ playsound(source, 'sound/machines/twobeep.ogg', 15, 1)
+ user.visible_message("[user] activates [source]'s signal.")
+ user.show_message(span_notice("The [source] beeps and states, \"Your current coordinates were registered by the supply console. LONGITUDE [location.x]. LATITUDE [location.y]. Area ID: [get_area(source)]\""), EMOTE_AUDIBLE, span_notice("The [source] vibrates but you can not hear it!"))
+ beacon_datum = new /datum/supply_beacon("[user.name] + [A]", get_turf(source), user.faction)
+ RegisterSignal(beacon_datum, COMSIG_QDELETING, PROC_REF(clean_beacon_datum))
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SUPPLY_BEACON_CREATED, src)
+ source.update_appearance()
+
+///Deactivates the beacon
+/datum/component/beacon/proc/deactivate(atom/movable/source, mob/user)
+ if(length(user?.do_actions))
+ user.balloon_alert(user, "Busy!")
+ active = TRUE
+ return
+ if(source.anchored)
+ if(user)
+ var/delay = max(1 SECONDS, anchor_time * 0.5 - 2 SECONDS * user.skills.getRating(SKILL_LEADERSHIP)) //Half as long as setting it up.
+ user.visible_message(span_notice("[user] starts removing [source] from the ground."),
+ span_notice("You start removing [source] from the ground, deactivating it."))
+ if(!do_after(user, delay, NONE, source, BUSY_ICON_GENERIC))
+ user.balloon_alert(user, "Keep still!")
+ active = TRUE
+ return
+ user.put_in_active_hand(source)
+ user.show_message(span_warning("The [source] beeps and states, \"Your last position is no longer accessible by the supply console"), EMOTE_AUDIBLE, span_notice("The [source] vibrates but you can not hear it!"))
+ source.anchored = FALSE
+ source.layer = initial(source.layer)
+ source.set_light(0)
+ SSminimaps.remove_marker(source)
+
+ source.visible_message(span_warning("[source] stops emitting a signal."))
+ QDEL_NULL(beacon_cam)
+ QDEL_NULL(beacon_datum)
+ activator = null
+ playsound(source, 'sound/machines/twobeep.ogg', 15, 1)
+ active = FALSE //this is here because of attack hand
+ source.update_appearance()
+
+///Adds an extra line of instructions to the examine
+/datum/component/beacon/proc/on_examine(atom/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+ examine_list += span_notice("Activate in hand to create a supply beacon signal.")
+
+///If the signal source dies, the beacon datum should as well
+/datum/component/beacon/proc/clean_beacon_datum()
+ SIGNAL_HANDLER
+ beacon_datum = null
+
+///Gives the beacon broadcaster object the appropriate, descriptive name
+/datum/component/beacon/proc/on_update_name(atom/source, updates)
+ SIGNAL_HANDLER
+ if(active)
+ source.name += " - [get_area(source)] - [activator]"
+ return
+ source.name = initial(source.name)
+
+///Updates the icon state of the object to an active state, if it has one
+/datum/component/beacon/proc/on_update_icon_state(atom/source, updates)
+ SIGNAL_HANDLER
+ if(active)
+ source.icon = icon(source.icon, active_icon_state)
+ else
+ source.icon = initial(source.icon)
+
+///What happens when we change Z level
+/datum/component/beacon/proc/on_z_change(atom/source, old_z, new_z)
+ SIGNAL_HANDLER
+ if(active)
+ beacon_datum.drop_location = get_turf(source)
+ return
+
+/datum/component/beacon/ai_droid/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_UNMANNED_COORDINATES, PROC_REF(toggle_activation))
+
+/datum/component/beacon/ai_droid/on_attack_hand(atom/movable/source, mob/user)
+ return //dont want marines disabling ai droid by clicking it even if it would be funny
+
+/datum/component/beacon/ai_droid/on_examine(atom/source, mob/user, list/examine_list)
+ return //we can't attack this in hand
+
+/datum/supply_beacon
+ /// Name printed on the supply console
+ var/name = ""
+ /// Where the supply drops will land
+ var/turf/drop_location
+ /// The faction of the beacon
+ var/faction = ""
+
+/datum/supply_beacon/New(_name, turf/_drop_location, _faction, life_time = 0 SECONDS)
+ name = _name
+ drop_location = _drop_location
+ faction = _faction
+ GLOB.supply_beacon[name] = src
+ if(life_time)
+ QDEL_IN(src, life_time)
+
+/// Remove that beacon from the list of glob supply beacon
+/datum/supply_beacon/Destroy()
+ GLOB.supply_beacon -= name
+ return ..()
diff --git a/code/datums/components/bump_attack.dm b/code/datums/components/bump_attack.dm
index 94fef2e61306c..22516335193f4 100644
--- a/code/datums/components/bump_attack.dm
+++ b/code/datums/components/bump_attack.dm
@@ -48,7 +48,7 @@
return
var/obj/item/held_item = bumper.get_inactive_held_item()
- if(held_item?.flags_item & CAN_BUMP_ATTACK)
+ if(held_item?.item_flags & CAN_BUMP_ATTACK)
return
active = FALSE
UnregisterSignal(bumper, COMSIG_MOVABLE_BUMP)
@@ -58,7 +58,7 @@
if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_BUMP_ATTACK))
return NONE
var/mob/living/bumper = parent
- if(!(target.flags_atom & BUMP_ATTACKABLE) || bumper.throwing || bumper.incapacitated() || HAS_TRAIT(target, TRAIT_TURRET_HIDDEN)) //RU TGMC EDIT
+ if(!(target.atom_flags & BUMP_ATTACKABLE) || bumper.throwing || bumper.incapacitated() || HAS_TRAIT(target, TRAIT_TURRET_HIDDEN)) //RU TGMC EDIT
return NONE
///Handles carbon bump action checks before actually doing the attack checks.
@@ -123,7 +123,7 @@
var/obj/item/held_item = bumper.get_active_held_item()
if(!held_item)
bumper.UnarmedAttack(target, TRUE)
- else if(held_item.flags_item & CAN_BUMP_ATTACK)
+ else if(held_item.item_flags & CAN_BUMP_ATTACK)
held_item.melee_attack_chain(bumper, target)
else //disables pushing if you have bump attacks on, so you don't accidentally misplace your enemy when switching to an item that can't bump attack
return COMPONENT_BUMP_RESOLVED
diff --git a/code/datums/components/chem_booster.dm b/code/datums/components/chem_booster.dm
index 47f494c6c7cbc..268e6fef0cb42 100644
--- a/code/datums/components/chem_booster.dm
+++ b/code/datums/components/chem_booster.dm
@@ -145,7 +145,7 @@
///Adds additional text for the component when examining the item it is attached to
/datum/component/chem_booster/proc/examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
- examine_text += span_notice("The chemical system currently holds [resource_storage_current]u of green blood. Its' enhancement level is set to [boost_amount].")
+ examine_text += span_notice("The chemical system currently holds [resource_storage_current]u of green blood. Its enhancement level is set to [boost_amount].")
examine_text += get_meds_beaker_contents()
///Disables active functions and cleans up actions when the suit is unequipped
diff --git a/code/datums/components/deployable_item.dm b/code/datums/components/deployable_item.dm
index b811cc176ef6b..f3704670019b8 100644
--- a/code/datums/components/deployable_item.dm
+++ b/code/datums/components/deployable_item.dm
@@ -6,16 +6,19 @@
var/undeploy_time = 0
///Typepath that the item deploys into. Can be anything but an item so far. The preffered type is /obj/machinery/deployable since it was built for this.
var/obj/deploy_type
+ ///Any extra checks required when trying to deploy this item
+ var/datum/callback/deploy_check_callback
-/datum/component/deployable_item/Initialize(_deploy_type, _deploy_time, _undeploy_time)
+/datum/component/deployable_item/Initialize(_deploy_type, _deploy_time, _undeploy_time, _deploy_check_callback)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
deploy_type = _deploy_type
deploy_time = _deploy_time
undeploy_time = _undeploy_time
+ deploy_check_callback = _deploy_check_callback
var/obj/item/attached_item = parent
- if(CHECK_BITFIELD(attached_item.flags_item, DEPLOY_ON_INITIALIZE))
+ if(CHECK_BITFIELD(attached_item.item_flags, DEPLOY_ON_INITIALIZE))
finish_deploy(attached_item, null, attached_item.loc, attached_item.dir)
/datum/component/deployable_item/RegisterWithParent()
@@ -52,6 +55,8 @@
var/list/modifiers = params2list(params)
if(!modifiers["ctrl"] || modifiers["right"] || get_turf(user) == location || !(user.Adjacent(object)) || !location)
return
+ if(deploy_check_callback && !deploy_check_callback.Invoke(user, location))
+ return
INVOKE_ASYNC(src, PROC_REF(finish_deploy), parent, user, location)
return COMSIG_KB_ACTIVATED
@@ -69,11 +74,11 @@
location.balloon_alert(user, "No room to deploy")
return
var/newdir = get_dir(user, location)
- if(deploy_type.flags_atom & ON_BORDER)
+ if(deploy_type.atom_flags & ON_BORDER)
for(var/obj/object in location)
if(!object.density)
continue
- if(!(object.flags_atom & ON_BORDER))
+ if(!(object.atom_flags & ON_BORDER))
continue
if(object.dir != newdir)
continue
@@ -110,7 +115,7 @@
if(item_to_deploy?.reagents?.total_volume)
item_to_deploy.reagents.trans_to(deployed_machine, item_to_deploy.reagents.total_volume)
- deployed_machine.update_icon_state()
+ deployed_machine.update_appearance()
if(user)
item_to_deploy.balloon_alert(user, "Deployed!")
@@ -167,4 +172,4 @@
deployed_machine.clear_internal_item()
QDEL_NULL(deployed_machine)
- undeployed_item.update_icon_state()
+ undeployed_item.update_appearance()
diff --git a/code/datums/components/harvester.dm b/code/datums/components/harvester.dm
index a84138caa4f02..f16d95c5fea71 100644
--- a/code/datums/components/harvester.dm
+++ b/code/datums/components/harvester.dm
@@ -75,19 +75,17 @@
///Adds additional text for the component when examining the item
/datum/component/harvester/proc/examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
- var/output = ""
if(length(loaded_reagents))
- output += "It currently holds: "
+ examine_list += "It currently holds: "
for(var/datum/reagent/reagent_type AS in loaded_reagents)
- output += "[initial(reagent_type.name)] - [loaded_reagents[reagent_type]]\n"
+ examine_list += "[initial(reagent_type.name)] - [loaded_reagents[reagent_type]]\n"
else
- output += "The internal storage is empty\n"
+ examine_list += "The internal storage is empty"
- output += "Compatible chemicals:\n"
+ examine_list += "Compatible chemicals:"
for(var/datum/reagent/reagent AS in loadable_reagents)
- output += "[initial(reagent.name)]\n"
+ examine_list += "[initial(reagent.name)]\n"
- to_chat(user, output)
///Adds mechanics info to the weapon
/datum/component/harvester/proc/get_mechanics_info(datum/source, list/mechanics_text)
@@ -120,7 +118,7 @@
user.balloon_alert(user, "incompatible reagent, check description")
return
- if(loaded_reagents[reagent_to_load] > max_loadable_reagent_amount)
+ if(loaded_reagents[reagent_to_load] >= max_loadable_reagent_amount)
user.balloon_alert(user, "full")
return
@@ -259,6 +257,18 @@
user.heal_overall_damage(5, 0, updating_health = TRUE)
return
+ if(target.stat == DEAD)
+ to_chat(user, span_rose("[target] is already dead."))
+ return
+
+ if(!ishuman(target))
+ return
+ var/mob/living/carbon/carbon_target = target
+
+ if((carbon_target.species.species_flags & NO_CHEM_METABOLIZATION))
+ to_chat(user, span_rose("[target] Cannot process chemicals."))
+ return
+
to_chat(user, span_rose("You prepare to stab [target != user ? "[target]" : "yourself"]!"))
new /obj/effect/temp_visual/telekinesis(get_turf(target))
diff --git a/code/datums/components/jump.dm b/code/datums/components/jump.dm
index 7fa5d0c983c6b..2aa1676f14483 100644
--- a/code/datums/components/jump.dm
+++ b/code/datums/components/jump.dm
@@ -37,7 +37,7 @@
set_vars(_jump_duration, _jump_cooldown, _stamina_cost, _jump_height, _jump_sound, _jump_flags, _jumper_allow_pass_flags)
///Actually sets the jump vars
-/datum/component/jump/proc/set_vars(_jump_duration = 0.5 SECONDS, _jump_cooldown = 1 SECONDS, _stamina_cost = 8, _jump_height = 16, _jump_sound = null, _jump_flags = JUMP_SHADOW, _jumper_allow_pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE)
+/datum/component/jump/proc/set_vars(_jump_duration = 0.5 SECONDS, _jump_cooldown = 1 SECONDS, _stamina_cost = 8, _jump_height = 16, _jump_sound = null, _jump_flags = JUMP_SHADOW, _jumper_allow_pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK)
jump_duration = _jump_duration
jump_cooldown = _jump_cooldown
stamina_cost = _stamina_cost
@@ -63,7 +63,8 @@
if(jump_sound)
playsound(jumper, jump_sound, 65)
- jumper.layer = ABOVE_MOB_LAYER
+ var/original_layer = jumper.layer
+ var/original_pass_flags = jumper.pass_flags
SEND_SIGNAL(jumper, COMSIG_ELEMENT_JUMP_STARTED)
jumper.adjustStaminaLoss(stamina_cost)
@@ -78,22 +79,21 @@
var/spin_number = ROUND_UP(jump_duration * 0.1)
jumper.animation_spin(jump_duration / spin_number, spin_number, jumper.dir == WEST ? FALSE : TRUE)
- animate(jumper, pixel_y = jumper.pixel_y + jump_height, layer = ABOVE_MOB_LAYER, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
- animate(pixel_y = jumper.pixel_y - jump_height, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_IN)
+ animate(jumper, pixel_y = jumper.pixel_y + jump_height, layer = MOB_JUMP_LAYER, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
+ animate(pixel_y = jumper.pixel_y - jump_height, layer = original_layer, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_IN)
if(jump_flags & JUMP_SHADOW)
animate(shadow_filter, y = -jump_height, size = 4, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
animate(y = 0, size = 0.9, time = jump_duration / 2, easing = CIRCULAR_EASING|EASE_IN)
- addtimer(CALLBACK(src, PROC_REF(end_jump), jumper), jump_duration)
+ addtimer(CALLBACK(src, PROC_REF(end_jump), jumper, original_pass_flags), jump_duration)
TIMER_COOLDOWN_START(jumper, JUMP_COMPONENT_COOLDOWN, jump_cooldown)
///Ends the jump
-/datum/component/jump/proc/end_jump(mob/living/jumper)
+/datum/component/jump/proc/end_jump(mob/living/jumper, original_pass_flags)
jumper.remove_filter(JUMP_COMPONENT)
- jumper.layer = initial(jumper.layer)
- jumper.pass_flags = initial(jumper.pass_flags)
+ jumper.pass_flags = original_pass_flags
REMOVE_TRAIT(jumper, TRAIT_SILENT_FOOTSTEPS, JUMP_COMPONENT)
SEND_SIGNAL(jumper, COMSIG_ELEMENT_JUMP_ENDED, TRUE, 1.5, 2)
SEND_SIGNAL(jumper.loc, COMSIG_TURF_JUMP_ENDED_HERE, jumper)
diff --git a/code/datums/components/largeobjecttransparency.dm b/code/datums/components/largeobjecttransparency.dm
index df0588b560a13..2162923f537fd 100644
--- a/code/datums/components/largeobjecttransparency.dm
+++ b/code/datums/components/largeobjecttransparency.dm
@@ -59,7 +59,7 @@
RegisterSignal(regist_tu, COMSIG_TURF_CHANGE, PROC_REF(OnTurfChange))
for(var/thing in regist_tu)
var/atom/check_atom = thing
- if(!(check_atom.flags_atom & CRITICAL_ATOM))
+ if(!(check_atom.atom_flags & CRITICAL_ATOM))
continue
amounthidden++
if(amounthidden)
@@ -84,7 +84,7 @@
/datum/component/largetransparency/proc/objectEnter(datum/source, atom/enterer)
SIGNAL_HANDLER
- if(!(enterer.flags_atom & CRITICAL_ATOM))
+ if(!(enterer.atom_flags & CRITICAL_ATOM))
return
if(!amounthidden)
reduceAlpha()
@@ -92,7 +92,7 @@
/datum/component/largetransparency/proc/objectLeave(datum/source, atom/leaver, direction)
SIGNAL_HANDLER
- if(!(leaver.flags_atom & CRITICAL_ATOM))
+ if(!(leaver.atom_flags & CRITICAL_ATOM))
return
amounthidden = max(0, amounthidden - 1)
if(!amounthidden)
diff --git a/code/datums/components/mounted_gun.dm b/code/datums/components/mounted_gun.dm
new file mode 100644
index 0000000000000..4b9f222143e37
--- /dev/null
+++ b/code/datums/components/mounted_gun.dm
@@ -0,0 +1,89 @@
+///This component allows gun mounting on vehicle types
+/datum/component/vehicle_mounted_weapon
+ ///The gun mounted on a vehicle
+ var/obj/item/weapon/gun/mounted_gun
+
+/datum/component/vehicle_mounted_weapon/Initialize(gun_type)
+ . = ..()
+ if(!istype(parent, /obj/vehicle))
+ return COMPONENT_INCOMPATIBLE
+ if(!(gun_type in subtypesof(/obj/item/weapon/gun)))
+ return COMPONENT_INCOMPATIBLE
+ mounted_gun = new gun_type(parent)
+ //NODROP so that you can't just drop the gun or have someone take it off your hands
+ ADD_TRAIT(mounted_gun, TRAIT_NODROP, MOUNTED_TRAIT)
+
+/datum/component/vehicle_mounted_weapon/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, PROC_REF(on_buckle))
+ RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, PROC_REF(on_unbuckle))
+ RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, PROC_REF(on_mousedrop))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand))
+ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(mounted_gun, COMSIG_ITEM_DROPPED, PROC_REF(on_weapon_drop))
+
+/datum/component/vehicle_mounted_weapon/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_MOVABLE_BUCKLE,
+ COMSIG_MOVABLE_UNBUCKLE,
+ COMSIG_MOUSEDROP_ONTO,
+ COMSIG_ATOM_ATTACKBY,
+ COMSIG_ATOM_EXAMINE,
+ COMSIG_ATOM_ATTACK_HAND,
+ ))
+ QDEL_NULL(mounted_gun)
+ return ..()
+
+///Behaviour on buckle. Puts the gun in the buckled mob's hands.
+/datum/component/vehicle_mounted_weapon/proc/on_buckle(datum/source, mob/living/buckling_mob, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0, silent)
+ SIGNAL_HANDLER
+ var/obj/vehicle/parent_vehicle = source
+ if(!parent_vehicle.is_equipment_controller(buckling_mob))
+ return
+ if(!buckling_mob.put_in_active_hand(mounted_gun) && !buckling_mob.put_in_inactive_hand(mounted_gun))
+ to_chat(buckling_mob, span_warning("Could not equip weapon! Click [parent] with a free hand to equip."))
+ return
+
+///Behaviour on unbuckle. Force drops the gun from the unbuckled mob's hands.
+/datum/component/vehicle_mounted_weapon/proc/on_unbuckle(datum/source, mob/living/unbuckled_mob, force = FALSE)
+ SIGNAL_HANDLER
+ unbuckled_mob.dropItemToGround(mounted_gun, TRUE)
+
+///Behaviour on mouse drop. If the user has clickdragged the chair to themselves they will unload it.
+/datum/component/vehicle_mounted_weapon/proc/on_mousedrop(datum/source, atom/over, mob/user)
+ SIGNAL_HANDLER
+ if(!isliving(user) || over != usr || !in_range(source, user))
+ return
+
+ mounted_gun.unload(user)
+
+///Behaviour on attackby. When a user clicks the wheelchair with an ammo magazine they reload the mounted weapon.
+/datum/component/vehicle_mounted_weapon/proc/on_attackby(datum/source, obj/item/I, mob/user, params)
+ SIGNAL_HANDLER
+ if(isammomagazine(I))
+ INVOKE_ASYNC(mounted_gun, TYPE_PROC_REF(/obj/item/weapon/gun, reload), I, user)
+ return COMPONENT_NO_AFTERATTACK
+
+///Behaviour on attack hand. Puts the gun in the user's hands if they're riding the vehicle and don't have the gun in their hands.
+/datum/component/vehicle_mounted_weapon/proc/on_attack_hand(datum/source, mob/user)
+ SIGNAL_HANDLER
+ var/obj/vehicle/parent_vehicle = source
+ if(parent_vehicle.is_equipment_controller(user) && !user.is_holding(mounted_gun))
+ user.put_in_active_hand(mounted_gun)
+ return COMPONENT_NO_ATTACK_HAND
+
+///Adds stuff to the examine of the vehicle.
+/datum/component/vehicle_mounted_weapon/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+ examine_list += span_warning("It has a [mounted_gun.name] attached.")
+ if(mounted_gun.rounds)
+ examine_list += span_notice("Ammo: [span_bold("[mounted_gun.rounds]/[mounted_gun.max_rounds]")]")
+ examine_list += span_notice("Drag to yourself to unload the mounted weapon.")
+ else
+ examine_list += span_notice("Reload it by clicking it with the appropriate ammo type.")
+
+///Handles the weapon being dropped. The only way this should happen is if they unbuckle, and this makes sure they can't just take the gun and run off with it.
+/datum/component/vehicle_mounted_weapon/proc/on_weapon_drop(obj/item/dropped, mob/user)
+ SIGNAL_HANDLER
+ var/obj/vehicle/vehicle_parent = parent
+ vehicle_parent.visible_message(span_warning("[dropped] violently snaps back into it's place in [parent]!"))
+ dropped.forceMove(vehicle_parent)
diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm
index 61088ed923e4c..a58608457bace 100644
--- a/code/datums/components/riding/riding.dm
+++ b/code/datums/components/riding/riding.dm
@@ -207,6 +207,10 @@
SIGNAL_HANDLER
return
+/// Calculates the additional delay to moving
+/datum/component/riding/proc/calculate_additional_delay(mob/living/user)
+ return 0
+
/// So we can check all occupants when we bump a door to see if anyone has access
/datum/component/riding/proc/vehicle_bump(atom/movable/movable_parent, obj/machinery/door/possible_bumped_door)
SIGNAL_HANDLER
diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm
index cbb18cee8b10f..2bd83685b786a 100644
--- a/code/datums/components/riding/riding_vehicle.dm
+++ b/code/datums/components/riding/riding_vehicle.dm
@@ -56,7 +56,7 @@
handle_ride(user, direction)
/// This handles the actual movement for vehicles once [/datum/component/riding/vehicle/proc/driver_move] has given us the green light
-/datum/component/riding/vehicle/proc/handle_ride(mob/user, direction)
+/datum/component/riding/vehicle/proc/handle_ride(mob/living/user, direction)
var/atom/movable/movable_parent = parent
var/turf/next = get_step(movable_parent, direction)
@@ -71,7 +71,7 @@
step(movable_parent, direction)
last_move_diagonal = ((direction & (direction - 1)) && (movable_parent.loc == next))
- COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal? 2 : 1) * vehicle_move_delay)
+ COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal ? 2 : 1) * vehicle_move_delay + calculate_additional_delay(user))
if(QDELETED(src))
return
@@ -113,9 +113,47 @@
set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list(0, 4)))
/datum/component/riding/vehicle/wheelchair
- vehicle_move_delay = 0
+ vehicle_move_delay = 6
ride_check_flags = RIDER_NEEDS_ARMS
+/datum/component/riding/vehicle/wheelchair/driver_move(atom/movable/movable_parent, mob/living/user, direction)
+ if(!iscarbon(user))
+ return COMPONENT_DRIVER_BLOCK_MOVE
+ var/mob/living/carbon/carbon_user = user
+
+ var/datum/limb/left_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_R_HAND)
+ var/datum/limb/right_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_L_HAND)
+ var/working_hands = 2
+
+ if(!left_hand?.is_usable() || user.get_item_for_held_index(1))
+ working_hands--
+ if(!right_hand?.is_usable() || user.get_item_for_held_index(2))
+ working_hands--
+ if(!working_hands)
+ to_chat(user, span_warning("You have no arms to propel [movable_parent]!"))
+ return COMPONENT_DRIVER_BLOCK_MOVE // No hands to drive your chair? Tough luck!
+ return ..()
+
+/datum/component/riding/vehicle/wheelchair/calculate_additional_delay(mob/living/user)
+ if(!iscarbon(user))
+ return 0
+ var/mob/living/carbon/carbon_user = user
+
+ var/datum/limb/left_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_R_HAND)
+ var/datum/limb/right_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_L_HAND)
+ var/delay_to_add = 0
+
+ if(!left_hand?.is_usable() || user.get_item_for_held_index(1))
+ delay_to_add += vehicle_move_delay * 0.5 //harder to move a wheelchair with a single hand
+ else if(left_hand?.is_broken())
+ delay_to_add = vehicle_move_delay * 0.33
+ if(!right_hand?.is_usable() || user.get_item_for_held_index(2))
+ delay_to_add += vehicle_move_delay * 0.5
+ else if(right_hand.is_broken())
+ delay_to_add = vehicle_move_delay * 0.33
+
+ return delay_to_add
+
/datum/component/riding/vehicle/wheelchair/handle_specials()
. = ..()
set_vehicle_dir_layer(SOUTH, OBJ_LAYER)
@@ -123,6 +161,9 @@
set_vehicle_dir_layer(EAST, OBJ_LAYER)
set_vehicle_dir_layer(WEST, OBJ_LAYER)
+/datum/component/riding/vehicle/wheelchair/weaponized
+ vehicle_move_delay = 5
+
/datum/component/riding/vehicle/motorbike
vehicle_move_delay = 2
ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER
diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm
index aab7b2e185946..c3ae9147caa88 100644
--- a/code/datums/components/rotation.dm
+++ b/code/datums/components/rotation.dm
@@ -106,10 +106,10 @@
return ..()
-/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user)
+/datum/component/simple_rotation/proc/ExamineMessage(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
if(rotation_flags & ROTATION_ALTCLICK)
- . += span_notice("Alt-click to rotate it clockwise.")
+ examine_list += span_notice("Alt-click to rotate it clockwise.")
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
diff --git a/code/datums/components/seethrough_mob.dm b/code/datums/components/seethrough_mob.dm
new file mode 100644
index 0000000000000..ab040fe95874e
--- /dev/null
+++ b/code/datums/components/seethrough_mob.dm
@@ -0,0 +1,133 @@
+///A component that lets you turn your character transparent in order to see and click through yourself.
+/datum/component/seethrough_mob
+ ///The atom that enables our dark magic
+ var/atom/movable/render_source_atom
+ ///The fake version of ourselves
+ var/image/trickery_image
+ ///Which alpha do we animate towards?
+ var/target_alpha
+ ///How long our faze in/out takes
+ var/animation_time
+ ///Does this object let clicks from players its transparent to pass through it
+ var/clickthrough
+ ///Is the seethrough effect currently active
+ var/is_active
+ ///The mob's original render_target value
+ var/initial_render_target_value
+ ///This component's personal uid
+ var/personal_uid
+
+/datum/component/seethrough_mob/Initialize(target_alpha = 100, animation_time = 0.5 SECONDS, clickthrough = TRUE)
+ . = ..()
+
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.target_alpha = target_alpha
+ src.animation_time = animation_time
+ src.clickthrough = clickthrough
+ src.is_active = FALSE
+ src.render_source_atom = new()
+
+ var/static/uid = 0
+ uid++
+ src.personal_uid = uid
+
+ render_source_atom.appearance_flags |= ( RESET_COLOR | RESET_TRANSFORM | KEEP_APART)
+
+ render_source_atom.vis_flags |= (VIS_INHERIT_ID | VIS_INHERIT_PLANE | VIS_INHERIT_LAYER)
+
+ render_source_atom.render_source = "*transparent_bigmob[personal_uid]"
+
+ var/datum/action/ability/xeno_action/toggle_seethrough/action = new(src)
+ action.give_action(parent)
+
+/datum/component/seethrough_mob/Destroy(force)
+ QDEL_NULL(render_source_atom)
+ return ..()
+
+///Set up everything we need to trick the client and keep it looking normal for everyone else
+/datum/component/seethrough_mob/proc/trick_mob()
+ SIGNAL_HANDLER
+
+ var/mob/fool = parent
+ var/icon/current_mob_icon = icon(fool.icon, fool.icon_state)
+ render_source_atom.pixel_x = -fool.pixel_x
+ render_source_atom.pixel_y = ((current_mob_icon.Height() - 32) * 0.5)
+ render_source_atom.name = "seethrough" //So our name is not just "movable" when looking at VVs
+
+ initial_render_target_value = fool.render_target
+ fool.render_target = "*transparent_bigmob[personal_uid]"
+ fool.vis_contents.Add(render_source_atom)
+
+ trickery_image = new(render_source_atom)
+ trickery_image.loc = render_source_atom
+ trickery_image.override = TRUE
+
+ trickery_image.pixel_x = 0
+ trickery_image.pixel_y = 0
+
+ if(clickthrough)
+ //Special plane so we can click through the overlay
+ SET_PLANE_EXPLICIT(trickery_image, SEETHROUGH_PLANE, fool)
+
+ fool.client.images += trickery_image
+
+ animate(trickery_image, alpha = target_alpha, time = animation_time)
+
+ RegisterSignal(fool, COMSIG_MOB_LOGOUT, PROC_REF(on_client_disconnect))
+
+///Remove the screen object and make us appear solid to ourselves again
+/datum/component/seethrough_mob/proc/untrick_mob()
+ var/mob/fool = parent
+ animate(trickery_image, alpha = 255, time = animation_time)
+ UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
+
+ //after playing the fade-in animation, remove the image and the trick atom
+ addtimer(CALLBACK(src, PROC_REF(clear_image), trickery_image, fool.client), animation_time)
+
+///Remove the image and the trick atom
+/datum/component/seethrough_mob/proc/clear_image(image/removee, client/remove_from)
+ var/atom/movable/atom_parent = parent
+ atom_parent.vis_contents -= render_source_atom
+ atom_parent.render_target = initial_render_target_value
+ remove_from?.images -= removee
+ remove_from.mob.update_appearance(UPDATE_ICON)
+
+///Effect is disabled when they log out because client gets deleted
+/datum/component/seethrough_mob/proc/on_client_disconnect()
+ SIGNAL_HANDLER
+
+ var/mob/fool = parent
+ UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
+ clear_image(trickery_image, fool.client)
+
+/datum/component/seethrough_mob/proc/toggle_active(datum/action/ability)
+ is_active = !is_active
+ if(is_active)
+ trick_mob()
+ ability.set_toggle(TRUE)
+ else
+ untrick_mob()
+ ability.set_toggle(FALSE)
+
+/datum/action/ability/xeno_action/toggle_seethrough
+ name = "Toggle Seethrough"
+ desc = "Allows you to see behind your massive body and click through it."
+ action_icon = 'icons/Xeno/actions.dmi'
+ action_icon_state = "xenohide"
+ cooldown_duration = 1 SECONDS
+ use_state_flags = ABILITY_USE_LYING
+ action_type = ACTION_TOGGLE
+
+/datum/action/ability/xeno_action/toggle_seethrough/action_activate(atom/t)
+ . = ..()
+ var/datum/component/seethrough_mob/transparency = target
+ transparency.toggle_active(src)
+ add_cooldown()
+
+/datum/action/ability/xeno_action/toggle_seethrough/Destroy()
+ var/datum/component/seethrough_mob/transparency = target
+ if(transparency.is_active)
+ transparency.untrick_mob()
+ return ..()
diff --git a/code/datums/components/shield.dm b/code/datums/components/shield.dm
index 07a1a89723b37..831d1e58c07eb 100644
--- a/code/datums/components/shield.dm
+++ b/code/datums/components/shield.dm
@@ -1,20 +1,23 @@
/datum/component/shield
+ ///Shielded mob
var/mob/living/affected
+ ///Callback to block damage entirely
var/datum/callback/intercept_damage_cb
+ ///Callback to transfer damage to the shield
var/datum/callback/transfer_damage_cb
- /// %-reduction-based armor.
- var/datum/armor/soft_armor
- /// Flat-damage-reduction-based armor.
- var/datum/armor/hard_armor
/// Percentage damage The shield intercepts.
var/datum/armor/cover
+ ///Behavior flags
var/shield_flags = NONE
+ ///What slots the parent item provides its shield effects in
var/slot_flags = list(SLOT_L_HAND, SLOT_R_HAND)
+ ///Shield priority layer
var/layer = 50
+ ///Is the shield currently active
var/active = TRUE
-/datum/component/shield/Initialize(shield_flags, shield_soft_armor, shield_hard_armor, shield_cover = list(MELEE = 80, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 80, BIO = 30, FIRE = 80, ACID = 80))
+/datum/component/shield/Initialize(shield_flags, shield_cover = list(MELEE = 80, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 80, BIO = 30, FIRE = 80, ACID = 80))
. = ..()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
@@ -33,20 +36,6 @@
setup_callbacks(shield_flags)
- if(!isnull(shield_soft_armor))
- soft_armor = shield_soft_armor
- if(islist(shield_soft_armor))
- soft_armor = getArmor(arglist(shield_soft_armor))
- else
- soft_armor = parent_item.soft_armor
-
- if(!isnull(shield_hard_armor))
- hard_armor = shield_hard_armor
- if(islist(shield_hard_armor))
- hard_armor = getArmor(arglist(shield_hard_armor))
- else
- hard_armor = parent_item.hard_armor
-
if(islist(shield_cover))
cover = getArmor(arglist(shield_cover))
else if(istype(shield_cover, /datum/armor))
@@ -58,13 +47,12 @@
/datum/component/shield/Destroy()
shield_detach_from_user()
- soft_armor = null
- hard_armor = null
cover = null
intercept_damage_cb = null
transfer_damage_cb = null
return ..()
+///Sets up the correct callbacks based on flagged behavior
/datum/component/shield/proc/setup_callbacks(shield_flags)
if(shield_flags & SHIELD_PURE_BLOCKING)
intercept_damage_cb = CALLBACK(src, PROC_REF(item_pure_block_chance))
@@ -89,6 +77,7 @@
else
deactivate_with_user()
+///Handles equipping the shield
/datum/component/shield/proc/shield_equipped(datum/source, mob/living/user, slot)
SIGNAL_HANDLER
if(!(slot in slot_flags))
@@ -100,9 +89,10 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
- if(parent_item.slowdown)
- human_user.add_movespeed_modifier(parent_item.type, TRUE, 0, ((parent_item.flags_item & IMPEDE_JETPACK) ? SLOWDOWN_IMPEDE_JETPACK : NONE), TRUE, parent_item.slowdown)
+ if(parent_item.slowdown) //todo: make this less smelly, I have no idea why this is on the shield component, and could likely cause unintended double slowdown
+ human_user.add_movespeed_modifier(parent_item.type, TRUE, 0, ((parent_item.item_flags & IMPEDE_JETPACK) ? SLOWDOWN_IMPEDE_JETPACK : NONE), TRUE, parent_item.slowdown)
+///Handles unequipping the shield
/datum/component/shield/proc/shield_dropped(datum/source, mob/user)
SIGNAL_HANDLER
shield_detach_from_user()
@@ -114,6 +104,7 @@
if(parent_item.slowdown)
human_user.remove_movespeed_modifier(parent.type)
+///Toggles shield effects for the user
/datum/component/shield/proc/shield_affect_user(mob/living/user)
if(affected)
if(affected == user)
@@ -123,12 +114,7 @@
if(active)
activate_with_user()
-/datum/component/shield/proc/activate_with_user()
- RegisterSignal(affected, COMSIG_LIVING_SHIELDCALL, PROC_REF(on_attack_cb_shields_call))
-
-/datum/component/shield/proc/deactivate_with_user()
- UnregisterSignal(affected, COMSIG_LIVING_SHIELDCALL)
-
+///Detaches shield from the user
/datum/component/shield/proc/shield_detach_from_user()
if(!affected)
return
@@ -136,74 +122,86 @@
deactivate_with_user()
affected = null
+///Activates shield effects
+/datum/component/shield/proc/activate_with_user()
+ RegisterSignal(affected, COMSIG_LIVING_SHIELDCALL, PROC_REF(on_attack_cb_shields_call))
+
+///Deactivates shield effects
+/datum/component/shield/proc/deactivate_with_user()
+ UnregisterSignal(affected, COMSIG_LIVING_SHIELDCALL)
+
+///Signal handler for incoming damage, directs to the right callback proc
/datum/component/shield/proc/on_attack_cb_shields_call(datum/source, list/affecting_shields, dam_type)
SIGNAL_HANDLER
if(cover.getRating(dam_type) <= 0)
return
affecting_shields[intercept_damage_cb] = layer
-/datum/component/shield/proc/item_intercept_attack(attack_type, incoming_damage, damage_type, silent, penetration)
+///Calculates a modifier to the shield coverage based on user or parent conditions
+/datum/component/shield/proc/get_shield_status_modifier()
var/obj/item/parent_item = parent
- var/status_cover_modifier = 1
+ var/shield_status_modifier = 1
if(parent_item.obj_integrity <= parent_item.integrity_failure)
- return incoming_damage
+ return 0
if(affected.IsSleeping() || affected.IsUnconscious() || affected.IsAdminSleeping()) //We don't do jack if we're literally KOed/sleeping/paralyzed.
- return incoming_damage
+ return 0
if(affected.IsStun() || affected.IsKnockdown() || affected.IsParalyzed()) //Halve shield cover if we're paralyzed or stunned
- status_cover_modifier *= 0.5
+ shield_status_modifier *= 0.5
if(iscarbon(affected))
var/mob/living/carbon/C = affected
if(C.IsStaggered()) //Lesser penalty to shield cover for being staggered.
- status_cover_modifier *= 0.75
+ shield_status_modifier *= 0.75
+
+ return shield_status_modifier
+
+///Damage intercept calculation
+/datum/component/shield/proc/item_intercept_attack(attack_type, incoming_damage, damage_type, silent, penetration)
+ var/shield_status_modifier = get_shield_status_modifier()
switch(attack_type)
- if(COMBAT_TOUCH_ATTACK)
- if(!prob(cover.getRating(damage_type) * status_cover_modifier))
- return FALSE //Bypassed the shield.
- incoming_damage = max(0, incoming_damage - hard_armor.getRating(damage_type))
- incoming_damage *= (100 - soft_armor.getRating(damage_type)) * 0.01
- return prob(50 - round(incoming_damage / 3))
- if(COMBAT_MELEE_ATTACK, COMBAT_PROJ_ATTACK)
- var/absorbing_damage = incoming_damage * cover.getRating(damage_type) * 0.01 * status_cover_modifier //Determine cover ratio; this is the % of damage we actually intercept.
+ if(COMBAT_TOUCH_ATTACK) //Touch attacks return true if the associated negative effect is blocked
+ if(!prob(cover.getRating(damage_type) * shield_status_modifier))
+ return FALSE
+ var/obj/item/parent_item = parent
+ incoming_damage = parent_item.modify_by_armor(incoming_damage, damage_type, penetration)
+ return prob(50 - round(incoming_damage / 3)) //Two checks for touch attacks to make it less absurdly effective, or something.
+ if(COMBAT_MELEE_ATTACK, COMBAT_PROJ_ATTACK) //we return the amount of damage that bypasses the shield
+ var/absorbing_damage = incoming_damage * cover.getRating(damage_type) * 0.01 * shield_status_modifier //Determine cover ratio; this is the % of damage we actually intercept.
if(!absorbing_damage)
- return incoming_damage //We are transparent to this kind of damage.
+ return incoming_damage
. = incoming_damage - absorbing_damage
- absorbing_damage = max(0, absorbing_damage - (hard_armor.getRating(damage_type) * (100 - penetration) * 0.01)) //Hard armor first, with pen as percent reduction to flat armor
- absorbing_damage *= (100 - max(0, soft_armor.getRating(damage_type) - penetration)) * 0.01 //Soft armor second, with pen as flat reduction to percent armor
- if(absorbing_damage <= 0)
- if(!silent)
- to_chat(affected, span_avoidharm("\The [parent_item.name] [. ? "softens" : "soaks"] the damage!"))
- return
if(transfer_damage_cb)
- return transfer_damage_cb.Invoke(absorbing_damage, ., silent)
+ return transfer_damage_cb.Invoke(absorbing_damage, ., damage_type, silent, penetration)
+
+///Applies damage to parent item
+/datum/component/shield/proc/transfer_damage_to_parent(return_damage, incoming_damage, damage_type, silent, penetration)
+ var/obj/item/parent_item = parent
+ incoming_damage = parent_item.modify_by_armor(incoming_damage, damage_type, penetration)
+ if(incoming_damage > parent_item.obj_integrity)
+ return_damage += incoming_damage - parent_item.obj_integrity //if we destroy the shield item, extra damage spills over
+ if(!silent)
+ to_chat(affected, span_avoidharm("\The [parent_item.name] [. ? "softens" : "soaks"] the damage!"))
+ parent_item.take_damage(incoming_damage)
+ return return_damage
+///Block chance calculation
/datum/component/shield/proc/item_pure_block_chance(attack_type, incoming_damage, damage_type, silent, penetration)
switch(attack_type)
- if(COMBAT_TOUCH_ATTACK)
- if(!prob(cover.getRating(damage_type) - penetration))
- return FALSE //Bypassed the shield.
- incoming_damage = max(0, incoming_damage - hard_armor.getRating(damage_type))
- incoming_damage *= (100 - soft_armor.getRating(damage_type)) * 0.01
- return prob(50 - round(incoming_damage / 3))
+ if(COMBAT_TOUCH_ATTACK) //Touch attacks return true if the associated negative effect is blocked
+ var/shield_status_modifier = get_shield_status_modifier()
+ if(!prob(cover.getRating(damage_type) * shield_status_modifier))
+ return FALSE
+ var/obj/item/parent_item = parent
+ incoming_damage = parent_item.modify_by_armor(incoming_damage, damage_type, penetration)
+ return prob(50 - round(incoming_damage / 3)) //Two checks for touch attacks to make it less absurdly effective, or something.
if(COMBAT_MELEE_ATTACK, COMBAT_PROJ_ATTACK)
if(prob(cover.getRating(damage_type) - penetration))
- return 0 //Blocked
- return incoming_damage //Went through.
-
-/datum/component/shield/proc/transfer_damage_to_parent(incoming_damage, return_damage, silent)
- . = return_damage
- var/obj/item/parent_item = parent
- if(incoming_damage >= parent_item.obj_integrity)
- . += incoming_damage - parent_item.obj_integrity
- parent_item.take_damage(incoming_damage, armour_penetration = 100) //Armor has already been accounted for, this should destroy the parent and thus the component.
- return
- if(!silent)
- to_chat(affected, span_avoidharm("\The [parent_item.name] [. ? "softens" : "soaks"] the damage!"))
- parent_item.take_damage(incoming_damage, armour_penetration = 100)
+ return 0
+ return incoming_damage
//Dune, Halo and energy shields.
@@ -220,7 +218,7 @@
var/next_recharge = 0 //world.time based
var/shield_overlay = "shield-blue"
-/datum/component/shield/overhealth/Initialize(shield_flags, shield_soft_armor, shield_hard_armor, shield_cover)
+/datum/component/shield/overhealth/Initialize(shield_flags, shield_cover = list(MELEE = 0, BULLET = 80, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, FIRE = 0, ACID = 80))
if(!issuit(parent))
return COMPONENT_INCOMPATIBLE
return ..()
@@ -234,7 +232,7 @@
intercept_damage_cb = CALLBACK(src, PROC_REF(overhealth_intercept_attack))
transfer_damage_cb = CALLBACK(src, PROC_REF(transfer_damage_to_overhealth))
-
+///Checks if damage should be passed to overshield
/datum/component/shield/overhealth/proc/overhealth_intercept_attack(attack_type, incoming_damage, damage_type, silent)
switch(attack_type)
if(COMBAT_TOUCH_ATTACK)
@@ -245,36 +243,19 @@
var/absorbing_damage = incoming_damage * cover.getRating(damage_type) * 0.01
if(!absorbing_damage)
return incoming_damage //We are transparent to this kind of damage.
- . = incoming_damage - absorbing_damage
- absorbing_damage = max(0, absorbing_damage - hard_armor.getRating(damage_type))
- absorbing_damage *= (100 - soft_armor.getRating(damage_type)) * 0.01
- return wrap_up_attack(absorbing_damage, ., silent)
-
-
-/datum/component/shield/overhealth/proc/wrap_up_attack(absorbing_damage, unabsorbed_damage, silent)
- . = unabsorbed_damage
- var/obj/item/parent_item = parent
- if(absorbing_damage <= 0)
- if(!.)
- if(!silent)
- to_chat(affected, span_avoidharm("\The [parent_item.name] soaks the damage!"))
- return
- if(transfer_damage_cb)
- return transfer_damage_cb.Invoke(absorbing_damage, ., silent)
- else if(!silent)
- to_chat(affected, span_avoidharm("\The [parent_item.name] softens the damage!"))
-
+ return transfer_damage_cb.Invoke(absorbing_damage, incoming_damage - absorbing_damage, silent)
+///Calculates actual damage to the shield, returning total amount that penetrates
/datum/component/shield/overhealth/proc/transfer_damage_to_overhealth(absorbing_damage, unabsorbed_damage, silent)
- . = unabsorbed_damage
- var/obj/item/parent_item = parent
if(absorbing_damage >= shield_integrity)
- . += absorbing_damage - shield_integrity
+ unabsorbed_damage += absorbing_damage - shield_integrity
if(!silent)
+ var/obj/item/parent_item = parent
to_chat(affected, span_avoidharm("\The [parent_item.name] [. ? "softens" : "soaks"] the damage!"))
damage_overhealth(absorbing_damage)
+ return unabsorbed_damage
-
+///Applies damage to overshield
/datum/component/shield/overhealth/proc/damage_overhealth(amount)
var/datum/effect_system/spark_spread/s = new
s.set_up(2, 1, get_turf(parent))
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index ad6553a6e797b..a6e6b3a622f56 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -76,7 +76,7 @@
SIGNAL_HANDLER
if(isitem(AM))
var/obj/item/I = AM
- if(I.flags_item & ITEM_ABSTRACT)
+ if(I.item_flags & ITEM_ABSTRACT)
return
if(istype(AM, /obj/projectile))
diff --git a/code/datums/components/stun_mitigation.dm b/code/datums/components/stun_mitigation.dm
index c881f1fb105e2..3ae59d1e2f1b2 100644
--- a/code/datums/components/stun_mitigation.dm
+++ b/code/datums/components/stun_mitigation.dm
@@ -90,7 +90,7 @@
///Actually deactivates the mitigation effect
/datum/component/stun_mitigation/proc/deactivate_with_user()
- UnregisterSignal(affected, COMSIG_LIVING_PROJECTILE_STUN)
+ UnregisterSignal(affected, list(COMSIG_LIVING_PROJECTILE_STUN, COMSIG_LIVING_JETPACK_STUN))
///Handles removing the mitigation from a user
/datum/component/stun_mitigation/proc/shield_detach_from_user()
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 06b85ae7e1bc3..c21cf8595127e 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -203,7 +203,7 @@ GLOBAL_DATUM_INIT(datacore, /datum/datacore, new)
else
assignment = "Unassigned"
- var/id = add_leading("[num2hex(randfloat(1, 1.6777215E7))]", 6, "0") //this was the best they could come up with? A large random number? *sigh* - actual 4407 code lol
+ var/id = add_leading("[num2hex(randfloat(1, 1.6777215E7), 2)]", 6, "0") //this was the best they could come up with? A large random number? *sigh* - actual 4407 code lol
//General Record
var/datum/data/record/G = new()
@@ -228,7 +228,7 @@ GLOBAL_DATUM_INIT(datacore, /datum/datacore, new)
var/datum/data/record/M = new()
M.fields["id"] = id
M.fields["name"] = H.real_name
- M.fields["b_type"] = H.b_type
+ M.fields["b_type"] = H.blood_type
M.fields["mi_dis"] = "None"
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
M.fields["ma_dis"] = "None"
@@ -303,7 +303,7 @@ GLOBAL_DATUM_INIT(datacore, /datum/datacore, new)
var/datum/data/record/M = new
M.fields["id"] = null
M.fields["name"] = H.real_name
- M.fields["b_type"] = H.b_type
+ M.fields["b_type"] = H.blood_type
M.fields["mi_dis"] = "None"
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
M.fields["ma_dis"] = "None"
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 7c4133c2334a4..b9fe35c8e20bd 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -17,6 +17,10 @@
*/
var/gc_destroyed
+ /// Open uis owned by this datum
+ /// Lazy, since this case is semi rare
+ var/list/open_uis
+
/// Active timers with this datum as the target
var/list/_active_timers
/// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
diff --git a/code/datums/elements/attachment.dm b/code/datums/elements/attachment.dm
index 2e88a4b9bcf43..f9c94b7f53629 100644
--- a/code/datums/elements/attachment.dm
+++ b/code/datums/elements/attachment.dm
@@ -5,7 +5,7 @@
var/list/attachment_data
//on_attach, on_detach, on_activate and can_attach are all proc paths that get turned into callbacks when they are called.
-/datum/element/attachment/Attach(datum/target, slot, overlay_icon, on_attach, on_detach, on_activate, can_attach, pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound, mob_overlay_icon, mob_pixel_shift_x, mob_pixel_shift_y, attachment_layer, extra_vars)
+/datum/element/attachment/Attach(datum/target, slot, overlay_icon, on_attach, on_detach, on_activate, can_attach, pixel_shift_x, pixel_shift_y, attach_features_flags, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound, mob_overlay_icon, mob_pixel_shift_x, mob_pixel_shift_y, attachment_layer, extra_vars)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
@@ -20,7 +20,7 @@
CAN_ATTACH = can_attach, //Callback that is called on attach to determine by the attachment whether or not it can attach to the item.
PIXEL_SHIFT_X = pixel_shift_x, //Pixel shift on X Axis for the attachments overlay.
PIXEL_SHIFT_Y = pixel_shift_y, //Pixel shift on Y Axis for the attachments overlay.
- FLAGS_ATTACH_FEATURES = flags_attach_features, //Flags for how the attachment functions.
+ FLAGS_ATTACH_FEATURES = attach_features_flags, //Flags for how the attachment functions.
ATTACH_DELAY = attach_delay, //Delay for attaching.
DETACH_DELAY = detach_delay, //Delay for detaching.
ATTACH_SKILL = attach_skill, //Skill used in attaching and detaching. Can be null. If user does not meet the skill requirement the attach delay and detach delay is doubled.
diff --git a/code/datums/elements/connect_loc.dm b/code/datums/elements/connect_loc.dm
index c373adafffe62..7693fb0febdfb 100644
--- a/code/datums/elements/connect_loc.dm
+++ b/code/datums/elements/connect_loc.dm
@@ -19,7 +19,7 @@
/datum/element/connect_loc/Detach(atom/movable/listener)
. = ..()
- unregister_signals(listener, listener.loc)
+ unregister_signals(listener, listener.loc, listener.locs)
UnregisterSignal(listener, COMSIG_MOVABLE_MOVED)
/datum/element/connect_loc/proc/update_signals(atom/movable/listener)
@@ -29,16 +29,25 @@
for (var/signal in connections)
//override=TRUE because more than one connect_loc element instance tracked object can be on the same loc
- listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE)
+ if(length(listener.locs) < 2) //this is kinda funny but a multitile object could be inside something
+ listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE)
+ continue
+ for(var/turf/turf AS in listener.locs)
+ listener.RegisterSignal(turf, signal, connections[signal], override=TRUE)
-/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc)
+
+/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc, list/turf/old_locs)
if(isnull(old_loc))
return
for (var/signal in connections)
- listener.UnregisterSignal(old_loc, signal)
+ if(length(old_locs) < 2)
+ listener.UnregisterSignal(old_loc, signal)
+ continue
+ for(var/turf/turf AS in old_locs)
+ listener.UnregisterSignal(turf, signal)
-/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc)
+/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc, movement_dir, forced, list/turf/old_locs)
SIGNAL_HANDLER
- unregister_signals(listener, old_loc)
+ unregister_signals(listener, old_loc, old_locs)
update_signals(listener)
diff --git a/code/datums/elements/debris.dm b/code/datums/elements/debris.dm
index 36fd9427cfd83..776db5dd36b39 100644
--- a/code/datums/elements/debris.dm
+++ b/code/datums/elements/debris.dm
@@ -71,7 +71,7 @@
smoke_visuals = new(source, /particles/impact_smoke)
smoke_visuals.particles.position = list(position_offset, position_offset)
smoke_visuals.particles.velocity = list(x_component_smoke, y_component_smoke)
- if(debris && !(P.ammo.flags_ammo_behavior & AMMO_ENERGY || P.ammo.flags_ammo_behavior & AMMO_XENO))
+ if(debris && !(P.ammo.ammo_behavior_flags & AMMO_ENERGY || P.ammo.ammo_behavior_flags & AMMO_XENO))
debris_visuals = new(source, /particles/debris)
debris_visuals.particles.position = generator(GEN_CIRCLE, position_offset, position_offset)
debris_visuals.particles.velocity = list(x_component, y_component)
@@ -83,7 +83,7 @@
smoke_visuals.layer = ABOVE_OBJ_LAYER + 0.01
if(P.ammo.sound_bounce)
var/pitch = 0
- if(P.ammo.flags_ammo_behavior & AMMO_SOUND_PITCH)
+ if(P.ammo.ammo_behavior_flags & AMMO_SOUND_PITCH)
pitch = 55000
playsound(source, P.ammo.sound_bounce, 50, 1, frequency = pitch)
addtimer(CALLBACK(src, PROC_REF(remove_ping), src, smoke_visuals, debris_visuals), 0.7 SECONDS)
diff --git a/code/datums/elements/directional_attack.dm b/code/datums/elements/directional_attack.dm
new file mode 100644
index 0000000000000..4b130aa2962c3
--- /dev/null
+++ b/code/datums/elements/directional_attack.dm
@@ -0,0 +1,43 @@
+/*!
+ * This element allows the mob its attached to the ability to click an adjacent mob by clicking a distant atom
+ * that is in the general direction relative to the parent.
+ */
+/datum/element/directional_attack/Attach(datum/target)
+ . = ..()
+ if(!ismob(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_ranged_attack))
+
+/datum/element/directional_attack/Detach(datum/source, ...)
+ . = ..()
+ UnregisterSignal(source, COMSIG_MOB_ATTACK_RANGED)
+
+/**
+ * This proc handles clicks on tiles that aren't adjacent to the source mob
+ * In addition to clicking the distant tile, it checks the tile in the direction and clicks the mob in the tile if there is one
+ * Arguments:
+ * * source - The mob clicking
+ * * clicked_atom - The atom being clicked (should be a distant one)
+ * * click_params - Miscellaneous click parameters, passed from Click itself
+ */
+/datum/element/directional_attack/proc/on_ranged_attack(mob/source, atom/clicked_atom, click_params)
+ SIGNAL_HANDLER
+
+ if(!(source?.client?.prefs?.toggles_gameplay & DIRECTIONAL_ATTACKS))
+ return
+
+ if(QDELETED(clicked_atom))
+ return
+
+ var/turf/turf_to_check = get_step(source, angle_to_dir(Get_Angle(source, clicked_atom)))
+ if(!turf_to_check || !source.Adjacent(turf_to_check))
+ return
+
+ var/mob/target_mob = locate() in turf_to_check
+ if(!target_mob || source.faction == target_mob.faction)
+ return
+
+ //This is here to undo the +1 the click on the distant turf adds so we can click the mob near us
+ source.next_click = world.time - 1
+ INVOKE_ASYNC(source, TYPE_PROC_REF(/mob, ClickOn), target_mob, turf_to_check, click_params)
diff --git a/code/datums/elements/egrill_element.dm b/code/datums/elements/egrill_element.dm
index f4caf58e1bf55..5e91f8d26aad0 100644
--- a/code/datums/elements/egrill_element.dm
+++ b/code/datums/elements/egrill_element.dm
@@ -33,7 +33,7 @@
/datum/element/egrill/proc/attackby(obj/source, obj/item/attacked_by, mob/attacker, params)
SIGNAL_HANDLER
- if(!iswirecutter(attacked_by) && !isscrewdriver(attacked_by) && !(attacked_by.flags_atom & CONDUCT))
+ if(!iswirecutter(attacked_by) && !isscrewdriver(attacked_by) && !(attacked_by.atom_flags & CONDUCT))
return
if(shock(source, attacker))
return COMPONENT_NO_AFTERATTACK
diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm
index fa820a46ff2ae..a3e5c2fa18ecf 100644
--- a/code/datums/elements/footstep.dm
+++ b/code/datums/elements/footstep.dm
@@ -30,7 +30,7 @@
if(!ishuman(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(humanstep_wrapper)) //we don't want the movement signal args
- RegisterSignal(target, COMSIG_ELEMENT_JUMP_ENDED, PROC_REF(play_humanstep))
+ RegisterSignals(target, list(COMSIG_ELEMENT_JUMP_ENDED, COMSIG_MOVABLE_PATROL_DEPLOYED), PROC_REF(play_humanstep))
steps_for_living[target] = 0
return
if(FOOTSTEP_MOB_SHOE)
@@ -48,11 +48,11 @@
footstep_sounds = GLOB.predalienstompy
//RUTGMC EDIT ADDITION END
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(simplestep_wrapper))
- RegisterSignal(target, COMSIG_ELEMENT_JUMP_ENDED, PROC_REF(play_simplestep))
+ RegisterSignals(target, list(COMSIG_ELEMENT_JUMP_ENDED, COMSIG_MOVABLE_PATROL_DEPLOYED), PROC_REF(play_simplestep))
steps_for_living[target] = 0
/datum/element/footstep/Detach(atom/movable/source)
- UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_ELEMENT_JUMP_ENDED))
+ UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_ELEMENT_JUMP_ENDED, COMSIG_MOVABLE_PATROL_DEPLOYED))
steps_for_living -= source
return ..()
@@ -189,7 +189,7 @@
var/override_sound = source_loc.get_footstep_override()
var/footstep_type
- if((source.wear_suit?.flags_armor_protection | source.w_uniform?.flags_armor_protection | source.shoes?.flags_armor_protection) & FEET) //We are not disgusting barefoot bandits
+ if((source.wear_suit?.armor_protection_flags | source.w_uniform?.armor_protection_flags | source.shoes?.armor_protection_flags) & FEET) //We are not disgusting barefoot bandits
var/static/list/footstep_sounds = GLOB.shoefootstep //static is faster
footstep_type = override_sound ? override_sound : source_loc.shoefootstep
playsound(
diff --git a/code/datums/elements/riding.dm b/code/datums/elements/riding.dm
index a9f14d2c3ba81..45546b1a0f3c9 100644
--- a/code/datums/elements/riding.dm
+++ b/code/datums/elements/riding.dm
@@ -104,7 +104,7 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
- flags_item = ITEM_ABSTRACT | DELONDROP | NOBLUDGEON
+ item_flags = ITEM_ABSTRACT | DELONDROP | NOBLUDGEON
resistance_flags = INDESTRUCTIBLE | UNACIDABLE | PROJECTILE_IMMUNE
var/mob/living/carbon/rider
var/mob/living/parent
diff --git a/code/datums/elements/scalping.dm b/code/datums/elements/scalping.dm
index e34ac71f7e953..f6718a6e3938b 100644
--- a/code/datums/elements/scalping.dm
+++ b/code/datums/elements/scalping.dm
@@ -26,6 +26,6 @@
/obj/item/scalp
name = "scalp"
desc = "The mutilated scalp of a slain xeno, proof of a great victory!"
- icon = 'icons/unused/Marine_research.dmi'
+ icon = 'icons/Xeno/xeno_materials.dmi'
icon_state = "chitin-chunk"
w_class = WEIGHT_CLASS_TINY
diff --git a/code/datums/elements/shrapnel_removal.dm b/code/datums/elements/shrapnel_removal.dm
index 7cc2573d36b63..35b92110da011 100644
--- a/code/datums/elements/shrapnel_removal.dm
+++ b/code/datums/elements/shrapnel_removal.dm
@@ -67,6 +67,10 @@
if(is_type_in_list(I, GLOB.known_implants))
continue
I.unembed_ourself(FALSE)
+ if(user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
+ personal_statistics.shrapnel_removed ++
+ personal_statistics.mission_shrapnel_removed ++
if(skill < SKILL_MEDICAL_PRACTICED)
user.visible_message(span_notice("[user] violently rips out [I] from [target]!"), span_notice("You violently rip out [I] from [target]!"))
targetlimb.take_damage_limb(30 * (SKILL_MEDICAL_PRACTICED - skill), 0, FALSE, FALSE)
diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm
index df4720d47759b..9257815968d84 100644
--- a/code/datums/emergency_calls/emergency_call.dm
+++ b/code/datums/emergency_calls/emergency_call.dm
@@ -152,7 +152,7 @@
message_admins("Distress beacon: '[name]' activated. Looking for candidates.")
if(announce)
- priority_announce("A distress beacon has been launched from the [SSmapping.configs[SHIP_MAP].map_name].", "Priority Alert", sound = 'sound/AI/distressbeacon.ogg')
+ priority_announce("A distress beacon has been launched from the [SSmapping.configs[SHIP_MAP].map_name].", title = "Distress Beacon", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/distressbeacon.ogg', color_override = "orange")
SSticker.mode.on_distress_cooldown = TRUE
diff --git a/code/datums/emergency_calls/retired.dm b/code/datums/emergency_calls/retired.dm
new file mode 100644
index 0000000000000..a963154aab088
--- /dev/null
+++ b/code/datums/emergency_calls/retired.dm
@@ -0,0 +1,58 @@
+/datum/emergency_call/retired
+ name = "Retired TGMC Veteran Squad"
+ base_probability = 15
+ alignement_factor = -1
+
+/datum/emergency_call/retired/print_backstory(mob/living/carbon/human/H)
+ to_chat(H, "You are an old, retired member of the TerraGov marine corps.")
+ to_chat(H, "Althought you may be past your prime, high command has deemed you capable enough to be sent to the [SSmapping.configs[SHIP_MAP].map_name], which has recently sent out a distress signal.")
+ to_chat(H, "Investigate why the distress signal was sent and show the younger generation how it's done!")
+
+/datum/emergency_call/retired/create_member(datum/mind/mind_to_assign)
+ . = ..()
+ if(!.)
+ return
+ var/mob/original = mind_to_assign.current
+ var/mob/living/carbon/human/H = .
+
+ if(H.gender == MALE)
+ H.h_style = pick("Bald", "Balding Hair", "Balding Fade", "Balding ponytail", "Balding medium")
+ else
+ H.h_style = pick("Overeye Very Short", "Updo", "Ponytail 1")
+ H.r_hair = 235
+ H.g_hair = 235
+ H.b_hair = 235
+ H.r_facial = 235
+ H.g_facial = 235
+ H.b_facial = 235
+ H.update_hair()
+
+ mind_to_assign.transfer_to(H, TRUE)
+ H.fully_replace_character_name(mind_to_assign.name, H.real_name)
+
+ if(original)
+ qdel(original)
+
+ print_backstory(H)
+
+ if(!leader)
+ leader = H
+ var/datum/job/J = SSjob.GetJobType(/datum/job/retired/leader)
+ H.apply_assigned_role_to_spawn(J)
+ to_chat(H, "
You are the TGMC retired veteran expedition leader! Lead your fellow veterans to one last hurrah!
")
+ return
+
+ if(prob(30)) //30% chance to get robot limbs instead of being legless in a wheelchair
+ var/datum/job/J = SSjob.GetJobType(/datum/job/retired/augmented)
+ H.apply_assigned_role_to_spawn(J)
+ to_chat(H, "
You are an augmented TGMC veteran, you may have had a few limbs replaced with synthetic versions, but at least you can walk! Follow the expedition leader and relive your glory days!
[span_notice("You are a grunt, with limited psionic potential.")]
")
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 9ec5ed0f73593..e59bdf64adbd8 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -14,7 +14,7 @@
var/list/mob_type_ignore_stat_typecache
var/stat_allowed = CONSCIOUS
var/sound //Sound to play when emote is called
- var/flags_emote = NONE
+ var/emote_flags = NONE
/// Cooldown between two uses of that emote. Every emote has its own coodldown
var/cooldown = 2 SECONDS
@@ -62,8 +62,8 @@
var/dchatmsg = "[prefix][user] [msg]"
var/tmp_sound = get_sound(user)
- if(tmp_sound && (!(flags_emote & EMOTE_FORCED_AUDIO) || !intentional))
- playsound(user, tmp_sound, 50, flags_emote & EMOTE_VARY)
+ if(tmp_sound && (!(emote_flags & EMOTE_FORCED_AUDIO) || !intentional))
+ playsound(user, tmp_sound, 50, emote_flags & EMOTE_VARY)
if(user.client)
for(var/mob/M AS in GLOB.dead_mob_list)
@@ -104,7 +104,7 @@
/datum/emote/proc/select_message_type(mob/user)
. = message
- if(!(flags_emote & EMOTE_MUZZLE_IGNORE) && user.is_muzzled() && emote_type == EMOTE_AUDIBLE)
+ if(!(emote_flags & EMOTE_MUZZLE_IGNORE) && user.is_muzzled() && emote_type == EMOTE_AUDIBLE)
return "makes a [pick("strong ", "weak ", "")]noise."
if(isxeno(user) && message_alien)
. = message_alien
@@ -132,7 +132,7 @@
return FALSE
if(intentional)
- if(flags_emote & EMOTE_FORCED_AUDIO)
+ if(emote_flags & EMOTE_FORCED_AUDIO)
return FALSE
if(sound || get_sound(user))
@@ -170,7 +170,7 @@
return FALSE
- if(flags_emote & EMOTE_RESTRAINT_CHECK)
+ if(emote_flags & EMOTE_RESTRAINT_CHECK)
if(isliving(user))
var/mob/living/L = user
if(L.incapacitated())
@@ -179,7 +179,7 @@
user.balloon_alert(user, "You cannot [key] while stunned")
return FALSE
- if(flags_emote & EMOTE_ARMS_CHECK)
+ if(emote_flags & EMOTE_ARMS_CHECK)
///okay snapper
var/mob/living/carbon/snapper = user
var/datum/limb/left_hand = snapper.get_limb("l_hand")
@@ -188,7 +188,7 @@
to_chat(user, span_notice("You cannot [key] without a working hand."))
return FALSE
- if((flags_emote & EMOTE_RESTRAINT_CHECK) && user.restrained())
+ if((emote_flags & EMOTE_RESTRAINT_CHECK) && user.restrained())
if(!intentional)
return FALSE
user.balloon_alert(user, "You cannot [key] while restrained")
diff --git a/code/datums/fire_support.dm b/code/datums/fire_support.dm
index 17efcf386b039..4a1c3935502b8 100644
--- a/code/datums/fire_support.dm
+++ b/code/datums/fire_support.dm
@@ -196,7 +196,7 @@
initiate_chat_message = "TARGET ACQUIRED ROCKET RUN INBOUND."
initiate_screen_message = "Rockets hot, incoming!"
initiate_title = "Avenger-4"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_pilot
start_visual = /obj/effect/temp_visual/dropship_flyby/som
uses = 2
@@ -231,6 +231,7 @@
initiate_chat_message = "TARGET ACQUIRED SENTRY POD LAUNCHING."
initiate_screen_message = "Co-ordinates confirmed, sentry pod launching."
initiate_sound = null
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/pod_officer
start_visual = null
start_sound = null
cooldown_duration = 1 SECONDS
@@ -283,7 +284,7 @@
initiate_chat_message = "TARGET ACQUIRED GUN RUN INBOUND."
initiate_screen_message = "Target received, gun run inbound."
initiate_title = "Avenger-4"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_pilot
start_visual = /obj/effect/temp_visual/dropship_flyby/som
uses = 3
@@ -328,7 +329,7 @@
initiate_screen_message = "Coordinates confirmed, high explosive inbound!"
initiate_title = "Rhino-1"
initiate_sound = 'sound/weapons/guns/misc/mortar_travel.ogg'
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/tgmc_mortar
start_visual = null
start_sound = 'sound/weapons/guns/misc/mortar_long_whistle.ogg'
@@ -338,7 +339,7 @@
/datum/fire_support/mortar/som
fire_support_type = FIRESUPPORT_TYPE_HE_MORTAR_SOM
initiate_title = "Guardian-1"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_mortar
/datum/fire_support/mortar/incendiary
name = "Incendiary mortar barrage"
@@ -355,7 +356,7 @@
/datum/fire_support/mortar/incendiary/som
fire_support_type = FIRESUPPORT_TYPE_INCENDIARY_MORTAR_SOM
initiate_title = "Guardian-1"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_mortar
/datum/fire_support/mortar/smoke
name = "Smoke mortar barrage"
@@ -382,7 +383,7 @@
/datum/fire_support/mortar/smoke/som
fire_support_type = FIRESUPPORT_TYPE_SMOKE_MORTAR_SOM
initiate_title = "Guardian-1"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_mortar
/datum/fire_support/mortar/smoke/acid
name = "Acid smoke mortar barrage"
@@ -391,7 +392,7 @@
icon_state = "acid_smoke_mortar"
initiate_chat_message = "COORDINATES CONFIRMED. MORTAR BARRAGE INCOMING."
initiate_screen_message = "Coordinates confirmed, acid smoke inbound!"
- smoketype = /datum/effect_system/smoke_spread/xeno/acid
+ smoketype = /datum/effect_system/smoke_spread/xeno/acid/opaque
smokeradius = 5
/datum/fire_support/mortar/smoke/satrapine
@@ -401,6 +402,7 @@
icon_state = "satrapine_mortar"
initiate_chat_message = "COORDINATES CONFIRMED. MORTAR BARRAGE INCOMING."
initiate_screen_message = "Coordinates confirmed, satrapine inbound!"
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_mortar
smoketype = /datum/effect_system/smoke_spread/satrapine
smokeradius = 5
@@ -413,11 +415,11 @@
initiate_chat_message = "TARGET ACQUIRED RAD MISSILE INBOUND."
initiate_screen_message = "Target locked, rads inbound!"
initiate_title = "Avenger-4"
- portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_over
+ portrait_type = /atom/movable/screen/text/screen_text/picture/potrait/som_pilot
start_visual = /obj/effect/temp_visual/dropship_flyby/som
uses = 2
///Base strength of the rad effects
- var/rad_strength = 30
+ var/rad_strength = 25
///Range for the maximum rad effects
var/inner_range = 3
///Range for the moderate rad effects
diff --git a/code/datums/gamemodes/_game_mode.dm b/code/datums/gamemodes/_game_mode.dm
index 0cbe77d118a20..d4bccce1752b1 100644
--- a/code/datums/gamemodes/_game_mode.dm
+++ b/code/datums/gamemodes/_game_mode.dm
@@ -17,8 +17,8 @@ GLOBAL_VAR(common_report) //Contains common part of roundend report
var/list/job_points_needed_by_job_type = list()
var/round_time_fog
- var/flags_round_type = NONE
- var/flags_xeno_abilities = NONE
+ var/round_type_flags = NONE
+ var/xeno_abilities_flags = NONE
///Determines whether rounds with the gamemode will be factored in when it comes to persistency
var/allow_persistence_save = TRUE
@@ -61,7 +61,7 @@ GLOBAL_VAR(common_report) //Contains common part of roundend report
///If the gamemode has a whitelist of valid ground maps. Whitelist overrides the blacklist
var/list/whitelist_ground_maps
///If the gamemode has a blacklist of disallowed ground maps
- var/list/blacklist_ground_maps = list(MAP_DELTA_STATION, MAP_PRISON_STATION, MAP_LV_624, MAP_WHISKEY_OUTPOST, MAP_OSCAR_OUTPOST, MAP_FORT_PHOBOS)
+ var/list/blacklist_ground_maps = list(MAP_DELTA_STATION, MAP_RESEARCH_OUTPOST, MAP_PRISON_STATION, MAP_LV_624, MAP_WHISKEY_OUTPOST, MAP_OSCAR_OUTPOST, MAP_FORT_PHOBOS)
///if fun tads are enabled by default
var/enable_fun_tads = FALSE
@@ -110,7 +110,7 @@ GLOBAL_VAR(common_report) //Contains common part of roundend report
create_characters()
spawn_characters()
transfer_characters()
- SSpoints.prepare_supply_packs_list(CHECK_BITFIELD(flags_round_type, MODE_HUMAN_ONLY))
+ SSpoints.prepare_supply_packs_list(CHECK_BITFIELD(round_type_flags, MODE_HUMAN_ONLY))
SSpoints.dropship_points = 0
SSpoints.supply_points[FACTION_TERRAGOV] = 0
@@ -122,6 +122,9 @@ GLOBAL_VAR(common_report) //Contains common part of roundend report
///Gamemode setup run after the game has started
/datum/game_mode/proc/post_setup()
addtimer(CALLBACK(src, PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME)
+ if(round_type_flags & MODE_FORCE_CUSTOMSQUAD_UI)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(send_global_signal), COMSIG_GLOB_DEPLOY_TIMELOCK_ENDED), deploy_time_lock)
+
if(!SSdbcore.Connect())
return
var/sql
@@ -168,10 +171,10 @@ GLOBAL_VAR(common_report) //Contains common part of roundend report
var/mob/living = player.transfer_character()
if(!living)
continue
-
qdel(player)
living.client.init_verbs()
living.notransform = TRUE
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAYER_ROUNDSTART_SPAWNED, living)
log_manifest(living.ckey, living.mind, living)
livings += living
@@ -262,11 +265,11 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
/datum/game_mode/proc/setup_blockers()
set waitfor = FALSE
- if(flags_round_type & MODE_LATE_OPENING_SHUTTER_TIMER)
+ if(round_type_flags & MODE_LATE_OPENING_SHUTTER_TIMER)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(send_global_signal), COMSIG_GLOB_OPEN_TIMED_SHUTTERS_LATE), SSticker.round_start_time + shutters_drop_time)
//Called late because there used to be shutters opened earlier. To re-add them just copy the logic.
- if(flags_round_type & MODE_XENO_SPAWN_PROTECT)
+ if(round_type_flags & MODE_XENO_SPAWN_PROTECT)
var/turf/T
while(length(GLOB.xeno_spawn_protection_locations))
T = GLOB.xeno_spawn_protection_locations[length(GLOB.xeno_spawn_protection_locations)]
@@ -385,6 +388,8 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
parts += "[GLOB.round_statistics.howitzer_shells_fired] howitzer shells were fired."
if(GLOB.round_statistics.rocket_shells_fired)
parts += "[GLOB.round_statistics.rocket_shells_fired] rocket artillery shells were fired."
+ if(GLOB.round_statistics.obs_fired)
+ parts += "[GLOB.round_statistics.obs_fired] orbital bombardements were fired."
if(GLOB.round_statistics.total_human_deaths[FACTION_TERRAGOV])
parts += "[GLOB.round_statistics.total_human_deaths[FACTION_TERRAGOV]] people were killed, among which [GLOB.round_statistics.total_human_revives[FACTION_TERRAGOV]] were revived and [GLOB.round_statistics.total_human_respawns] respawned. For a [(GLOB.round_statistics.total_human_revives[FACTION_TERRAGOV] / max(GLOB.round_statistics.total_human_deaths[FACTION_TERRAGOV], 1)) * 100]% revival rate and a [(GLOB.round_statistics.total_human_respawns / max(GLOB.round_statistics.total_human_deaths[FACTION_TERRAGOV], 1)) * 100]% respawn rate."
if(SSevacuation.human_escaped)
@@ -469,13 +474,11 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
if(GLOB.round_statistics.points_from_research)
parts += "[GLOB.round_statistics.points_from_research] requisitions points gained from research."
if(length(GLOB.round_statistics.req_items_produced))
+ parts += "" // make it special from other stats above
parts += "Requisitions produced: "
for(var/atom/movable/path AS in GLOB.round_statistics.req_items_produced)
- parts += "[GLOB.round_statistics.req_items_produced[path]] [initial(path.name)]"
- if(path == GLOB.round_statistics.req_items_produced[length(GLOB.round_statistics.req_items_produced)]) //last element
- parts += "."
- else
- parts += ","
+ var/last = GLOB.round_statistics.req_items_produced[length(GLOB.round_statistics.req_items_produced)]
+ parts += "[GLOB.round_statistics.req_items_produced[path]] [initial(path.name)][last ? "." : ","]"
if(length(parts))
return "
[parts.Join(" ")]
"
@@ -586,6 +589,7 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
player.create_character()
SSjob.spawn_character(player, TRUE)
player.mind.transfer_to(player.new_character, TRUE)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAYER_LATE_SPAWNED, player.new_character)
log_manifest(player.new_character.ckey, player.new_character.mind, player.new_character, latejoin = TRUE)
var/datum/job/job = player.assigned_role
job.on_late_spawn(player.new_character)
@@ -957,7 +961,7 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
/// Displays your position in the larva queue and how many burrowed larva there are, if applicable
/datum/game_mode/proc/handle_larva_timer(datum/dcs, mob/source, list/items)
- if(!(flags_round_type & MODE_INFESTATION))
+ if(!(round_type_flags & MODE_INFESTATION))
return
var/larva_position = SEND_SIGNAL(source.client, COMSIG_CLIENT_GET_LARVA_QUEUE_POSITION)
if (larva_position) // If non-zero, we're in queue
@@ -976,3 +980,7 @@ GLOBAL_LIST_INIT(bioscan_locations, list(
items += "Xeno respawn timer: READY"
else
items += "Xeno respawn timer: [(status_value / 60) % 60]:[add_leading(num2text(status_value % 60), 2, "0")]"
+
+///Returns a list of verbs to give ghosts in this gamemode
+/datum/game_mode/proc/ghost_verbs(mob/dead/observer/observer)
+ return
diff --git a/code/datums/gamemodes/campaign.dm b/code/datums/gamemodes/campaign.dm
index 9d0898b9346f3..07920127e09cc 100644
--- a/code/datums/gamemodes/campaign.dm
+++ b/code/datums/gamemodes/campaign.dm
@@ -1,34 +1,36 @@
/datum/game_mode/hvh/campaign
name = "Campaign"
config_tag = "Campaign"
- flags_round_type = MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY
+ round_type_flags = MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY
whitelist_ship_maps = list(MAP_ITERON)
whitelist_ground_maps = list(MAP_FORT_PHOBOS)
bioscan_interval = 3 MINUTES
valid_job_types = list(
- /datum/job/terragov/command/captain/campaign = 1,
- /datum/job/terragov/command/staffofficer/campaign = 2,
- /datum/job/terragov/command/fieldcommander/campaign = 1,
- /datum/job/terragov/squad/engineer = 4,
+ /datum/job/terragov/squad/standard = -1,
/datum/job/terragov/squad/corpsman = 8,
+ /datum/job/terragov/squad/engineer = 4,
/datum/job/terragov/squad/smartgunner = 4,
/datum/job/terragov/squad/leader = 4,
- /datum/job/terragov/squad/standard = -1,
- /datum/job/som/command/commander = 1,
- /datum/job/som/command/staffofficer = 2,
- /datum/job/som/command/fieldcommander = 1,
- /datum/job/som/squad/leader = 4,
- /datum/job/som/squad/veteran = 2,
- /datum/job/som/squad/engineer = 4,
- /datum/job/som/squad/medic = 8,
+ /datum/job/terragov/command/fieldcommander/campaign = 1,
+ /datum/job/terragov/command/staffofficer/campaign = 2,
+ /datum/job/terragov/command/captain/campaign = 1,
/datum/job/som/squad/standard = -1,
+ /datum/job/som/squad/medic = 8,
+ /datum/job/som/squad/engineer = 4,
+ /datum/job/som/squad/veteran = 4,
+ /datum/job/som/squad/leader = 4,
+ /datum/job/som/command/fieldcommander = 1,
+ /datum/job/som/command/staffofficer = 2,
+ /datum/job/som/command/commander = 1,
)
///The current mission type being played
var/datum/campaign_mission/current_mission
///campaign stats organised by faction
var/list/datum/faction_stats/stat_list = list()
- ///List of death times by key. Used for respawn time
+ ///List of death times by ckey. Used for respawn time
var/list/player_death_times = list()
+ ///List of timers to auto open the respawn window
+ var/list/respawn_timers = list()
/datum/game_mode/hvh/campaign/announce()
to_chat(world, "The current game mode is - Campaign!")
@@ -41,7 +43,7 @@
. = ..()
for(var/faction in factions)
stat_list[faction] = new /datum/faction_stats(faction)
- RegisterSignal(SSdcs, COMSIG_LIVING_JOB_SET, PROC_REF(register_faction_member))
+ RegisterSignals(SSdcs, list(COMSIG_GLOB_PLAYER_ROUNDSTART_SPAWNED, COMSIG_GLOB_PLAYER_LATE_SPAWNED), PROC_REF(register_faction_member))
RegisterSignals(SSdcs, list(COMSIG_GLOB_MOB_DEATH, COMSIG_MOB_GHOSTIZE), PROC_REF(set_death_time))
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_ENDED, PROC_REF(cut_death_list_timer))
addtimer(CALLBACK(SSticker.mode, TYPE_PROC_REF(/datum/game_mode/hvh/campaign, intro_sequence)), SSticker.round_start_time + 1 MINUTES)
@@ -64,8 +66,8 @@
return respawnee.respawn()
var/respawn_delay = CAMPAIGN_RESPAWN_TIME + stat_list[respawnee.faction]?.respawn_delay_modifier
- if((player_death_times[respawnee.key] + respawn_delay) > world.time)
- to_chat(respawnee, "Respawn timer has [round((player_death_times[respawnee.key] + respawn_delay - world.time) / 10)] seconds remaining.")
+ if((player_death_times[respawnee.ckey] + respawn_delay) > world.time)
+ to_chat(respawnee, "Respawn timer has [round((player_death_times[respawnee.ckey] + respawn_delay - world.time) / 10)] seconds remaining.")
return
attempt_attrition_respawn(respawnee)
@@ -122,13 +124,68 @@
continue
stat_list[i].get_status_tab_items(source, items)
+/datum/game_mode/hvh/campaign/ghost_verbs(mob/dead/observer/observer)
+ return list(/datum/action/campaign_overview, /datum/action/campaign_loadout)
///sets up the newly selected mission
/datum/game_mode/hvh/campaign/proc/load_new_mission(datum/campaign_mission/new_mission)
current_mission = new_mission
+ addtimer(CALLBACK(src, PROC_REF(autobalance_cycle)), CAMPAIGN_AUTOBALANCE_DELAY) //we autobalance teams after a short delay to account for slow respawners
current_mission.load_mission()
TIMER_COOLDOWN_START(src, COOLDOWN_BIOSCAN, bioscan_interval)
+///Checks team balance and tries to correct if possible
+/datum/game_mode/hvh/campaign/proc/autobalance_cycle()
+ var/list/autobalance_faction_list = autobalance_check()
+ if(!autobalance_faction_list)
+ return
+
+ for(var/mob/living/carbon/human/faction_member AS in GLOB.alive_human_list_faction[autobalance_faction_list[1]])
+ if(stat_list[faction_member.faction].faction_leader == faction_member)
+ continue
+ swap_player_team(faction_member, autobalance_faction_list[2])
+
+ addtimer(CALLBACK(src, PROC_REF(autobalance_bonus)), CAMPAIGN_AUTOBALANCE_DECISION_TIME + 1 SECONDS)
+
+/** Checks team balance
+ * Returns null if teams are nominally balanced
+ * Returns a list with the stronger team first if they are inbalanced
+ */
+/datum/game_mode/hvh/campaign/proc/autobalance_check(ratio = MAX_UNBALANCED_RATIO_TWO_HUMAN_FACTIONS)
+ var/team_one_count = length(GLOB.alive_human_list_faction[factions[1]])
+ var/team_two_count = length(GLOB.alive_human_list_faction[factions[2]])
+
+ if(team_one_count > team_two_count * ratio)
+ return list(factions[1], factions[2])
+ else if(team_two_count > team_one_count * ratio)
+ return list(factions[2], factions[1])
+
+///Actually swaps the player to the other team, unless balance has been restored
+/datum/game_mode/hvh/campaign/proc/swap_player_team(mob/living/carbon/human/user, new_faction)
+ if(tgui_alert(user, "The teams are currently imbalanced, in favour of your team.", "Join the other team?", list("Stay on team", "Change team"), CAMPAIGN_AUTOBALANCE_DECISION_TIME, FALSE) != "Change team")
+ return
+ var/list/current_ratio = autobalance_check(1)
+ if(!current_ratio || current_ratio[2] == user.faction)
+ to_chat(user, span_warning("Team balance already corrected."))
+ return
+ LAZYREMOVE(GLOB.alive_human_list_faction[user.faction], user)
+ user.faction = new_faction //we set this first so the ghost's faction and subsequent job screen is correct, but it means we have to remove from the faction list above first.
+ var/mob/dead/observer/ghost = user.ghostize()
+ user.job.add_job_positions(1)
+ qdel(user)
+ var/datum/individual_stats/new_stats = stat_list[new_faction].get_player_stats(ghost)
+ new_stats.give_funds(max(stat_list[new_faction].accumulated_mission_reward * 0.5, 200)) //Added credits for swapping team
+ player_respawn(ghost) //auto open the respawn screen
+
+///buffs the weaker team if players don't voluntarily switch
+/datum/game_mode/hvh/campaign/proc/autobalance_bonus()
+ var/list/autobalance_faction_list = autobalance_check()
+ if(!autobalance_faction_list)
+ return
+
+ var/autobal_num = ROUND_UP((length(GLOB.alive_human_list_faction[autobalance_faction_list[1]]) - length(GLOB.alive_human_list_faction[autobalance_faction_list[2]])) * 0.2)
+ current_mission.spawn_mech(autobalance_faction_list[2], 0, 0, autobal_num, "[autobal_num] additional mechs granted for autobalance")
+
//respawn stuff
///Records the players death time for respawn time purposes
@@ -140,16 +197,32 @@
return
if(!(player.faction in factions))
return
- player_death_times[player.key] = world.time
+ player_death_times[player.ckey] = world.time
+ respawn_timers[player.ckey] = addtimer(CALLBACK(src, PROC_REF(auto_attempt_respawn), player.ckey), CAMPAIGN_RESPAWN_TIME + stat_list[player.faction]?.respawn_delay_modifier + 1, TIMER_STOPPABLE)
+
+///Auto pops up the respawn window
+/datum/game_mode/hvh/campaign/proc/auto_attempt_respawn(respawnee_ckey)
+ for(var/mob/player AS in GLOB.player_list)
+ if(player.ckey != respawnee_ckey)
+ continue
+ respawn_timers[respawnee_ckey] = null
+ if(isliving(player) && player.stat != DEAD)
+ return
+ player_respawn(player)
+ return
///Wrapper for cutting the deathlist via timer due to the players not immediately returning to base
/datum/game_mode/hvh/campaign/proc/cut_death_list_timer(datum/source)
SIGNAL_HANDLER
addtimer(CALLBACK(src, PROC_REF(cut_death_list)), AFTER_MISSION_TELEPORT_DELAY + 1)
-///cuts the death time list at mission end
+///cuts the death time and respawn_timers list at mission end
/datum/game_mode/hvh/campaign/proc/cut_death_list(datum/source)
player_death_times.Cut()
+ for(var/ckey in respawn_timers)
+ auto_attempt_respawn(ckey) //Faction datum doesn't pop up for ghosts
+ deltimer(respawn_timers[ckey])
+ respawn_timers.Cut()
///respawns the player if attrition points are available
/datum/game_mode/hvh/campaign/proc/attempt_attrition_respawn(mob/candidate)
@@ -270,15 +343,6 @@
SIGNAL_HANDLER
if(!(new_member.faction in factions))
return
- add_verb(new_member, /mob/living/proc/open_faction_stats_ui)
-///Opens up the players campaign status UI
-/mob/living/proc/open_faction_stats_ui()
- set name = "Campaign Status"
- set desc = "Check the status of your faction in the campaign."
- set category = "IC"
-
- var/datum/faction_stats/your_faction = GLOB.faction_stats_datums[faction]
- if(!your_faction)
- return
- your_faction.interact(src)
+ var/datum/action/campaign_overview/overview = new
+ overview.give_action(new_member)
diff --git a/code/datums/gamemodes/campaign/campaign_assets.dm b/code/datums/gamemodes/campaign/campaign_assets.dm
index 120ba6525fda4..47abfeb86cb0c 100644
--- a/code/datums/gamemodes/campaign/campaign_assets.dm
+++ b/code/datums/gamemodes/campaign/campaign_assets.dm
@@ -30,6 +30,8 @@
var/detailed_desc = "This is a placeholder asset. You shouldn't see this, it does nothing at all."
///The faction associated with these stats
var/datum/faction_stats/faction
+ ///Specific portrait used when activating this asset. Defaults to faction default if not specified
+ var/asset_portrait = null
///asset related flags
var/asset_flags = ASSET_ACTIVATED_EFFECT
///Number of times this can be used
@@ -45,9 +47,12 @@
///Feedback message if this asset is unusable during this mission
var/blacklist_message = "Unavailable during this mission."
-/datum/campaign_asset/New(datum/faction_stats/winning_faction)
+/datum/campaign_asset/New(datum/faction_stats/new_faction)
. = ..()
- faction = winning_faction
+ if(!istype(new_faction))
+ return qdel(src)
+ SEND_SIGNAL(new_faction, COMSIG_CAMPAIGN_NEW_ASSET, src)
+ faction = new_faction
if(asset_flags & ASSET_IMMEDIATE_EFFECT)
immediate_effect()
if(asset_flags & ASSET_PASSIVE_EFFECT)
@@ -65,8 +70,8 @@
immediate_effect()
///Handles the activated asset process
-/datum/campaign_asset/proc/attempt_activatation(mob/user)
- if(activation_checks(user))
+/datum/campaign_asset/proc/attempt_activatation(mob/user, check_override = FALSE)
+ if(!check_override && activation_checks(user))
return FALSE
activated_effect()
diff --git a/code/datums/gamemodes/campaign/campaign_mission.dm b/code/datums/gamemodes/campaign/campaign_mission.dm
index 7c218fef78e25..15a50058ddd73 100644
--- a/code/datums/gamemodes/campaign/campaign_mission.dm
+++ b/code/datums/gamemodes/campaign/campaign_mission.dm
@@ -21,7 +21,7 @@
MISSION_HOSTILE_FACTION = 0,
)
///Any mission behavior flags
- var/mission_flags = null
+ var/mission_flags = NONE
///faction that chose the mission
var/starting_faction
///faction that did not choose the mission
@@ -66,21 +66,30 @@
MISSION_OUTCOME_MINOR_LOSS = list(0, 0),
MISSION_OUTCOME_MAJOR_LOSS = list(0, 0),
)
+ ///cash rewards for the mission type
+ var/list/cash_rewards = list(
+ MISSION_OUTCOME_MAJOR_VICTORY = list(700, 500),
+ MISSION_OUTCOME_MINOR_VICTORY = list(600, 500),
+ MISSION_OUTCOME_DRAW = list(500, 500),
+ MISSION_OUTCOME_MINOR_LOSS = list(500, 600),
+ MISSION_OUTCOME_MAJOR_LOSS = list(500, 700),
+ )
/// Timer used to calculate how long till mission ends
var/game_timer
///The length of time until mission ends, if timed
- var/max_game_time = null
+ var/max_game_time = 0
///Whether the max game time has been reached
var/max_time_reached = FALSE
///Delay before the mission actually starts
- var/mission_start_delay = 3 MINUTES
+ var/mission_start_delay = 1.5 MINUTES
///Delay from shutter drop until game TIMER starts
- var/game_timer_delay = 3 MINUTES
+ var/game_timer_delay = 1 MINUTES
///Map text intro message for the start of the mission
var/list/intro_message = list(
MISSION_STARTING_FACTION = "starting faction intro text here",
MISSION_HOSTILE_FACTION = "hostile faction intro text here",
)
+ ///Message to players when a mission ends
var/list/outro_message = list(
MISSION_OUTCOME_MAJOR_VICTORY = list(
MISSION_STARTING_FACTION = "Major victory All mission objectives achieved, outstanding work!",
@@ -108,15 +117,15 @@
///Operation name for hostile faction
var/op_name_hostile
///Possible rewards for a major victory, used by Generate_rewards()
- var/list/major_victory_reward_table = list()
+ var/list/major_victory_reward_table
///Possible rewards for a minor victory, used by Generate_rewards()
- var/list/minor_victory_reward_table = list()
+ var/list/minor_victory_reward_table
///Possible rewards for a minor loss, used by Generate_rewards()
- var/list/minor_loss_reward_table = list()
+ var/list/minor_loss_reward_table
///Possible rewards for a major loss, used by Generate_rewards()
- var/list/major_loss_reward_table = list()
+ var/list/major_loss_reward_table
///Possible rewards for a draw, used by Generate_rewards()
- var/list/draw_reward_table = list()
+ var/list/draw_reward_table
/datum/campaign_mission/New(initiating_faction)
. = ..()
@@ -135,6 +144,7 @@
op_name_hostile = GLOB.operation_namepool[/datum/operation_namepool].get_random_name()
load_mission_brief() //late loaded so we can ref the specific factions etc
+ set_loot_tables()
/datum/campaign_mission/Destroy(force, ...)
STOP_PROCESSING(SSslowprocess, src)
@@ -148,6 +158,22 @@
end_mission()
return PROCESS_KILL
+///Sets up the loot tables for this mission, if required
+/datum/campaign_mission/proc/set_loot_tables()
+ if(starting_faction == FACTION_TERRAGOV)
+ major_victory_reward_table = GLOB.campaign_tgmc_major_loot
+ minor_victory_reward_table = GLOB.campaign_tgmc_minor_loot
+ else if(starting_faction == FACTION_SOM)
+ major_victory_reward_table = GLOB.campaign_som_major_loot
+ minor_victory_reward_table = GLOB.campaign_som_minor_loot
+
+ if(hostile_faction == FACTION_TERRAGOV)
+ minor_loss_reward_table = GLOB.campaign_tgmc_minor_loot
+ major_loss_reward_table = GLOB.campaign_tgmc_major_loot
+ else if(hostile_faction == FACTION_SOM)
+ minor_loss_reward_table = GLOB.campaign_som_minor_loot
+ major_loss_reward_table = GLOB.campaign_som_major_loot
+
///Sets up the mission once it has been selected
/datum/campaign_mission/proc/load_mission()
play_selection_intro()
@@ -181,7 +207,7 @@
if(max_time_reached)
items += "Mission status: Mission complete"
items += ""
- else if(game_timer)
+ else
items += "Mission time remaining: [mission_end_countdown()]"
items += ""
@@ -216,6 +242,9 @@
if(MISSION_OUTCOME_DRAW)
reward_table = draw_reward_table
+ if(!length(reward_table))
+ return
+
for(var/i = 1 to reward_amount)
var/obj/reward = pickweight(reward_table)
new reward(get_turf(pick(GLOB.campaign_reward_spawners[faction])))
@@ -226,16 +255,35 @@
///sets up the timer for the mission
/datum/campaign_mission/proc/set_mission_timer()
- if(!iscampaigngamemode(SSticker.mode))
+ if(game_timer)
return
-
game_timer = addtimer(VARSET_CALLBACK(src, max_time_reached, TRUE), max_game_time, TIMER_STOPPABLE)
+///Pauses the gametimer, recording the remaining time left in max_game_time
+/datum/campaign_mission/proc/pause_mission_timer(trait_source = TRAIT_GENERIC)
+ if(!trait_source)
+ trait_source = TRAIT_GENERIC
+ ADD_TRAIT(src, CAMPAIGN_MISSION_TIMER_PAUSED, trait_source)
+ if(!game_timer)
+ return
+ max_game_time = timeleft(game_timer)
+ deltimer(game_timer)
+ game_timer = null
+
+///Attempts to resume the gametimer
+/datum/campaign_mission/proc/resume_mission_timer(trait_source = TRAIT_GENERIC, forced = FALSE)
+ REMOVE_TRAIT(src, CAMPAIGN_MISSION_TIMER_PAUSED, trait_source)
+ if(!forced && HAS_TRAIT(src, CAMPAIGN_MISSION_TIMER_PAUSED))
+ return
+ set_mission_timer()
+
///accesses the timer for status panel
/datum/campaign_mission/proc/mission_end_countdown()
- if(max_time_reached)
- return "Mission finished"
- var/eta = timeleft(game_timer) * 0.1
+ //if(max_time_reached)
+ // return "Mission finished"
+ if(!game_timer && HAS_TRAIT(src, CAMPAIGN_MISSION_TIMER_PAUSED))
+ return "Timer paused"
+ var/eta = game_timer ? (timeleft(game_timer) * 0.1) : (max_game_time * 0.1)
if(eta > 0)
return "[(eta / 60) % 60]:[add_leading(num2text(eta % 60), 2, "0")]"
@@ -276,6 +324,16 @@
for(var/i in GLOB.quick_loadouts)
var/datum/outfit/quick/outfit = GLOB.quick_loadouts[i]
outfit.quantity = initial(outfit.quantity)
+ for(var/job in GLOB.campaign_loadout_items_by_role)
+ for(var/datum/loadout_item/loadout_item AS in GLOB.campaign_loadout_items_by_role[job])
+ loadout_item.quantity = initial(loadout_item.quantity)
+ for(var/mob/living/carbon/human/corpse AS in GLOB.dead_human_list) //clean up all the bodies and refund normal roles if required
+ if(corpse.z != mission_z_level.z_value)
+ continue
+ if(!HAS_TRAIT(corpse, TRAIT_UNDEFIBBABLE) && corpse.job.job_cost)
+ corpse.job.free_job_positions(1)
+
+ qdel(corpse)
///Unregisters all signals when the mission finishes
/datum/campaign_mission/proc/unregister_mission_signals()
@@ -321,6 +379,7 @@
modify_attrition_points(attrition_point_rewards[outcome][1], attrition_point_rewards[outcome][2])
apply_victory_points(victory_point_rewards[outcome][1], victory_point_rewards[outcome][2])
+ apply_cash_reward(cash_rewards[outcome][1], cash_rewards[outcome][2])
//reset attrition points - unused points are lost
mode.stat_list[starting_faction].active_attrition_points = 0
@@ -356,6 +415,11 @@
mode.stat_list[starting_faction].total_attrition_points += start_team_points
mode.stat_list[hostile_faction].total_attrition_points += hostile_team_points
+///applies mission cash bonuses to both factions
+/datum/campaign_mission/proc/apply_cash_reward(start_team_cash, hostile_team_cash)
+ mode.stat_list[starting_faction].apply_cash(start_team_cash)
+ mode.stat_list[hostile_faction].apply_cash(hostile_team_cash)
+
///checks how many marines and SOM are still alive
/datum/campaign_mission/proc/count_humans(list/z_levels = SSmapping.levels_by_trait(ZTRAIT_AWAY), count_flags) //todo: make new Z's not away levels, or ensure ground and away is consistant in behavior
var/list/team_one_alive = list()
@@ -437,7 +501,7 @@
GLOB.campaign_structures -= mission_obj
///spawns mechs for a faction
-/datum/campaign_mission/proc/spawn_mech(mech_faction, heavy_mech, medium_mech, light_mech)
+/datum/campaign_mission/proc/spawn_mech(mech_faction, heavy_mech, medium_mech, light_mech, override_message)
if(!mech_faction)
return
var/total_count = (heavy_mech + medium_mech + light_mech)
@@ -457,4 +521,11 @@
GLOB.campaign_structures += new_mech
RegisterSignal(new_mech, COMSIG_QDELETING, TYPE_PROC_REF(/datum/campaign_mission, remove_mission_object))
- map_text_broadcast(mech_faction, "[total_count] mechs have been deployed for this mission.", "Mechs available")
+ map_text_broadcast(mech_faction, override_message ? override_message : "[total_count] mechs have been deployed for this mission.", "Mechs available")
+
+///Returns the current mission, if its the campaign gamemode
+/proc/get_current_mission()
+ if(!iscampaigngamemode(SSticker.mode))
+ return null
+ var/datum/game_mode/hvh/campaign/mode = SSticker.mode
+ return mode.current_mission
diff --git a/code/datums/gamemodes/campaign/faction_stats.dm b/code/datums/gamemodes/campaign/faction_stats.dm
index 6b058f9a8131c..49f01727408d8 100644
--- a/code/datums/gamemodes/campaign/faction_stats.dm
+++ b/code/datums/gamemodes/campaign/faction_stats.dm
@@ -45,14 +45,14 @@ GLOBAL_LIST_INIT(campaign_default_purchasable_assets, list(
/datum/campaign_asset/teleporter_charges,
/datum/campaign_asset/teleporter_enabled,
/datum/campaign_asset/equipment/medkit_basic/som,
- /datum/campaign_asset/equipment/materials_pack,
+ /datum/campaign_asset/equipment/materials_pack/som,
/datum/campaign_asset/equipment/ballistic_som,
/datum/campaign_asset/equipment/shotguns_som,
/datum/campaign_asset/equipment/volkite,
/datum/campaign_asset/equipment/heavy_armour_som,
/datum/campaign_asset/equipment/shields_som,
/datum/campaign_asset/equipment/grenades_som,
- /datum/campaign_asset/equipment/at_mines,
+ /datum/campaign_asset/equipment/at_mines/som,
/datum/campaign_asset/equipment/tac_bino_som,
/datum/campaign_asset/tactical_reserves,
),
@@ -66,9 +66,10 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
/datum/campaign_mission/tdm/mech_wars = 12,
/datum/campaign_mission/destroy_mission/supply_raid = 15,
/datum/campaign_mission/destroy_mission/base_rescue = 12,
+ /datum/campaign_mission/raiding_base = 6,
),
FACTION_SOM = list(
- /datum/campaign_mission/tdm/lv624 = 10,
+ /datum/campaign_mission/tdm/orion = 10,
/datum/campaign_mission/destroy_mission/fire_support_raid/som = 15,
/datum/campaign_mission/tdm/mech_wars/som = 12,
/datum/campaign_mission/destroy_mission/supply_raid/som = 15,
@@ -90,7 +91,7 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
var/active_attrition_points = 0
///Multiplier on the passive attrition point gain for this faction
var/attrition_gain_multiplier = 1
- ///cumulative loss bonus which is applied to attrition gain mult
+ ///cumulative loss bonus which is applied to attrition gain mult and player credit mission reward
var/loss_bonus = 0
///Future missions this faction can currently choose from
var/list/datum/campaign_mission/available_missions = list()
@@ -103,9 +104,13 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
///Any special behavior flags for the faction
var/stats_flags = NONE
///Portrait used for general screen text notifications
- var/atom/movable/screen/text/screen_text/picture/faction_portrait
+ var/faction_portrait
///Faction-wide modifier to respawn delay
var/respawn_delay_modifier = 0
+ ///records how much currency has been earned from missions, for late join players
+ var/accumulated_mission_reward = 0
+ ///list of individual stats by ckey
+ var/list/datum/individual_stats/individual_stat_list = list()
/datum/faction_stats/New(new_faction)
. = ..()
@@ -118,6 +123,7 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
for(var/i = 1 to CAMPAIGN_STANDARD_MISSION_QUANTITY)
generate_new_mission()
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_ENDED, PROC_REF(mission_end))
+ RegisterSignals(SSdcs, list(COMSIG_GLOB_PLAYER_ROUNDSTART_SPAWNED, COMSIG_GLOB_PLAYER_LATE_SPAWNED), PROC_REF(register_faction_member))
faction_portrait = GLOB.faction_to_portrait[faction] ? GLOB.faction_to_portrait[faction] : /atom/movable/screen/text/screen_text/picture/potrait/unknown
@@ -125,6 +131,32 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
GLOB.faction_stats_datums -= faction
return ..()
+///Sets up newly spawned players with the campaign status verb
+/datum/faction_stats/proc/register_faction_member(datum/source, mob/living/carbon/human/new_member)
+ SIGNAL_HANDLER
+ if(!ishuman(new_member))
+ return
+ if(new_member.faction != faction)
+ return
+ if(individual_stat_list[new_member.ckey])
+ individual_stat_list[new_member.ckey].current_mob = new_member
+ individual_stat_list[new_member.ckey].apply_perks()
+ else
+ get_player_stats(new_member)
+ var/datum/action/campaign_loadout/loadouts = new
+ loadouts.give_action(new_member)
+ if(!(new_member.job.job_cost))
+ return
+ loadouts.action_activate()
+
+///Returns a users individual stat datum, generating a new one if required
+/datum/faction_stats/proc/get_player_stats(mob/user)
+ if(!user.ckey)
+ return
+ if(!individual_stat_list[user.ckey])
+ individual_stat_list[user.ckey] = new /datum/individual_stats(user, faction, accumulated_mission_reward)
+ return individual_stat_list[user.ckey]
+
///Randomly adds a new mission to the available pool
/datum/faction_stats/proc/generate_new_mission()
if(!length(GLOB.campaign_mission_pool[faction]) || (length(available_missions) >= CAMPAIGN_STANDARD_MISSION_QUANTITY))
@@ -158,6 +190,8 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
for(var/mob/living/carbon/human/candidate AS in possible_candidates)
if(candidate.job.title != senior_rank)
continue
+ if(!candidate.client)
+ continue
senior_rank_list += candidate
if(!length(senior_rank_list))
senior_rank_list.Cut()
@@ -183,6 +217,11 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
faction_assets[new_asset] = new new_asset(src)
RegisterSignals(faction_assets[new_asset], list(COMSIG_CAMPAIGN_ASSET_ACTIVATION, COMSIG_CAMPAIGN_DISABLER_ACTIVATION), PROC_REF(force_update_static_data))
+///Removes an asset from a faction entirely
+/datum/faction_stats/proc/remove_asset(datum/campaign_asset/removed_asset)
+ if(faction_assets[removed_asset])
+ QDEL_NULL(faction_assets[removed_asset])
+
///handles post mission wrap up for the faction
/datum/faction_stats/proc/mission_end(datum/source, datum/campaign_mission/completed_mission, winning_faction)
SIGNAL_HANDLER
@@ -197,21 +236,38 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
generate_new_mission()
update_static_data_for_all_viewers()
- addtimer(CALLBACK(src, PROC_REF(return_to_base)), AFTER_MISSION_TELEPORT_DELAY)
+ addtimer(CALLBACK(src, PROC_REF(return_to_base), completed_mission), AFTER_MISSION_TELEPORT_DELAY)
addtimer(CALLBACK(src, PROC_REF(get_selector)), AFTER_MISSION_LEADER_DELAY) //if the leader died, we load a new one after a bit to give respawns some time
+///applies cash rewards to the faction and all individuals
+/datum/faction_stats/proc/apply_cash(amount)
+ if(!amount)
+ return
+ amount *= 1 + loss_bonus
+ accumulated_mission_reward += amount
+ for(var/i in individual_stat_list)
+ var/datum/individual_stats/player_stats = individual_stat_list[i]
+ player_stats.give_funds(amount)
+
///Returns all faction members back to base after the mission is completed
-/datum/faction_stats/proc/return_to_base()
+/datum/faction_stats/proc/return_to_base(datum/campaign_mission/completed_mission)
for(var/mob/living/carbon/human/human_mob AS in GLOB.alive_human_list_faction[faction])
- if(!human_mob.job.job_cost) //asset based roles are one use
- human_mob.ghostize()
- qdel(human_mob)
+ if((human_mob.z && human_mob.z != completed_mission.mission_z_level.z_value) && human_mob.job.job_cost && human_mob.client) //why is byond so cursed that being inside something makes you z = 0
+ human_mob.revive(TRUE)
+ human_mob.overlay_fullscreen_timer(0.5 SECONDS, 10, "roundstart1", /atom/movable/screen/fullscreen/black)
+ human_mob.overlay_fullscreen_timer(2 SECONDS, 20, "roundstart2", /atom/movable/screen/fullscreen/spawning_in)
+ human_mob.forceMove(pick(GLOB.spawns_by_job[human_mob.job.type]))
+ human_mob.Stun(1 SECONDS) //so you don't accidentally shoot your team etc
continue
- human_mob.revive(TRUE)
- human_mob.overlay_fullscreen_timer(0.5 SECONDS, 10, "roundstart1", /atom/movable/screen/fullscreen/black)
- human_mob.overlay_fullscreen_timer(2 SECONDS, 20, "roundstart2", /atom/movable/screen/fullscreen/spawning_in)
- human_mob.forceMove(pick(GLOB.spawns_by_job[human_mob.job.type]))
- human_mob.Stun(1 SECONDS) //so you don't accidentally shoot your team etc
+
+ var/mob/dead/observer/ghost = human_mob.ghostize()
+ if(human_mob.job.job_cost) //We don't refund ally roles
+ human_mob.job.add_job_positions(1)
+ qdel(human_mob)
+ if(!ghost) //if they ghosted already
+ return
+ var/datum/game_mode/mode = SSticker.mode
+ mode.player_respawn(ghost) //auto open the respawn screen
///Generates status tab info for the mission
/datum/faction_stats/proc/get_status_tab_items(mob/source, list/items)
@@ -240,6 +296,8 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
update_static_data_for_all_viewers()
//UI stuff//
+/datum/faction_stats/ui_assets(mob/user)
+ return list(get_asset_datum(/datum/asset/spritesheet/campaign/missions), get_asset_datum(/datum/asset/spritesheet/campaign/assets))
/datum/faction_stats/ui_interact(mob/living/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -249,6 +307,8 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
ui.open()
/datum/faction_stats/ui_state(mob/user)
+ if(isobserver(user))
+ return GLOB.always_state
return GLOB.conscious_state
/datum/faction_stats/ui_static_data(mob/living/user)
@@ -356,8 +416,6 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
data["victory_points"] = victory_points
data["max_victory_points"] = CAMPAIGN_MAX_VICTORY_POINTS
data["faction"] = faction
- data["icons"] = GLOB.campaign_icons
- data["mission_icons"] = GLOB.campaign_mission_icons
return data
@@ -371,6 +429,8 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
CRASH("campaign_mission loaded without campaign game mode")
var/mob/living/user = usr
+ if(!istype(user))
+ return
switch(action)
if("set_attrition_points")
@@ -380,12 +440,11 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
if((current_mode.current_mission?.mission_state != MISSION_STATE_NEW) && (current_mode.current_mission?.mission_state != MISSION_STATE_LOADED))
to_chat(user, "Current mission already ongoing, unable to assign more personnel at this time.")
return
- total_attrition_points += active_attrition_points
- active_attrition_points = 0 //reset, you can change your mind up until the mission starts
- var/choice = tgui_input_number(user, "How much manpower would you like to dedicate to this mission?", "Attrition Point selection", 0, total_attrition_points, 0, 60 SECONDS)
- if(!choice)
- choice = 0
- total_attrition_points -= choice
+ var/combined_attrition = total_attrition_points + active_attrition_points
+ var/choice = tgui_input_number(user, "How much manpower would you like to dedicate to this mission?", "Attrition Point selection", 0, combined_attrition, 0, 60 SECONDS)
+ combined_attrition = total_attrition_points + active_attrition_points //we do it again in case the amount has changed
+ choice = clamp(choice, 0, combined_attrition)
+ total_attrition_points = combined_attrition - choice
active_attrition_points = choice
for(var/mob/living/carbon/human/faction_member AS in GLOB.alive_human_list_faction[faction])
faction_member.playsound_local(null, 'sound/effects/CIC_order.ogg', 30, 1)
@@ -432,7 +491,8 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
return
for(var/mob/living/carbon/human/faction_member AS in GLOB.alive_human_list_faction[faction])
faction_member.playsound_local(null, 'sound/effects/CIC_order.ogg', 30, 1)
- faction_member.play_screen_text("OVERWATCH " + "[choice.name] asset activated", faction_portrait)
+ var/portrait = choice.asset_portrait ? choice.asset_portrait : faction_portrait
+ faction_member.play_screen_text("OVERWATCH " + "[choice.name] asset activated", portrait)
to_chat(faction_member, "[user] has activated the [choice.name] campaign asset.")
return TRUE
@@ -455,3 +515,14 @@ GLOBAL_LIST_INIT(campaign_mission_pool, list(
to_chat(faction_member, "[user] has purchased the [initial(selected_asset.name)] campaign asset.")
update_static_data_for_all_viewers()
return TRUE
+
+//overview for campaign gamemode
+/datum/action/campaign_overview
+ name = "Campaign overview"
+ action_icon_state = "campaign_overview"
+
+/datum/action/campaign_overview/action_activate()
+ var/datum/faction_stats/your_faction = GLOB.faction_stats_datums[owner.faction]
+ if(!your_faction)
+ return
+ your_faction.interact(owner)
diff --git a/code/datums/gamemodes/campaign/individual_stats.dm b/code/datums/gamemodes/campaign/individual_stats.dm
new file mode 100644
index 0000000000000..57ae70628ea08
--- /dev/null
+++ b/code/datums/gamemodes/campaign/individual_stats.dm
@@ -0,0 +1,424 @@
+#define TAB_LOADOUT "Loadout"
+#define TAB_PERKS "Perks"
+
+/datum/individual_stats
+ interaction_flags = INTERACT_UI_INTERACT
+ var/owner_ckey
+ ///currently occupied mob - if any
+ var/mob/living/carbon/current_mob
+ ///Credits. You buy stuff with it
+ var/currency = 450
+ ///List of job types based on faction
+ var/list/valid_jobs = list()
+ ///Single list of unlocked perks for easy reference
+ var/list/unlocked_perks = list()
+ ///Unlocked perks organised by jobs effected
+ var/list/list/datum/perk/perks_by_job = list()
+ ///Unlocked items
+ var/list/list/datum/loadout_item/unlocked_items = list()
+ ///List of loadouts by role
+ var/list/datum/outfit_holder/loadouts = list()
+ ///The faction associated with these stats
+ var/faction
+ ///Currently selected UI category tab
+ var/selected_tab = TAB_LOADOUT
+ ///Currently selected UI job tab
+ var/selected_job
+
+/datum/individual_stats/New(mob/living/carbon/new_mob, new_faction, new_currency)
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_ENDED, PROC_REF(post_mission_credits))
+ owner_ckey = new_mob.ckey
+ current_mob = new_mob
+ faction = new_faction
+ currency += new_currency
+ for(var/datum/job/job_type AS in SSticker.mode.valid_job_types)
+ if(job_type::faction != faction)
+ continue
+ valid_jobs += job_type::title
+ loadouts[job_type::title] = new /datum/outfit_holder(job_type::title)
+ perks_by_job[job_type::title] = list()
+ unlocked_items[job_type::title] = list()
+
+/datum/individual_stats/Destroy(force, ...)
+ current_mob = null
+ unlocked_perks = null
+ perks_by_job = null
+ unlocked_items = null
+ return ..()
+
+///Pay each player additional credits based on individual performance during the mission
+/datum/individual_stats/proc/post_mission_credits(datum/source)
+ SIGNAL_HANDLER
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[owner_ckey]
+ give_funds(personal_statistics.get_mission_reward())
+
+///Applies cash
+/datum/individual_stats/proc/give_funds(amount)
+ currency += amount
+ if(!current_mob)
+ return
+ to_chat(current_mob, span_warning("You have received a cash bonus of [amount]."))
+
+///uses some funtokens, returns the amount missing, if insufficient funds
+/datum/individual_stats/proc/use_funds(amount)
+ if(amount > currency)
+ return amount - currency
+ currency -= amount
+
+///Adds a perk if able
+/datum/individual_stats/proc/purchase_perk(datum/perk/new_perk, mob/living/user)
+ . = TRUE
+ if(!istype(new_perk))
+ return FALSE
+ if(new_perk in unlocked_perks)
+ to_chat(user, span_warning("Perk already purchased."))
+ return FALSE
+ if(length(new_perk.prereq_perks))
+ var/perk_found
+ for(var/prereq in new_perk.prereq_perks)
+ perk_found = FALSE
+ for(var/datum/perk/perk AS in unlocked_perks)
+ if(perk.type != prereq)
+ continue
+ perk_found = TRUE
+ if(!perk_found)
+ to_chat(user, span_warning("One or more prerequisites missing for this perk."))
+ return FALSE
+ if(use_funds(new_perk.unlock_cost))
+ to_chat(user, span_warning("Insufficient funds for this perk."))
+ return FALSE
+
+ new_perk.unlock_bonus(user, src)
+ unlocked_perks += new_perk
+ for(var/supported_job in new_perk.jobs_supported)
+ if(!perks_by_job[supported_job])
+ continue
+ perks_by_job[supported_job] += new_perk
+
+ if(!istype(user)) //we immediately apply the perk where possible
+ return
+ if(!(user.job.title in new_perk.jobs_supported))
+ return
+ new_perk.apply_perk(user)
+
+///Unlocks a loadout item for use
+/datum/individual_stats/proc/unlock_loadout_item(item_type, job_type_or_types, mob/user, cost_override, job_req_override = FALSE)
+ if(!islist(job_type_or_types))
+ job_type_or_types = list(job_type_or_types)
+ var/datum/loadout_item/item = GLOB.campaign_loadout_item_type_list[item_type]
+ if(!istype(item))
+ return FALSE
+ var/insufficient_credits = use_funds(isnum(cost_override) ? cost_override : item.unlock_cost)
+ if(insufficient_credits)
+ to_chat(user, span_warning("Requires [insufficient_credits] more credits."))
+ return FALSE
+ for(var/job_type in job_type_or_types)
+ if(!job_req_override && !(job_type in item.jobs_supported))
+ continue
+ loadouts[job_type]?.unlock_new_option(item)
+ return TRUE
+
+///Adds an item to the unlockable list for a job
+/datum/individual_stats/proc/make_available_loadout_item(item_type, job_type_or_types, mob/user, job_req_override = FALSE)
+ if(!islist(job_type_or_types))
+ job_type_or_types = list(job_type_or_types)
+ var/datum/loadout_item/item = GLOB.campaign_loadout_item_type_list[item_type]
+ if(!istype(item))
+ return FALSE
+ for(var/job_type in job_type_or_types)
+ if(!job_req_override && !(job_type in item.jobs_supported))
+ continue
+ loadouts[job_type]?.allow_new_option(item)
+ return TRUE
+
+///Adds and equips a loadout item, replacing another
+/datum/individual_stats/proc/replace_loadout_option(new_item, removed_item, job_type_or_types, job_req_override = FALSE)
+ if(!islist(job_type_or_types))
+ job_type_or_types = list(job_type_or_types)
+ var/datum/loadout_item/item = GLOB.campaign_loadout_item_type_list[new_item]
+ if(!istype(item))
+ return FALSE
+ for(var/job_type in job_type_or_types)
+ if(!job_req_override && !(job_type in item.jobs_supported))
+ continue
+ loadouts[job_type]?.unlock_new_option(item)
+ if(loadouts[job_type]?.remove_option(GLOB.campaign_loadout_item_type_list[removed_item]))
+ loadouts[job_type].attempt_equip_loadout_item(item)
+ return TRUE
+
+///Applies all perks to a mob
+/datum/individual_stats/proc/apply_perks()
+ if(!current_mob || QDELETED(current_mob))
+ return
+ for(var/datum/perk/perk AS in perks_by_job[current_mob.job.title])
+ perk.apply_perk(current_mob)
+
+//UI stuff
+/datum/individual_stats/ui_assets(mob/user)
+ return list(get_asset_datum(/datum/asset/spritesheet/campaign/perks), get_asset_datum(/datum/asset/spritesheet/campaign/loadout_items))
+
+/datum/individual_stats/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(ui)
+ return
+ ui = new(user, src, "IndividualStats")
+ ui.open()
+
+/datum/individual_stats/ui_state(mob/user)
+ if(isobserver(user))
+ return GLOB.always_state
+ return GLOB.conscious_state
+
+/datum/individual_stats/ui_data(mob/user)
+ var/datum/game_mode/hvh/campaign/current_mode = SSticker.mode
+ if(!istype(current_mode))
+ CRASH("campaign_mission loaded without campaign game mode")
+
+ var/list/data = list()
+ var/mob/living/living_user = user
+ data["current_job"] = istype(living_user) ? living_user.job.title : null
+ data["currency"] = currency
+
+ if(selected_tab != TAB_LOADOUT)
+ return data
+ //This cannot be static data due to the limitations on how frequently static data can be updated, and clicking on loadout options requires a data update.
+ var/list/equipped_loadouts_data = list() //items currently equipped to ALL job outfits
+ var/list/available_loadouts_data = list() //all available AND purchasable loadout options
+ var/list/outfit_cost_data = list() //Current cost of all outfits
+
+ var/datum/outfit_holder/outfit = loadouts[selected_job]
+
+ var/list/outfit_cost_list = list()
+ outfit_cost_list["job"] = selected_job
+ outfit_cost_list["outfit_cost"] = outfit.loadout_cost
+ outfit_cost_data += list(outfit_cost_list)
+
+ for(var/slot in outfit.equipped_things)
+ var/datum/loadout_item/loadout_item = outfit.equipped_things[slot]
+ if(!loadout_item)
+ continue
+ var/list/equipped_item_ui_data = list() //slot + equipped item data
+ var/list/current_loadout_item_data = list() //equipped item data
+ current_loadout_item_data["name"] = loadout_item.name
+ current_loadout_item_data["job"] = outfit.role
+ current_loadout_item_data["slot"] = GLOB.inventory_slots_to_string["[loadout_item.item_slot]"]
+ current_loadout_item_data["type"] = loadout_item.type
+ current_loadout_item_data["desc"] = loadout_item.desc
+ current_loadout_item_data["purchase_cost"] = loadout_item.purchase_cost
+ current_loadout_item_data["unlock_cost"] = loadout_item.unlock_cost
+ current_loadout_item_data["valid_choice"] = loadout_item.item_checks(outfit)
+ current_loadout_item_data["icon"] = loadout_item.ui_icon
+ current_loadout_item_data["quantity"] = loadout_item.quantity
+ current_loadout_item_data["requirements"] = loadout_item.req_desc
+ current_loadout_item_data["unlocked"] = TRUE
+
+ equipped_item_ui_data["item_type"] = current_loadout_item_data
+ equipped_item_ui_data["slot"] = slot
+ equipped_item_ui_data["slot_text"] = GLOB.inventory_slots_to_string["[slot]"]
+
+ equipped_loadouts_data += list(equipped_item_ui_data)
+
+ for(var/slot in outfit.available_list)
+ for(var/datum/loadout_item/loadout_item AS in outfit.available_list[slot])
+ var/list/available_loadout_item_data = list()
+ available_loadout_item_data["name"] = loadout_item.name
+ available_loadout_item_data["job"] = outfit.role
+ available_loadout_item_data["slot"] = GLOB.inventory_slots_to_string["[loadout_item.item_slot]"]
+ available_loadout_item_data["type"] = loadout_item.type
+ available_loadout_item_data["desc"] = loadout_item.desc
+ available_loadout_item_data["purchase_cost"] = loadout_item.purchase_cost
+ available_loadout_item_data["unlock_cost"] = loadout_item.unlock_cost
+ available_loadout_item_data["valid_choice"] = loadout_item.item_checks(outfit)
+ available_loadout_item_data["icon"] = loadout_item.ui_icon
+ available_loadout_item_data["quantity"] = loadout_item.quantity
+ available_loadout_item_data["requirements"] = loadout_item.req_desc
+ available_loadout_item_data["unlocked"] = TRUE
+ available_loadouts_data += list(available_loadout_item_data)
+
+ for(var/slot in outfit.purchasable_list)
+ for(var/datum/loadout_item/loadout_item AS in outfit.purchasable_list[slot])
+ var/list/purchasable_loadout_item_data = list()
+ purchasable_loadout_item_data["name"] = loadout_item.name
+ purchasable_loadout_item_data["job"] = outfit.role
+ purchasable_loadout_item_data["slot"] = GLOB.inventory_slots_to_string["[loadout_item.item_slot]"]
+ purchasable_loadout_item_data["type"] = loadout_item.type
+ purchasable_loadout_item_data["desc"] = loadout_item.desc
+ purchasable_loadout_item_data["purchase_cost"] = loadout_item.purchase_cost
+ purchasable_loadout_item_data["unlock_cost"] = loadout_item.unlock_cost
+ purchasable_loadout_item_data["valid_choice"] = loadout_item.item_checks(outfit)
+ purchasable_loadout_item_data["icon"] = loadout_item.ui_icon
+ purchasable_loadout_item_data["quantity"] = loadout_item.quantity
+ purchasable_loadout_item_data["requirements"] = loadout_item.req_desc
+ purchasable_loadout_item_data["unlocked"] = FALSE
+ available_loadouts_data += list(purchasable_loadout_item_data)
+
+ data["equipped_loadouts_data"] = equipped_loadouts_data
+ data["available_loadouts_data"] = available_loadouts_data
+ data["outfit_cost_data"] = outfit_cost_data
+
+ return data
+
+/datum/individual_stats/ui_static_data(mob/user)
+ var/datum/game_mode/hvh/campaign/current_mode = SSticker.mode
+ if(!istype(current_mode))
+ CRASH("campaign_mission loaded without campaign game mode")
+
+ var/list/data = list()
+
+ var/ui_theme
+ switch(faction)
+ if(FACTION_SOM)
+ ui_theme = "som"
+ else
+ ui_theme = "ntos"
+ data["ui_theme"] = ui_theme
+ data["faction"] = faction
+ data["jobs"] = valid_jobs
+
+ var/list/perks_data = list()
+ for(var/job in perks_by_job)
+ for(var/datum/perk/perk AS in GLOB.campaign_perks_by_role[job])
+ var/list/perk_data = list()
+ perk_data["name"] = perk.name
+ perk_data["job"] = job
+ perk_data["type"] = perk.type
+ perk_data["desc"] = perk.desc
+ perk_data["requirements"] = perk.req_desc
+ perk_data["cost"] = perk.unlock_cost
+ perk_data["icon"] = perk.ui_icon
+ perk_data["currently_active"] = !!(perk in perks_by_job[job])
+ perks_data += list(perk_data)
+ data["perks_data"] = perks_data
+
+ return data
+
+/datum/individual_stats/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/datum/game_mode/hvh/campaign/current_mode = SSticker.mode
+ if(!istype(current_mode))
+ CRASH("campaign_mission loaded without campaign game mode")
+
+ var/mob/living/user = usr
+
+ switch(action)
+ if("set_selected_tab")
+ var/new_tab = params["new_selected_tab"]
+ if(new_tab != TAB_LOADOUT && new_tab != TAB_PERKS)
+ return
+ selected_tab = new_tab
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ return TRUE
+ if("set_selected_job")
+ var/new_job = params["new_selected_job"]
+ if(!new_job)
+ return
+ selected_job = new_job
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ return TRUE
+ if("play_ding")
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50) //just for the consistant experience
+ return TRUE
+ if("unlock_perk")
+ var/unlocked_perk = text2path(params["selected_perk"])
+ if(!unlocked_perk)
+ return
+ if(!GLOB.campaign_perk_list[unlocked_perk])
+ return
+ var/datum/perk/perk = GLOB.campaign_perk_list[unlocked_perk]
+ if(!purchase_perk(perk, user))
+ return
+ ui.send_full_update()
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ return TRUE
+ if("equip_item")
+ var/equipped_item_type = text2path(params["selected_item"])
+ if(!equipped_item_type)
+ return
+ var/equipped_item_job = params["selected_job"]
+ if(!equipped_item_job)
+ return
+ for(var/datum/loadout_item/item AS in GLOB.campaign_loadout_items_by_role[equipped_item_job])
+ if(!istype(item, equipped_item_type))
+ continue
+ loadouts[equipped_item_job].equip_loadout_item(item)
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ return TRUE
+ if("unlock_item")
+ var/equipped_item_type = text2path(params["unlocked_item"])
+ if(!equipped_item_type)
+ return
+ var/equipped_item_job = params["selected_job"]
+ if(!equipped_item_job)
+ return
+ if(!unlock_loadout_item(equipped_item_type, equipped_item_job, user))
+ return
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ return TRUE
+ if("equip_outfit")
+ var/job = params["outfit_job"]
+ if(!job || !loadouts[job])
+ return
+ if(!istype(user) || user.stat)
+ to_chat(user, span_warning("Must be alive to do this!"))
+ return
+ var/obj/item/card/id/user_id = user.get_idcard()
+ if(!(user_id.id_flags & CAN_BUY_LOADOUT))
+ to_chat(user, span_warning("You have already selected a loadout for this mission."))
+ return
+ if(user.job.title != job)
+ to_chat(user, span_warning("Invalid job. This outfit is for [job]."))
+ return
+ if(!is_mainship_level(user.z))
+ to_chat(user, span_warning("You can't equip a new loadout in the field!"))
+ return
+ if(!loadouts[job].check_full_loadout())
+ to_chat(user, span_warning("Invalid loadout."))
+ return
+ var/insufficient_credits = use_funds(loadouts[job].loadout_cost)
+ if(insufficient_credits)
+ to_chat(user, span_warning("Requires [insufficient_credits] more credits."))
+ return
+ loadouts[job].equip_loadout(user)
+ user.playsound_local(user, 'sound/effects/menu_click.ogg', 50)
+ user_id.id_flags &= ~CAN_BUY_LOADOUT
+ return TRUE
+
+//loadout/perk UI for campaign gamemode
+/datum/action/campaign_loadout
+ name = "Loadout menu"
+ action_icon_state = "individual_stats"
+
+/datum/action/campaign_loadout/give_action(mob/M)
+ . = ..()
+ var/datum/faction_stats/your_faction = GLOB.faction_stats_datums[owner.faction]
+ if(!your_faction)
+ return
+
+ var/datum/individual_stats/stats = your_faction.get_player_stats(owner)
+ if(!stats)
+ return
+ stats.current_mob = M
+
+/datum/action/campaign_loadout/action_activate()
+ var/datum/faction_stats/your_faction = GLOB.faction_stats_datums[owner.faction]
+ if(!your_faction)
+ return
+ var/datum/individual_stats/stats = your_faction.get_player_stats(owner)
+ if(!stats)
+ return
+ stats.current_mob = owner //taking over ssd's creates a mismatch
+ //we have to update selected tab/job so we load the correct data for the UI
+ if(!isliving(owner))
+ stats.selected_job = stats.valid_jobs[1]
+ else
+ var/mob/living/living_owner = owner
+ stats.selected_job = living_owner.job.title
+ stats.selected_tab = TAB_LOADOUT
+ stats.interact(owner)
+
+#undef TAB_LOADOUT
+#undef TAB_PERKS
diff --git a/code/datums/gamemodes/campaign/loadout_items.dm b/code/datums/gamemodes/campaign/loadout_items.dm
new file mode 100644
index 0000000000000..44b7748efa7bb
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items.dm
@@ -0,0 +1,96 @@
+///Available by default
+#define LOADOUT_ITEM_ROUNDSTART_OPTION (1<<0)
+///This is the default option for this slot
+#define LOADOUT_ITEM_DEFAULT_CHOICE (1<<1)
+///Available for unlock by default
+#define LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE (1<<2)
+
+GLOBAL_LIST_INIT(campaign_loadout_slots, list(ITEM_SLOT_OCLOTHING, ITEM_SLOT_ICLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_EYES, ITEM_SLOT_EARS, \
+ITEM_SLOT_MASK, ITEM_SLOT_HEAD, ITEM_SLOT_FEET, ITEM_SLOT_ID, ITEM_SLOT_BELT, ITEM_SLOT_BACK, ITEM_SLOT_L_POCKET, ITEM_SLOT_R_POCKET, ITEM_SLOT_SUITSTORE))
+
+//List of all loadout_item datums
+GLOBAL_LIST_INIT_TYPED(campaign_loadout_item_type_list, /datum/loadout_item, init_glob_loadout_item_list())
+
+/proc/init_glob_loadout_item_list()
+ . = list()
+ for(var/type in subtypesof(/datum/loadout_item))
+ var/datum/loadout_item/item_type = new type
+ if(!length(item_type.jobs_supported))
+ qdel(item_type)
+ continue
+ .[item_type.type] = item_type
+
+//List of all loadout_item datums by job, excluding ones that must be unlocked //now including those
+GLOBAL_LIST_INIT(campaign_loadout_items_by_role, init_campaign_loadout_items_by_role())
+
+/proc/init_campaign_loadout_items_by_role()
+ . = list()
+ for(var/job in GLOB.campaign_jobs)
+ .[job] = list()
+ for(var/i in GLOB.campaign_loadout_item_type_list)
+ var/datum/loadout_item/option = GLOB.campaign_loadout_item_type_list[i]
+ if(option.jobs_supported && !(job in option.jobs_supported))
+ continue
+ .[job] += option
+
+//represents an equipable item
+//Are singletons
+/datum/loadout_item
+ ///Item name
+ var/name
+ ///Item desc
+ var/desc
+ ///Addition desc for special reqs such as black/whitelist
+ var/req_desc
+ ///Typepath of the actual item this datum represents
+ var/obj/item/item_typepath
+ ///UI icon for this item
+ var/ui_icon = "default"
+ ///inventory slot it is intended to go into
+ var/item_slot
+ ///Behavior flags for loadout items
+ var/loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION
+ ///Cost to unlock this option
+ var/unlock_cost = 0
+ ///Cost to use this option
+ var/purchase_cost = 0
+ ///The amount of this available per mission. -1 for unlimited
+ var/quantity = -1
+ ///Job types that this perk is available to
+ var/list/jobs_supported
+ ///assoc list by slot of items required for this to be equipped. Requires only 1 out of the list
+ var/list/item_whitelist
+ ///assoc list by slot of items blacklisted for this to be equipped
+ var/list/item_blacklist
+
+///Attempts to add an item to a loadout
+/datum/loadout_item/proc/item_checks(datum/outfit_holder/outfit_holder)
+ if(length(item_whitelist) && !whitelist_check(outfit_holder))
+ return FALSE
+ if(length(item_blacklist) && !blacklist_check(outfit_holder))
+ return FALSE
+ return TRUE
+
+///checks if a loadout has one or more whitelist items
+/datum/loadout_item/proc/whitelist_check(datum/outfit_holder/outfit_holder)
+ for(var/whitelist_item in item_whitelist)
+ var/type_to_check = outfit_holder.equipped_things["[item_whitelist[whitelist_item]]"]?.item_typepath
+ if(type_to_check == whitelist_item)
+ return TRUE
+ return FALSE
+
+///Checks if a loadout has any blacklisted items
+/datum/loadout_item/proc/blacklist_check(datum/outfit_holder/outfit_holder)
+ for(var/blacklist_item in item_blacklist)
+ var/type_to_check = outfit_holder.equipped_things["[item_blacklist[blacklist_item]]"]?.item_typepath
+ if(type_to_check == blacklist_item)
+ return FALSE
+ return TRUE
+
+///Any post equip things related to this item
+/datum/loadout_item/proc/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ return role_post_equip(wearer, loadout)
+
+///A separate post equip proc for role specific code. Split for more flexible parent overriding
+/datum/loadout_item/proc/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ return
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/back_slot.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/back_slot.dm
new file mode 100644
index 0000000000000..ba3dde9517317
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/back_slot.dm
@@ -0,0 +1,110 @@
+/datum/loadout_item/back/som_satchel
+ name = "Mining satchel"
+ desc = "A satchel with origins dating back to the mining colonies.. Carries less than a backpack, but items can be drawn instantly."
+ item_typepath = /obj/item/storage/backpack/satchel/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_STAFF_OFFICER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/back/som_combat_pack
+ name = "Mining rucksack"
+ desc = "A rucksack with origins dating back to the mining colonies. Has the storage capacity of a backpack but no draw delay."
+ purchase_cost = 25
+ item_typepath = /obj/item/storage/backpack/lightpack/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/back/som_combat_pack/free
+ purchase_cost = 0
+ jobs_supported = list(SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/back/som_flamer_tank
+ name = "Flame tank"
+ desc = "A specialized fuel tank for use with the V-62 incinerator."
+ req_desc = "Requires a V-62 incinerator."
+ item_typepath = /obj/item/ammo_magazine/flamer_tank/backtank
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ item_whitelist = list(/obj/item/weapon/gun/flamer/som/mag_harness = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/back/som_flamer_tank/x_fuel
+ name = "X-fuel tank"
+ desc = "A specialized fuel tank of ultra thick napthal type X, known for its extreme heat and slow burn rate, as well as it's distinct blue flames. For use with the V-62 incinerator."
+ item_typepath = /obj/item/ammo_magazine/flamer_tank/backtank/X
+ purchase_cost = 40
+ unlock_cost = 200
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/back/blinkdrive
+ name = "Blink drive"
+ desc = "A portable Bluespace Displacement Drive, otherwise known as a blink drive. \
+ Can teleport the user across short distances with a degree of unreliability, with potentially fatal results. \
+ Teleporting past 5 tiles, to tiles out of sight or rapid use of the drive add variance to the teleportation destination."
+ req_desc = "Requires an energy sword or V-21 SMG."
+ item_typepath = /obj/item/blink_drive
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ quantity = 2
+ item_whitelist = list(
+ /obj/item/weapon/energy/sword/som = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/smg/som/veteran = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/back/som_shotgun
+ name = "V-51"
+ desc = "Equipped with a mag harness, bayonet and undebarrel flashlight. The V-51 is the main shotgun utilised by the Sons of Mars. \
+ Semi automatic with great handling and mobility, it is less powerful than the SH-35 used by the TGMC, but makes up for it with a superior rate of fire. \
+ Uses 12 gauge shells."
+ ui_icon = "shotgun"
+ purchase_cost = 25
+ item_typepath = /obj/item/weapon/gun/shotgun/som/standard
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+ loadout_item_flags = NONE
+
+/datum/loadout_item/back/som_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/shotgun/buckshot, SLOT_R_HAND)
+
+/datum/loadout_item/back/som_rocket_bag
+ name = "RPG bag"
+ desc = "This backpack holds 4 RPGs, in addition to a V-71 RPG launcher. Equipped with radioactive and incendiary warheads, \
+ the V-71 is incredibly effective at softening up or flushing out organic targets, making them easy prey to finish off. Has a draw delay."
+ req_desc = "Requires a suit with a Mithridatius environmental protection module."
+ ui_icon = "rpg"
+ purchase_cost = 50
+ quantity = 2
+ item_typepath = /obj/item/storage/holster/backholster/rpg/som/war_crimes
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/mithridatius = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/back/som_heat_rocket_bag
+ name = "HEAT RPG bag"
+ desc = "Unlocked for free with the Heavy weapon specialisation perk. This backpack holds 4 high explosive anti armor RPGs, in addition to a V-71 RPG launcher. Deals significant damage against vehicles and mechs, but will also generally devastate human victims in a pinch. \
+ Has a draw delay and has poor accuracy against human targets."
+ ui_icon = "rpg"
+ unlock_cost = 300
+ purchase_cost = 100
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+ quantity = 2
+ item_typepath = /obj/item/storage/holster/backholster/rpg/som/heat
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/back/volkite_powerpack
+ name = "M-70 powerpack"
+ desc = "A heavy reinforced backpack with an array of ultradensity energy cells, linked to a miniature radioisotope thermoelectric generator for continuous power generation. \
+ Used to power the largest man portable volkite weaponry. Click drag cells to the powerpack to recharge."
+ req_desc = "Requires a VX-42 culverin or VX-33 caliver."
+ item_typepath = /obj/item/cell/lasgun/volkite/powerpack
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/culverin/magharness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/tacsensor = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/back/boarding_axe
+ name = "Boarding axe"
+ desc = "A SOM boarding axe, a monstrous two handed weapon that inflicts terrible damage even through heavy armor. \
+ When wielded it can be used to block as well as attack, and can also be used to force unpowered airlocks open. \
+ You'll kill pretty much anything you can hit with this - providing you can get close enough to use it."
+ ui_icon = "axe"
+ item_typepath = /obj/item/weapon/twohanded/fireaxe/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_FIELD_COMMANDER)
+ item_blacklist = list(/obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_SUITSTORE)
+ loadout_item_flags = NONE
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/belt.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/belt.dm
new file mode 100644
index 0000000000000..15c53b6e0201a
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/belt.dm
@@ -0,0 +1,119 @@
+/datum/loadout_item/belt/som_ammo_belt
+ name = "Ammo belt"
+ desc = "A belt with origins traced to the M276 ammo belt and some old colony security. Holds 6 normal sized magazines."
+ item_typepath = /obj/item/storage/belt/marine/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/som_mg/standard = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/flamer/som/mag_harness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/som/standard = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/som/support = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/belt/som_sparepouch
+ name = "Utility pouch"
+ desc = "A small, lightweight pouch that can be clipped onto armor or your belt to provide additional storage for miscellaneous gear or box and drum magazines. Made from genuine SOM leather."
+ item_typepath = /obj/item/storage/belt/sparepouch/som
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/belt/som_shotgun_mixed
+ name = "Shotgun shell rig"
+ desc = "An ammunition belt designed to hold shotgun shells or individual bullets. Made with traditional SOM leather. Loaded full of buckshot and flechette shells."
+ item_typepath = /obj/item/storage/belt/shotgun/som/mixed
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/belt/som_shotgun_flechette
+ name = "Shotgun shell rig"
+ desc = "An ammunition belt designed to hold shotgun shells or individual bullets. Made with traditional SOM leather. Loaded full of flechette shells."
+ item_typepath = /obj/item/storage/belt/shotgun/som/flechette
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+
+/datum/loadout_item/belt/som_grenades
+ name = "Grenade rig"
+ desc = "A simple harness system available in many configurations. This version is designed to carry bulk quantities of grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/belt/grenade/som
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ purchase_cost = 80
+ quantity = 2
+
+/datum/loadout_item/belt/som_grenades/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BELT)
+
+/datum/loadout_item/belt/som_burst_pistol
+ name = "V-11e"
+ desc = "The standard sidearm used by the Sons of Mars. A reliable and simple weapon that is often seen on the export market on the outer colonies. \
+ Typically chambered in 9mm armor piercing rounds. This one is configures for burstfire, and loaded with extended mags."
+ ui_icon = "v11"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/belt/som_burst_pistol/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_HOLSTER)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/som/burst(wearer), SLOT_IN_HOLSTER)
+
+/datum/loadout_item/belt/sawn_off
+ name = "Sawn-off shotgun"
+ desc = "A double barreled shotgun whose barrel has been artificially shortened to reduce range for further CQC potiential. Extremely powerful at close range, but is very difficult to handle."
+ req_desc = "Requires a VX-42 culverin or VX-33 caliver with powerpack."
+ ui_icon = "sshotgun"
+ item_typepath = /obj/item/weapon/gun/shotgun/double/sawn
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/culverin/magharness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/tacsensor = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/belt/energy_sword
+ name = "Energy sword"
+ desc = "A SOM energy sword. Designed to cut through armored plate. An uncommon primary weapon, typically seen wielded by so called 'blink assault' troops. \
+ Can be used defensively to great effect, mainly against opponents trying to strike you in melee, although some users report varying levels of success in blocking ranged projectiles."
+ ui_icon = "machete"
+ item_typepath = /obj/item/weapon/energy/sword/som
+ loadout_item_flags = NONE
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+
+/datum/loadout_item/belt/som_lifesaver
+ name = "S17 lifesaver bag"
+ desc = "A belt with heavy origins from the belt used by paramedics and doctors in the old mining colonies."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/belt/lifesaver/som/quick
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/belt/som_officer_pistol
+ name = "VX-12 Serpenta"
+ desc = "The 'serpenta' is a volkite energy pistol typically seen in the hands of SOM officers and some NCOs, and is quite dangerous for it's size. \
+ Comes in a holster that fits on your waist or armor."
+ ui_icon = "pistol"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/som/serpenta
+ jobs_supported = list(SOM_SQUAD_LEADER, SOM_STAFF_OFFICER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ item_blacklist = list(/obj/item/storage/holster/belt/pistol/m4a3/som/serpenta = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/belt/som_officer_pistol_custom
+ name = "VX-12c Serpenta"
+ desc = "The 'serpenta' is a volkite energy pistol typically seen in the hands of SOM officers and some NCOs, and is quite dangerous for it's size. \
+ This particular weapon appears to be a custom model with improved performance. Comes in a fancy holster that fits on your waist or armor."
+ ui_icon = "pistol"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/som/fancy/fieldcommander
+ jobs_supported = list(SOM_FIELD_COMMANDER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ item_blacklist = list(/obj/item/storage/holster/belt/pistol/m4a3/som/fancy/fieldcommander = ITEM_SLOT_SUITSTORE)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/ears.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/ears.dm
new file mode 100644
index 0000000000000..ae9a3c46e3614
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/ears.dm
@@ -0,0 +1,13 @@
+/datum/loadout_item/ears/som_standard
+ name = "Standard headset"
+ desc = "A headset, allowing for communication with your team and access to the tactical minimap. You're in for a bad time if you don't use this."
+ item_typepath = /obj/item/radio/headset/mainship/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/ears/som_command
+ name = "Command headset"
+ desc = "A command headset, allowing for communication with all squads and access to the tactical minimap. You're in for a bad time if you don't use this."
+ item_typepath = /obj/item/radio/headset/mainship/som/command
+ jobs_supported = list(SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/feet.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/feet.dm
new file mode 100644
index 0000000000000..07e24d77b20e2
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/feet.dm
@@ -0,0 +1,13 @@
+/datum/loadout_item/feet/som_boots
+ name = "Combat shoes"
+ desc = "Shoes with origins dating back to the old mining colonies. These were made for more than just walking."
+ item_typepath = /obj/item/clothing/shoes/marine/som/knife
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/feet/som_officer
+ name = "officer's boots"
+ desc = "A shiny pair of boots, normally seen on the feet of SOM officers."
+ item_typepath = /obj/item/clothing/shoes/marinechief/som
+ jobs_supported = list(SOM_STAFF_OFFICER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/gloves.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/gloves.dm
new file mode 100644
index 0000000000000..508e26911656f
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/gloves.dm
@@ -0,0 +1,28 @@
+/datum/loadout_item/gloves/som_gloves
+ name = "SOM gloves"
+ desc = "Gloves with origins dating back to the old mining colonies, they look pretty tough."
+ item_typepath = /obj/item/clothing/gloves/marine/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/gloves/som_veteran_gloves
+ name = "Veteran gloves"
+ desc = "Gloves with origins dating back to the old mining colonies. These ones seem tougher than normal."
+ item_typepath = /obj/item/clothing/gloves/marine/som/veteran
+ jobs_supported = list(SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/gloves/som_insulated
+ name = "Insulated gloves"
+ desc = "Gloves with origins dating back to the old mining colonies. These ones appear to have an electrically insulating layer built into them."
+ item_typepath = /obj/item/clothing/gloves/marine/som/insulated
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/gloves/som_officer_gloves
+ name = "Officer gloves"
+ desc = "Black gloves commonly worn by SOM officers."
+ item_typepath = /obj/item/clothing/gloves/marine/som/officer
+ jobs_supported = list(SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/head.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/head.dm
new file mode 100644
index 0000000000000..3b69a4d64855a
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/head.dm
@@ -0,0 +1,70 @@
+/datum/loadout_item/helmet/som_standard
+ name = "Infantry helmet"
+ desc = "The standard combat helmet worn by SOM combat troops. Made using advanced polymers to provide very effective protection without compromising visibility."
+ item_typepath = /obj/item/clothing/head/modular/som
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/som_standard/medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+
+/datum/loadout_item/helmet/som_standard/medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_HEAD)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_HEAD)
+
+/datum/loadout_item/helmet/som_veteran
+ name = "Veteran helmet"
+ desc = "The standard combat helmet worn by SOM combat specialists. State of the art materials provides more protection for more valuable brains."
+ item_typepath = /obj/item/clothing/head/modular/som/veteran
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/gorgon
+ name = "Gorgon helmet"
+ desc = "Made for use with Gorgon pattern assault armor, providing superior protection. Typically seen on SOM leaders or their most elite combat units."
+ item_typepath = /obj/item/clothing/head/modular/som/leader
+ jobs_supported = list(SOM_SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/gorgon/fc
+ name = "Gorgon helmet"
+ desc = "Made for use with Gorgon pattern assault armor, providing superior protection. This one has gold markings indicating it belongs to a high ranking field officer."
+ item_typepath = /obj/item/clothing/head/modular/som/leader/officer
+ jobs_supported = list(SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/helmet/som_surt
+ name = "Hades Helmet"
+ desc = "A standard combat helmet with a Hades fireproof module."
+ req_desc = "Requires a suit with a Hades module."
+ item_typepath = /obj/item/clothing/head/modular/som/hades
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/pyro = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/helmet/som_tyr
+ name = "Lorica Helmet"
+ desc = "A bulky helmet paired with the 'Lorica' armor module, designed for outstanding protection at the cost of significant weight and reduced flexibility. \
+ Substantial additional armor improves protection against all damage."
+ req_desc = "Requires a suit with a Lorica module."
+ ui_icon = "lorica"
+ item_typepath = /obj/item/clothing/head/modular/som/lorica
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/lorica = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/helmet/som_mimir
+ name = "Biohazard helmet"
+ desc = "A standard combat helmet with a Mithridatius 'Mith' environmental protection module."
+ req_desc = "Requires a suit with a Mithridatius environmental protection module."
+ item_typepath = /obj/item/clothing/head/modular/som/bio
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/mithridatius = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/helmet/som_engineer
+ name = "Engineer helmet"
+ desc = "A specialised helmet designed for use by combat engineers. Its main feature being an integrated welding mask."
+ item_typepath = /obj/item/clothing/head/modular/som/engineer
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/som_engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/pockets.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/pockets.dm
new file mode 100644
index 0000000000000..e19db1484355a
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/pockets.dm
@@ -0,0 +1,205 @@
+/datum/loadout_item/r_pocket/som_standard_first_aid
+ name = "First aid pouch"
+ desc = "Standard SOM first-aid pouch. Contains a basic set of medical supplies."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/r_pocket/som_standard_first_aid/standard_improved
+ desc = "Standard SOM first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol_leader
+ loadout_item_flags = null
+
+/datum/loadout_item/r_pocket/som_standard_first_aid/improved
+ desc = "Standard SOM first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol_leader
+ jobs_supported = list(SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/r_pocket/som_support_grenades
+ name = "Support nades"
+ desc = "A pouch carrying a set of six standard support grenades. Includes smoke grenades of both lethal and nonlethal varieties, as well as stun grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/som/combat_patrol
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/r_pocket/som_standard_grenades
+ name = "Standard nades"
+ desc = "A pouch carrying a set of six standard offensive grenades. Contains HE and incendiary grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/som/standard
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/r_pocket/war_crime_grenades
+ name = "Warcrime nades"
+ desc = "A pouch carrying a set of rad and satrapine grenades. Extremely hazardous."
+ ui_icon = "grenade"
+ req_desc = "Requires a suit with a Mithridatius environmental protection module."
+ item_typepath = /obj/item/storage/pouch/grenade/som
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/mithridatius = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/r_pocket/war_crime_grenades/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/r_pocket/som_shotgun
+ name = "Buckshot shells"
+ desc = "A pouch specialized for holding shotgun ammo. Contains buckshot shells."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/shotgun/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+
+/datum/loadout_item/r_pocket/som_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/r_pocket/som_construction
+ name = "Construction pouch"
+ desc = "A pouch containing an assortment of construction supplies. Allows for the rapid establishment of fortified positions."
+ ui_icon = "materials"
+ item_typepath = /obj/item/storage/pouch/construction/som
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/r_pocket/som_construction/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags_empty/half, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags/large_stack, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/full, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/r_pocket/som_magazine
+ name = "Mag pouch-P"
+ desc = "A pouch containing three ammo magazines. Will contain a primary ammo type where applicable."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/magazine/large/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/som_mg/standard = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/flamer/som/mag_harness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/som/standard = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/som/support = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/r_pocket/som_tools
+ name = "Tool pouch"
+ desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool."
+ ui_icon = "construction"
+ item_typepath = /obj/item/storage/pouch/tools/som/full
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/r_pocket/som_general
+ name = "General pouch"
+ desc = "A general purpose pouch used to carry small items."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/general/som
+ jobs_supported = list(SOM_STAFF_OFFICER, SOM_COMMANDER)
+
+//l_pocket
+/datum/loadout_item/l_pocket/som_standard_first_aid
+ name = "First aid pouch"
+ desc = "Standard SOM first-aid pouch. Contains a basic set of medical supplies."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/som_standard_first_aid/standard_improved
+ desc = "Standard SOM first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol_leader
+ loadout_item_flags = null
+
+/datum/loadout_item/l_pocket/som_standard_first_aid/improved
+ desc = "Standard SOM first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/som/combat_patrol_leader
+ jobs_supported = list(SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/som_support_grenades
+ name = "Support nades"
+ desc = "A pouch carrying a set of six standard support grenades. Includes smoke grenades of both lethal and nonlethal varieties, as well as stun grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/som/combat_patrol
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/l_pocket/som_standard_grenades
+ name = "Standard nades"
+ desc = "A pouch carrying a set of six standard offensive grenades. Contains HE and incendiary grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/som/standard
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/l_pocket/war_crime_grenades
+ name = "Warcrime nades"
+ desc = "A pouch carrying a set of rad and satrapine grenades. Extremely hazardous."
+ ui_icon = "grenade"
+ req_desc = "Requires a suit with a Mithridatius environmental protection module."
+ item_typepath = /obj/item/storage/pouch/grenade/som
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/mithridatius = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/l_pocket/war_crime_grenades/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_L_POUCH)
+
+/datum/loadout_item/l_pocket/som_shotgun
+ name = "Flechette shells"
+ desc = "A pouch specialized for holding shotgun ammo. Contains Flechette shells."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/shotgun/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER)
+
+/datum/loadout_item/l_pocket/som_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+
+/datum/loadout_item/l_pocket/som_construction
+ name = "Construction pouch"
+ desc = "A pouch containing an assortment of construction supplies. Allows for the rapid establishment of fortified positions."
+ ui_icon = "materials"
+ item_typepath = /obj/item/storage/pouch/construction/som
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/l_pocket/som_construction/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags_empty/half, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags/large_stack, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/full, SLOT_IN_L_POUCH)
+
+/datum/loadout_item/l_pocket/som_magazine
+ name = "Mag pouch-S"
+ desc = "A pouch containing three ammo magazines. Will contain a secondary ammo type where applicable."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/magazine/large/som
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/som_mg/standard = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/flamer/som/mag_harness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/som/standard = ITEM_SLOT_SUITSTORE,
+ )
+
+
+/datum/loadout_item/l_pocket/som_magazine/medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/som_general
+ name = "General pouch"
+ desc = "A general purpose pouch used to carry small items."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/general/som
+ jobs_supported = list(SOM_STAFF_OFFICER, SOM_COMMANDER)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit.dm
new file mode 100644
index 0000000000000..2a7519abb9b1a
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit.dm
@@ -0,0 +1,195 @@
+/datum/loadout_item/suit_slot/som_light_shield
+ name = "L Aegis armor"
+ desc = "M-11 scout armor with a Aegis shield module. Provides excellent mobility but lower protection."
+ ui_icon = "light_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/som/light/shield
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/suit_slot/som_light_shield/veteran
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ req_desc = "Requires a blink drive."
+ item_whitelist = list(/obj/item/blink_drive = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked
+ desc = "M-11 scout armor with a Aegis shield module. Provides excellent mobility but lower protection. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/som/light/shield_overclocked
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked/medic
+ item_typepath = /obj/item/clothing/suit/modular/som/light/shield_overclocked/medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked/medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked/engineer
+ item_typepath = /obj/item/clothing/suit/modular/som/light/shield_overclocked/engineer
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked/engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_light_shield/overclocked/veteran
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ req_desc = "Requires a blink drive."
+ item_whitelist = list(/obj/item/blink_drive = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_slot/som_medium_shield
+ name = "M Aegis armor"
+ desc = "M-21 battle armor with a Aegis shield module. Provides balanced mobility and protection."
+ ui_icon = "medium_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/som/shield
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/som_medium_shield/overclocked
+ desc = "M-21 battle armor with a Aegis shield module. Provides balanced mobility and protection. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/som/shield_overclocked
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/som_medium_shield/overclocked/medic
+ item_typepath = /obj/item/clothing/suit/modular/som/shield_overclocked/medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_slot/som_medium_shield/overclocked/medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_medium_shield/overclocked/engineer
+ item_typepath = /obj/item/clothing/suit/modular/som/shield_overclocked/engineer
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_slot/som_medium_shield/overclocked/engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_heavy_shield
+ name = "H Aegis armor"
+ desc = "M-31 combat armor with a Aegis shield module. Provides excellent protection but lower mobility."
+ ui_icon = "heavy_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/shield
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/som_heavy_shield/overclocked
+ desc = "M-31 combat armor with a Aegis shield module. Provides excellent protection but lower mobility. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/shield_overclocked
+ jobs_supported = list(SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/som_heavy_shield/breacher
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ req_desc = "Requires a V-21 and boarding shield."
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION
+ item_whitelist = list(
+ /obj/item/weapon/gun/smg/som/one_handed = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/suit_slot/som_heavy_shield/breacher/overclocked
+ desc = "M-31 combat armor with a Aegis shield module. Provides excellent protection but lower mobility. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/shield_overclocked
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/som_heavy_surt
+ name = "H Hades armor"
+ desc = "M-31 combat armor with a Hades fireproof module. Provides excellent protection and almost total fire immunity, but has poor mobility."
+ ui_icon = "heavy_armour"
+ req_desc = "Requires a V-62 incinerator."
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/pyro
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ item_whitelist = list(/obj/item/weapon/gun/flamer/som/mag_harness = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/suit_slot/som_heavy_tyr
+ name = "H Lorica armor"
+ desc = "M-31 combat armor with a Lorica extra armor module. Provides incredible protection at the cost of further reduced mobility."
+ ui_icon = "lorica"
+ req_desc = "Requires a boarding axe primary weapon."
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/lorica
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ item_whitelist = list(
+ /obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/suit_slot/som_heavy_tyr/veteran
+ req_desc = "Requires a VX-32 charger and boarding shield."
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/somvet = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/suit_slot/gorgon
+ name = "Gorgon armor"
+ desc = "M-35 'Gorgon' armor with integrated Apollo automedical module. Provides outstanding protection without severely limiting mobility. \
+ Typically seen on SOM leaders or their most elite combat units due to the significant construction and maintenance requirements."
+ ui_icon = "gorgon"
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/leader/valk
+ jobs_supported = list(SOM_SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/gorgon/fc
+ name = "Gorgon armor"
+ desc = "M-35 'Gorgon' armor with integrated Apollo automedical module. Provides outstanding protection without severely limiting mobility. \
+ Typically seen on SOM leaders or their most elite combat units due to the significant construction and maintenance requirements. \
+ The gold markings on this one signify it is worn by a high ranking field officer"
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/leader/officer
+ jobs_supported = list(SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/suit_slot/som_heavy_mimir
+ name = "H Mith armor"
+ desc = "M-31 combat armor with a Mithridatius 'Mith' environmental protection module. Provides excellent armor and total immunity to chemical attacks, and improved radiological protection. Has lower mobility."
+ req_desc = "Requires a helmet with a Mithridatius environmental protection module."
+ ui_icon = "heavy_armour"
+ item_typepath = /obj/item/clothing/suit/modular/som/heavy/mithridatius
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ item_whitelist = list(/obj/item/clothing/head/modular/som/bio = ITEM_SLOT_HEAD)
+ purchase_cost = 75
+ quantity = 4
+
+//engineer
+/datum/loadout_item/suit_slot/som_engineer
+ name = "M armor"
+ desc = "M-21 battle armor with engineering storage. Provides balanced armor and mobility."
+ ui_icon = "medium_armour"
+ item_typepath = /obj/item/clothing/suit/modular/som/engineer
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/som_engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_engineer/light
+ name = "L armor"
+ desc = "M-11 scout armor with engineering storage. Provides excellent mobility but lower protection."
+ ui_icon = "light_armour"
+ item_typepath = /obj/item/clothing/suit/modular/som/light/engineer
+
+//medic
+/datum/loadout_item/suit_slot/som_medic
+ name = "M armor"
+ desc = "M-21 battle armor with medical storage. Provides balanced armor and mobility."
+ ui_icon = "medium_armour"
+ item_typepath = /obj/item/clothing/suit/modular/som/medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/som_medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/som_medic/light
+ name = "L armor"
+ desc = "M-11 scout armor with medical storage. Provides excellent mobility but lower protection."
+ ui_icon = "light_armour"
+ item_typepath = /obj/item/clothing/suit/modular/som/light/medic
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/engineer.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/engineer.dm
new file mode 100644
index 0000000000000..eb0b672426edd
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/engineer.dm
@@ -0,0 +1,204 @@
+/datum/loadout_item/suit_store/main_gun/som_engineer
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x24mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/standard
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle/enhanced
+ name = "V-31+"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses a mix of standard and AP 10x24mm caseless ammunition, and 10 gauge micro grenades."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/mpi
+ name = "MPi-KM"
+ desc = "Equipped with a mag harness and laser sight. The MPi-KM is a modern reproduction based off several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ These weapons were already ancient at that time, and their continued use by the SOM speaks more to their cultural legacy than any tactical benefits. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/black/magharness
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/mpi/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/carbine
+ name = "V-34"
+ desc = "Equipped with a red dot sight and foldable stock. The V-34 is a modern redesign of an ancient weapon that saw extensive use in the Martian uprising. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/black/standard
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/smg
+ name = "V-21"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/support
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/smg/enhanced
+ name = "V-21+"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/flechette_shotgun
+ name = "V-51"
+ desc = "Equipped with a mag harness and bayonet. The V-51 is the main shotgun utilised by the Sons of Mars. \
+ Semi automatic with great handling and mobility, it is less powerful than the SH-35 used by the TGMC, but makes up for it with a superior rate of fire. \
+ Uses 12 gauge shells."
+ ui_icon = "shotgun"
+ item_typepath = /obj/item/weapon/gun/shotgun/som/support
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/flechette_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/flechette_shotgun/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/volkite_charger
+ name = "VX-32 charger"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight and laser sight. The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. Can be used one handed relatively effectively with sufficient skill. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/standard
+ unlock_cost = 300
+ purchase_cost = 25
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/som_engineer/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/field_commander.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/field_commander.dm
new file mode 100644
index 0000000000000..d5189ff12ac83
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/field_commander.dm
@@ -0,0 +1,205 @@
+/datum/loadout_item/suit_store/main_gun/som_field_commander
+ jobs_supported = list(SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!ammo_type)
+ return
+ if(istype(wearer.back, /obj/item/storage))
+ if(istype(wearer.belt, /obj/item/storage/holster/belt/pistol/m4a3/som)) //if we have a backpack and pistol belt, we just load more ammo in the back
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else //else we put the sidearm in the bag
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta/custom(wearer), SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. Also comes with light armor piercing ammunition. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x25mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/veteran
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/smg
+ name = "V-21"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with armor piercing ammunition. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/veteran
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/volkite_charger
+ name = "VX-32 charger"
+ desc = "Equipped with a motion sensor and gyroscopic stabiliser for effective one handed use. \
+ The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/scout
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/volkite_caliver
+ name = "VX-33 caliver"
+ desc = "Equipped with a red dot sight and laser sight. \
+ The VX-33 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has middling mobility and handling, it is a long range rifle analogue, able to project strong damage even at long ranges. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-32, and can also be linked to a volkite powerpack."
+ ui_icon = "volkite"
+ purchase_cost = 50
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/tacsensor
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/volkite_caliver/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/mpi
+ name = "MPi-KM"
+ desc = "Equipped with a mag harness and underbarrel grenade launcher. This MPi-KM is an original example of one of several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ Passed down the generations and lovingly maintained as a family heirloom, \
+ its use on modern battlefields is an idiosyncratic example of the SOM's persistant desire to maintain a link to their cultural past, more than any possible tactical reason. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/grenadier
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/mpi/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/carbine
+ name = "V-34"
+ desc = "Equipped with a mag harness and foldable stock. This V-34 is refurbished and well maintained weapon passed down from its use during the original Martian rebellion, \
+ more family heirloom than a battlefield weapon, it serves just as well regardless. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/mag_harness
+
+/datum/loadout_item/suit_store/main_gun/som_field_commander/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/fc_boarding_axe
+ name = "Boarding axe"
+ desc = "A SOM boarding axe, a monstrous two handed weapon that inflicts terrible damage even through heavy armor. \
+ When wielded it can be used to block as well as attack, and can also be used to force unpowered airlocks open. \
+ You'll kill pretty much anything you can hit with this - providing you can get close enough to use it."
+ ui_icon = "axe"
+ item_typepath = /obj/item/weapon/twohanded/fireaxe/som
+ item_blacklist = list(/obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_BACK)
+ jobs_supported = list(SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/suit_store/fc_boarding_axe/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign/som, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+ if(istype(wearer.belt, /obj/item/storage/holster/belt/pistol/m4a3/som))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta/custom(wearer), SLOT_IN_BACKPACK)
+
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/medic.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/medic.dm
new file mode 100644
index 0000000000000..7bbece10d3be4
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/medic.dm
@@ -0,0 +1,175 @@
+/datum/loadout_item/suit_store/main_gun/som_medic
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_store/main_gun/som_medic/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x24mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/standard
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_medic/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_medic/standard_rifle/enhanced
+ name = "V-31+"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses a mix of standard and AP 10x24mm caseless ammunition, and 10 gauge micro grenades."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_medic/mpi
+ name = "MPi-KM"
+ desc = "Equipped with a mag harness and laser sight. The MPi-KM is a modern reproduction based off several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ These weapons were already ancient at that time, and their continued use by the SOM speaks more to their cultural legacy than any tactical benefits. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/black/magharness
+
+/datum/loadout_item/suit_store/main_gun/som_medic/mpi/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_medic/carbine
+ name = "V-34"
+ desc = "Equipped with a red dot sight and foldable stock. The V-34 is a modern redesign of an ancient weapon that saw extensive use in the Martian uprising. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/black/standard
+
+/datum/loadout_item/suit_store/main_gun/som_medic/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_medic/smg
+ name = "V-21"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/support
+
+/datum/loadout_item/suit_store/main_gun/som_medic/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/enhanced
+ name = "V-21+"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_medic/flechette_shotgun
+ name = "V-51"
+ desc = "Equipped with a mag harness and bayonet, and solely loaded with flechette rounds. The V-51 is the main shotgun utilised by the Sons of Mars. \
+ Semi automatic with great handling and mobility, it is less powerful than the SH-35 used by the TGMC, but makes up for it with a superior rate of fire. \
+ Uses 12 gauge shells."
+ ui_icon = "shotgun"
+ item_typepath = /obj/item/weapon/gun/shotgun/som/support
+
+/datum/loadout_item/suit_store/main_gun/som_medic/flechette_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_medic/volkite_charger
+ name = "VX-32 charger"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight and laser sight. The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. Can be used one handed relatively effectively with sufficient skill. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/standard
+ unlock_cost = 300
+ purchase_cost = 25
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/som_medic/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/squad_leader.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/squad_leader.dm
new file mode 100644
index 0000000000000..97e19c10f09b5
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/squad_leader.dm
@@ -0,0 +1,164 @@
+/datum/loadout_item/suit_store/main_gun/som_squad_leader
+ jobs_supported = list(SOM_SQUAD_LEADER)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!ammo_type)
+ return
+ if(istype(wearer.back, /obj/item/storage))
+ if(istype(wearer.belt, /obj/item/storage/holster/belt/pistol/m4a3/som)) //if we have a backpack and pistol belt, we just load more ammo in the back
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else //else we put the sidearm in the bag
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta(wearer), SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. Also comes with light armor piercing ammunition. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x25mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/veteran
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/smg
+ name = "V-21"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with armor piercing ammunition. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/veteran
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/volkite_charger
+ name = "VX-32 charger"
+ desc = "Equipped with a motion sensor and gyroscopic stabiliser for effective one handed use. \
+ The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/scout
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/volkite_caliver
+ name = "VX-33 caliver"
+ desc = "Equipped with a motion sensor and laser sight. \
+ The VX-33 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has middling mobility and handling, it is a long range rifle analogue, able to project strong damage even at long ranges. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-32, and can also be linked to a volkite powerpack."
+ ui_icon = "volkite"
+ purchase_cost = 50
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/tacsensor
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/volkite_caliver/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/mpi
+ name = "MPi-KM"
+ desc = "Equipped with a mag harness and underbarrel grenade launcher. This MPi-KM is an original example of one of several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ Passed down the generations and lovingly maintained as a family heirloom, \
+ its use on modern battlefields is an idiosyncratic example of the SOM's persistant desire to maintain a link to their cultural past, more than any possible tactical reason. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/grenadier
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/mpi/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/carbine
+ name = "V-34"
+ desc = "Equipped with a mag harness and foldable stock. This V-34 is refurbished and well maintained weapon passed down from its use during the original Martian rebellion, \
+ more family heirloom than a battlefield weapon, it serves just as well regardless. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/mag_harness
+
+/datum/loadout_item/suit_store/main_gun/som_squad_leader/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/standard.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/standard.dm
new file mode 100644
index 0000000000000..da1de837f2261
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/standard.dm
@@ -0,0 +1,414 @@
+/datum/loadout_item/suit_store/main_gun/som_marine
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!ammo_type)
+ return
+ if(!isstorage(wearer.back))
+ return
+ if(istype(wearer.belt, /obj/item/storage/holster/belt/pistol/m4a3/som)) //if we have a backpack and pistol belt, we just load more ammo in the back
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else //else we put the sidearm in the bag
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/som/standard(wearer), SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x24mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/standard
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle/enhanced
+ name = "V-31+"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses a mix of standard and AP 10x24mm caseless ammunition, and 10 gauge micro grenades."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/som_marine/mpi_grenadier
+ name = "MPi-KM"
+ desc = "Equipped with a red dot sight and underbarrel grenade launcher. The MPi-KM is a modern reproduction based off several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ These weapons were already ancient at that time, and their continued use by the SOM speaks more to their cultural legacy than any tactical benefits. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/black/grenadier
+
+/datum/loadout_item/suit_store/main_gun/som_marine/mpi_grenadier/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/carbine
+ name = "V-34"
+ desc = "Equipped with a red dot sight and foldable stock. The V-34 is a modern redesign of an ancient weapon that saw extensive use in the Martian uprising. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/black/standard
+
+/datum/loadout_item/suit_store/main_gun/som_marine/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg
+ name = "V-21"
+ desc = "Equipped with a motion sensor, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ req_desc = "Requires M-11 scout armor."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/scout
+ item_whitelist = list(
+ /obj/item/clothing/suit/modular/som/light/shield = ITEM_SLOT_OCLOTHING,
+ /obj/item/clothing/suit/modular/som/light/shield_overclocked = ITEM_SLOT_OCLOTHING,
+ )
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/enhanced
+ name = "V-21+"
+ desc = "Equipped with a motion sensor, recoil compensator and vertical grip. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_shotgun
+ name = "V-51"
+ desc = "Equipped with a mag harness, bayonet and undebarrel flashlight. The V-51 is the main shotgun utilised by the Sons of Mars. \
+ Semi automatic with great handling and mobility, it is less powerful than the SH-35 used by the TGMC, but makes up for it with a superior rate of fire. \
+ Uses 12 gauge shells."
+ req_desc = "Requires M-11 scout armor."
+ ui_icon = "shotgun"
+ item_typepath = /obj/item/weapon/gun/shotgun/som/standard
+ item_whitelist = list(
+ /obj/item/clothing/suit/modular/som/light/shield = ITEM_SLOT_OCLOTHING,
+ /obj/item/clothing/suit/modular/som/light/shield_overclocked = ITEM_SLOT_OCLOTHING,
+ )
+
+/datum/loadout_item/suit_store/main_gun/som_marine/standard_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/flamer
+ name = "V-62 incinerator"
+ desc = "Equipped with a mag harness and wide nozzle. The V-62 is a deadly weapon employed in close quarter combat, favoured as much for the terror it inspires as the actual damage it inflicts. \
+ It has good range for a flamer, able to effortly clear out enclosed or defensive positions but lacks the integrated extinguisher of its TGMC equivalent."
+ req_desc = "Requires M-31 combat armor with a Hades fireproof module."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/flamer/som/mag_harness
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/pyro = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/flamer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X/som, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/flamer/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som/extended, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield
+ name = "V-21 & riot shield"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with a S-144 boarding shield, intended for use with M-31 combat armor for boarding actions.. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ When used with the boarding shield, use of the higher rate of fire is highly unrecommended outside of anything but absolute point blank range. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "riot_shield"
+ item_typepath = /obj/item/weapon/gun/smg/som/one_handed
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/som, SLOT_L_HAND)
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ return ..() //we explicitly don't want a sidearm for this weapon choice
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield/enhanced
+ name = "V-21+ & riot shield"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with a S-144 boarding shield, intended for use with M-31 combat armor for boarding actions.. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ When used with the boarding shield, use of the higher rate of fire is highly unrecommended outside of anything but absolute point blank range. \
+ Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_marine/machinegunner
+ name = "V-41"
+ desc = "Equipped with a red dot sight, extended barrel and bipod. The V-41 is a large man portable machine used by the SOM, allowing for sustained, accurate suppressive firepower at the cost of mobility and handling. \
+ Commonly seen where their preferred tactics of fast, mobile aggression is ill suited. Has impressive ranged damage application as a static weapon. Uses 10x26mm Caseless ammunition."
+ ui_icon = "v41"
+ item_typepath = /obj/item/weapon/gun/rifle/som_mg/standard
+
+/datum/loadout_item/suit_store/main_gun/som_marine/machinegunner/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/machinegunner/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/satrapine, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/volkite_charger
+ name = "VX-32 charger"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a motion detector and gyroscopic stabilizer. The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. Can be used one handed relatively effectively with sufficient skill. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/scout
+ unlock_cost = 300
+ purchase_cost = 35
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/som_marine/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/volkite_charger/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/boarding_axe
+ name = "Boarding axe"
+ desc = "A SOM boarding axe, a monstrous two handed weapon that inflicts terrible damage even through heavy armor. \
+ When wielded it can be used to block as well as attack, and can also be used to force unpowered airlocks open. \
+ You'll kill pretty much anything you can hit with this - providing you can get close enough to use it."
+ req_desc = "Requires M-31 combat armor with a Lorica extra armor module."
+ ui_icon = "axe"
+ item_typepath = /obj/item/weapon/twohanded/fireaxe/som
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/lorica = ITEM_SLOT_OCLOTHING)
+ item_blacklist = list(/obj/item/weapon/twohanded/fireaxe/som = ITEM_SLOT_BACK)
+ jobs_supported = list(SOM_SQUAD_MARINE)
+
+/datum/loadout_item/suit_store/boarding_axe/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle
+ name = "V-31-suppressed"
+ desc = "Equipped with a mag harness, suppressor, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ This particular example is a less common variant intended for stealthy operations, where its quietness and lack of muzzle flash can help get the jump on unsuspecting opponents. \
+ Uses 10x24mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/suppressed
+
+/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle/enhanced
+ name = "V-31-suppressed+"
+ desc = "Equipped with a mag harness, suppressor, vertical grip and integrated micro rail launcher. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ This particular example is a less common variant intended for stealthy operations, where its quietness and lack of muzzle flash can help get the jump on unsuspecting opponents. \
+ Uses a mix of standard and AP 10x24mm caseless ammunition, and 10 gauge micro grenades."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/som/ap
+
+/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/veteran.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/veteran.dm
new file mode 100644
index 0000000000000..83332e2d9fd1b
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/suit_storage/veteran.dm
@@ -0,0 +1,372 @@
+/datum/loadout_item/suit_store/main_gun/som_veteran
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!ammo_type)
+ return
+ if(istype(wearer.back, /obj/item/storage))
+ if(istype(wearer.belt, /obj/item/storage/holster/belt/pistol/m4a3/som)) //if we have a backpack and pistol belt, we just load more ammo in the back
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else //else we put the sidearm in the bag
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/som/standard(wearer), SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/standard_rifle
+ name = "V-31"
+ desc = "Equipped with a red dot sight, extended barrel, vertical grip and integrated micro rail launcher. Also comes with light armor piercing ammunition. The V-31 is the principal ballistic weapon for the SOM. \
+ It has good mobility and handling and a good rate of fire, but tends to favour closer range fighting compared to many TGMC equivilents. \
+ The rail launcher electromagnetically launches a variety of 10 gauge airbursting grenades. Extremely effective when used correctly, their fixed fuse time makes them entirely ineffective at very close or far ranges. \
+ Managing engagement range is thus vital for maximising the effectiveness of this weapon. \
+ Uses 10x25mm caseless ammunition and 10 gauge micro grenades."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/som/veteran
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/smoke_burst, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/standard_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/dragonbreath, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/micro_grenade/cluster, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/smg
+ name = "V-21"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with armor piercing ammunition. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/veteran
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/breacher
+ name = "VX-32B charger"
+ desc = "Equipped with a mag harness and gyroscopic stabiliser for effective one handed use, and comes with a S-144 boarding shield, intended for use with M-31 Lorica combat armor for boarding actions. \
+ The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "riot_shield"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/somvet
+ purchase_cost = 60
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/breacher/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/som, SLOT_L_HAND)
+ if(istype(wearer.back, /obj/item/storage))
+ return ..()
+
+ wearer.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/breacher/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_charger
+ name = "VX-32 charger"
+ desc = "Equipped with a motion sensor and gyroscopic stabiliser for effective one handed use. \
+ The VX-32 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has excellent mobility and handling and is best used at close range. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-33."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/charger/scout
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_charger/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_charger/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_caliver
+ name = "VX-33 caliver"
+ desc = "Equipped with a red dot sight and laser sight. \
+ The VX-33 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has middling mobility and handling, it is a long range rifle analogue, able to project strong damage even at long ranges. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-32, and can also be linked to a volkite powerpack."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/standard
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_caliver/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_caliver/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/mpi
+ name = "MPi-KM"
+ desc = "Equipped with a mag harness and underbarrel grenade launcher. This MPi-KM is an original example of one of several variants of kalashnikov type rifles used during the original Martian rebellion. \
+ Passed down the generations and lovingly maintained as a family heirloom, \
+ its use on modern battlefields is an idiosyncratic example of the SOM's persistant desire to maintain a link to their cultural past, more than any possible tactical reason. \
+ Despite having relatively poor mobility and handling, it never the less has fearsome firepower and good capacity, ensuring it stays a relevant weapon choice for the SOM. Uses 7.62x39mm ammunition."
+ ui_icon = "ak47"
+ item_typepath = /obj/item/weapon/gun/rifle/mpi_km/grenadier
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/mpi/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/carbine
+ name = "V-34"
+ desc = "Equipped with a mag harness and foldable stock. This V-34 is refurbished and well maintained weapon passed down from its use during the original Martian rebellion, \
+ more family heirloom than a battlefield weapon, it serves just as well regardless. \
+ It combines good mobility and managable handling with fearsome stopping power and a tremendous rate of fire, making the V-34 an exceptionally deadly weapon at close range. \
+ With poor falloff and accuracy, it is a poor weapon outside of close range, and its mobility lacks compared to some other close range weapons like the V-21. \
+ Uses 7.62x39mm ammunition."
+ ui_icon = "v34"
+ item_typepath = /obj/item/weapon/gun/rifle/som_carbine/mag_harness
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/mpi_km/extended, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_caliver_pack
+ name = "VX-33P Caliver"
+ desc = "Equipped with a motion sensor and laser sight, this one is intended to be used with a back worm powerpack. \
+ The VX-33 is a sophisticated energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ Has middling mobility and handling, it is a long range rifle analogue, able to project strong damage even at long ranges. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ Uses volkite power cells, shared with the VX-32, and can also be linked to a volkite powerpack."
+ req_desc = "Requires a volkite powerback."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/tacsensor
+ quantity = 2
+ purchase_cost = 50
+ item_whitelist = list(/obj/item/cell/lasgun/volkite/powerpack = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_caliver_pack/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ if(istype(wearer.belt, /obj/item/weapon/gun/shotgun/double/sawn))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_culverin
+ name = "VX-42 culverin"
+ desc = "Equipped with a mag harness. \
+ The VX-42 is a massive and terrifying energy weapon capable of explosively deflagrated organic targets, horrifically burning and igniting the victim and anyone unfortunate enough to be near them. \
+ It has poor mobility and handling and is somewhat inaccurate at range, especially on the move. Despite this, the VX-42 can unleash a blistering amount of firepower, making it one of the most feared weapons in the SOM arsenal. \
+ Targets at close range are torn apart, and its high rate of fire more than makes up for its somewhat poor long range accuracy. \
+ Its deflagrating ability works best against light armored targets, where it can quickly mow down and demoralise tightly packed enemies. Against heavily armored opponents, its effectiveness can quickly drop however. \
+ It must be linked to a volkite powerpack, allowing for sustained fire, although its energy demands can quickly drain even the powerpack, leaving a trigger happy operate vulnerable while it recharges."
+ req_desc = "Requires a volkite powerback to operate."
+ ui_icon = "volkite"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/culverin/magharness
+ quantity = 2
+ purchase_cost = 100
+ item_whitelist = list(/obj/item/cell/lasgun/volkite/powerpack = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/volkite_culverin/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+ if(istype(wearer.belt, /obj/item/weapon/gun/shotgun/double/sawn))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_ACCESSORY)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/radioactive_smg
+ name = "V-21R"
+ desc = "Equipped with a red dot sight, recoil compensator and vertical grip, along with radioactive and incendiary ammunition. The V-21 is the principal submachinegun used by the Sons of Mars, with a variable rate of fire. \
+ Has outstanding mobility and handling and can be comfortably fired one handed on its lower fire rate mode. \
+ When set to its higher rate of fire, it unleashes a staggering torrent of firepower, but is difficult to control even two handed, and quickly loses effectiveness at range. \
+ At close range however, it will quickly obliterate most targets - as long as you don't run out of ammo. \
+ It uses 10x20mm caseless rounds."
+ req_desc = "Requires a suit with a Mithridatius environmental protection module."
+ ui_icon = "smg"
+ item_typepath = /obj/item/weapon/gun/smg/som/support
+ item_whitelist = list(/obj/item/clothing/suit/modular/som/heavy/mithridatius = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/suit_store/main_gun/som_veteran/radioactive_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+ if(istype(wearer.belt, /obj/item/storage/belt))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som, SLOT_IN_BELT)
+ if(istype(wearer.l_store, /obj/item/storage/pouch/magazine))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ if(istype(wearer.r_store, /obj/item/storage/pouch/magazine))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/som/incendiary, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/rad, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/energy_sword
+ name = "Energy sword"
+ desc = "A SOM energy sword. Designed to cut through armored plate. An uncommon primary weapon, typically seen wielded by so called 'blink assault' troops. \
+ Can be used defensively to great effect, mainly against opponents trying to strike you in melee, although some users report varying levels of success in blocking ranged projectiles."
+ ui_icon = "machete"
+ item_typepath = /obj/item/weapon/energy/sword/som
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/suit_store/energy_sword/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary/som, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/SOM/uniform.dm b/code/datums/gamemodes/campaign/loadout_items/SOM/uniform.dm
new file mode 100644
index 0000000000000..6d0547e6422ec
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/SOM/uniform.dm
@@ -0,0 +1,67 @@
+/datum/loadout_item/uniform/som_standard
+ name = "SOM uniform"
+ desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies."
+ item_typepath = /obj/item/clothing/under/som/webbing
+ jobs_supported = list(SOM_SQUAD_MARINE)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_veteran
+ name = "SOM veteran uniform"
+ desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies. This one has markings indicating specialist status."
+ item_typepath = /obj/item/clothing/under/som/veteran/webbing
+ jobs_supported = list(SOM_SQUAD_VETERAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_leader
+ name = "SOM leader uniform"
+ desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies. This one has leadership markings."
+ item_typepath = /obj/item/clothing/under/som/leader/webbing
+ jobs_supported = list(SOM_SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//corpsman
+/datum/loadout_item/uniform/som_medic
+ name = "SOM medical uniform"
+ desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies. This one has medical markings."
+ item_typepath = /obj/item/clothing/under/som/medic/vest
+ jobs_supported = list(SOM_SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_medic/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/bodybag/cryobag, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/roller, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tweezers_advanced, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/nanoblood, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/spaceacillin, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/combat_advanced, SLOT_IN_ACCESSORY)
+
+//engineer
+/datum/loadout_item/uniform/som_engineer
+ name = "SOM uniform"
+ desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies."
+ req_desc = "Requires a tool pouch. You ARE an engineer, right?"
+ item_typepath = /obj/item/clothing/under/som/webbing
+ jobs_supported = list(SOM_SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_field_commander
+ name = "Officer uniform"
+ desc = "The distinct black uniform befitting a SOM field officer."
+ item_typepath = /obj/item/clothing/under/som/officer/webbing
+ jobs_supported = list(SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_officer
+ name = "Officer uniform"
+ desc = "The distinct black uniform of a SOM officer. Usually worn by junior officers."
+ item_typepath = /obj/item/clothing/under/som/officer
+ jobs_supported = list(SOM_STAFF_OFFICER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/som_senior_officer
+ name = "Officer uniform"
+ desc = "The distinct jacketed black uniform of a SOM officer. Usually worn by senior officers."
+ item_typepath = /obj/item/clothing/under/som/officer/senior
+ jobs_supported = list(SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/back_slot.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/back_slot.dm
new file mode 100644
index 0000000000000..cdf0e77cafa80
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/back_slot.dm
@@ -0,0 +1,190 @@
+/datum/loadout_item/back
+ item_slot = ITEM_SLOT_BACK
+
+/datum/loadout_item/back/empty
+ name = "no backpack"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+/datum/loadout_item/back/marine_satchel
+ name = "Satchel"
+ desc = "A heavy-duty satchel carried by some TGMC soldiers and support personnel. Carries less than a backpack, but items can be drawn instantly."
+ item_typepath = /obj/item/storage/backpack/marine/satchel
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, STAFF_OFFICER, CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/back/marine_backpack
+ name = "Backpack"
+ desc = "The standard-issue pack of the TGMC forces. Designed to slug gear into the battlefield. Carries more than a satchel but has a draw delay."
+ item_typepath = /obj/item/storage/backpack/marine
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER)
+
+/datum/loadout_item/back/combat_pack
+ name = "Combat pack"
+ desc = "A small lightweight pack for expeditions and short-range operations. Has the storage capacity of a backpack but no draw delay."
+ purchase_cost = 25
+ item_typepath = /obj/item/storage/backpack/lightpack
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER)
+
+/datum/loadout_item/back/combat_pack/free
+ purchase_cost = 0
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/back/flamer_tank
+ name = "Flame tank"
+ desc = "A specialized fuel tank for use with the FL-84 flamethrower and FL-240 incinerator unit."
+ req_desc = "Requires a FL-84 flamethrower."
+ item_typepath = /obj/item/ammo_magazine/flamer_tank/backtank
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/wide = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/back/flamer_tank/x_fuel
+ name = "X-fuel tank"
+ desc = "A specialized fuel tank of ultra thick napthal type X, known for its extreme heat and slow burn rate, as well as it's distinct blue flames. For use with the FL-84 flamethrower and FL-240 incinerator unit."
+ item_typepath = /obj/item/ammo_magazine/flamer_tank/backtank/X
+ purchase_cost = 40
+ unlock_cost = 200
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/back/jetpack
+ name = "Heavy jetpack"
+ desc = "An upgraded jetpack with enough fuel to send a person flying for a short while with extreme force. \
+ It provides better mobility for heavy users and enough thrust to be used in an aggressive manner. \
+ Alt right click or middleclick to fly to a destination when the jetpack is equipped. Will collide with hostiles"
+ req_desc = "Requires a SMG-25 or ALF-51B."
+ item_typepath = /obj/item/jetpack_marine/heavy
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(
+ /obj/item/weapon/gun/smg/m25/magharness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/rifle/alf_machinecarbine/assault = ITEM_SLOT_SUITSTORE,
+ )
+
+//special unlockable
+/datum/loadout_item/back/marine_shotgun
+ name = "SH-35"
+ desc = "Equipped with a mag harness, bayonet, angled grip and foldable stock. \
+ The SH-35 is the most commonly used shotgun of the TGMC. With good mobility and handling, it has unparalleled close range power when using buckshot. Able to kill or maim all but the most heavily armored targets with a single well aimmed blast. \
+ When using flechette rounds, it can provide surprisingly powerful long range damage with good penetration, although its low rate of fire means its sustained damage is relatively poor. \
+ Uses 12 gauge shells."
+ ui_icon = "t35"
+ purchase_cost = 25
+ item_typepath = /obj/item/weapon/gun/shotgun/pump/t35/standard
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER)
+ loadout_item_flags = NONE
+
+/datum/loadout_item/back/marine_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/shotgun/buckshot, SLOT_R_HAND)
+
+/datum/loadout_item/back/tgmc_heam_rocket_bag
+ name = "HEAM rocket bag"
+ desc = "Unlocked for free with the Heavy weapon specialisation perk. This backpack holds 4 67mm high explosive anti mech shells, in addition to a recoiless rifle. \
+ The recoiless rifle is a powerful support weapon that deals significant damage against heavily armored mechs or vehicles, \
+ but will generally devastate any human target unfortunate enough to be hit in a pinch. Has a draw delay and has poor accuracy against human targets."
+ ui_icon = "t160"
+ unlock_cost = 300
+ purchase_cost = 100
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+ quantity = 2
+ item_typepath = /obj/item/storage/holster/backholster/rpg/heam
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/back/machete
+ name = "Machete"
+ desc = "A large leather scabbard carrying a M2132 machete. It can be strapped to the back, waist or armor. Extremely dangerous against human opponents - if you can get close enough."
+ ui_icon = "machete"
+ item_typepath = /obj/item/storage/holster/blade/machete/full
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER)
+ loadout_item_flags = NONE
+
+//corpsman
+/datum/loadout_item/back/corpsman_satchel
+ name = "Medical satchel"
+ desc = "A heavy-duty satchel carried by some TGMC corpsmen. You can recharge defibrillators by plugging them in. Carries less than a backpack, but items can be drawn instantly."
+ item_typepath = /obj/item/storage/backpack/marine/corpsman/satchel
+ jobs_supported = list(SQUAD_CORPSMAN)
+
+/datum/loadout_item/back/corpsman_backpack
+ name = "Medical backpack"
+ desc = "The standard-issue backpack worn by TGMC corpsmen. You can recharge defibrillators by plugging them in. Carries more than a satchel but has a draw delay."
+ item_typepath = /obj/item/storage/backpack/marine/corpsman
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//engineer
+/datum/loadout_item/back/engineerpack
+ name = "Sentry welderpack"
+ desc = "A specialized backpack worn by TGMC technicians. It carries a fueltank for quick welder refueling. Loaded with 2 point defense sentries, excellent for defending areas or establishing killboxes."
+ item_typepath = /obj/item/storage/backpack/marine/engineerpack
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/back/engineerpack/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/sentry/mini/combat_patrol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/sentry/mini/combat_patrol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/minisentry, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/minisentry, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/back/tgmc_rocket_bag
+ name = "Rocket bag"
+ desc = "This backpack holds 4 67mm shells, in addition to a recoiless rifle. \
+ A powerful ranged weapon with a wide area of effect, the recoiless rifle is a powerful support weapon that can severely wound whole groups of opponents in a single shot. Has a draw delay."
+ ui_icon = "t160"
+ purchase_cost = 100
+ quantity = 2
+ item_typepath = /obj/item/storage/holster/backholster/rpg/low_impact
+ jobs_supported = list(SQUAD_ENGINEER)
+
+/datum/loadout_item/back/tech_backpack
+ name = "Demolition backpack"
+ desc = "The standard-issue backpack worn by TGMC technicians. Filled with a tremendous amount of detpacks, C4, claymores and grenades. Has a draw delay."
+ item_typepath = /obj/item/storage/backpack/marine/tech
+ jobs_supported = list(SQUAD_ENGINEER)
+
+/datum/loadout_item/back/tech_backpack/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/minelayer, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/explosive_mines/large, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/explosive_mines/large, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/detpack, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/assembly/signaler, SLOT_IN_BACKPACK)
+
+//smartgunner
+/datum/loadout_item/back/sg_minigun_powerpack
+ name = "SG-85 powerpack"
+ desc = "A reinforced backpack heavy with the IFF altered ammunition, onboard micro generator, and extensive cooling system which enables the SG-85 gatling gun to operate. \
+ Use the SG-85 on the backpack itself to connect them."
+ req_desc = "Requires an SG-85."
+ item_typepath = /obj/item/ammo_magazine/minigun_powerpack/smartgun
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+ item_whitelist = list(/obj/item/weapon/gun/minigun/smart_minigun/motion_detector = ITEM_SLOT_SUITSTORE)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/belt.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/belt.dm
new file mode 100644
index 0000000000000..a84775408f085
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/belt.dm
@@ -0,0 +1,142 @@
+/datum/loadout_item/belt
+ item_slot = ITEM_SLOT_BELT
+
+/datum/loadout_item/belt/empty
+ name = "no belt"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/belt/ammo_belt
+ name = "Ammo belt"
+ desc = "The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. This version is the standard variant designed for bulk ammunition-carrying operations."
+ item_typepath = /obj/item/storage/belt/marine
+ jobs_supported = list(SQUAD_MARINE, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/minigun/smart_minigun/motion_detector = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/flamer/big_flamer/marinestandard/wide = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/standard_mmg/machinegunner = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/rifle/standard_gpmg/machinegunner = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/shotgun/pump/t35/standard = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/belt/sparepouch
+ name = "G8 pouch"
+ desc = "A small, lightweight pouch that can be clipped onto Armat Systems M3 Pattern armor or your belt to provide additional storage for miscellaneous gear or box and drum magazines."
+ item_typepath = /obj/item/storage/belt/sparepouch
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/belt/sparepouch/smartgunner
+ desc = "A general storage pouch. \
+ Contains a MP-19 sidearm, and spare ammo for the SG-85, or addition drum magazines for the SG-29." //contents handled by the SG-85
+ req_desc = "Requires an SG-85."
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+ item_whitelist = list(
+ /obj/item/weapon/gun/minigun/smart_minigun/motion_detector = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/belt/shotgun_mixed
+ name = "Shotgun shell rig"
+ desc = "An ammunition belt designed to hold shotgun shells or individual bullets. Loaded full of buckshot and flechette shells."
+ item_typepath = /obj/item/storage/belt/shotgun/mixed
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/belt/smg_holster
+ name = "SMG-25 holster"
+ desc = "The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. \
+ This version is designed for the SMG-25, and features a larger frame to support the gun. Due to its unorthodox design, it isn't a very common sight, and is only specially issued."
+ ui_icon = "m25"
+ item_typepath = /obj/item/storage/holster/m25
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(
+ /obj/item/weapon/gun/smg/m25/magharness = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/flamer/big_flamer/marinestandard/wide = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/standard_mmg/machinegunner = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/belt/smg_holster/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/m25/holstered(wearer), SLOT_IN_HOLSTER)
+
+/datum/loadout_item/belt/machete
+ name = "Machete"
+ desc = "A large leather scabbard carrying a M2132 machete. It can be strapped to the back, waist or armor. Extremely dangerous against human opponents - if you can get close enough."
+ ui_icon = "machete"
+ item_typepath = /obj/item/storage/holster/blade/machete/full
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER)
+
+/datum/loadout_item/belt/belt_harness
+ name = "Belt harness"
+ desc = "A shoulder worn strap with clamps that can attach to most anything. Should keep you from losing your weapon, hopefully."
+ item_typepath = /obj/item/belt_harness/marine
+ jobs_supported = list(SQUAD_MARINE, SQUAD_ENGINEER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/belt/belt_harness/smart_gunner
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+
+//medic
+/datum/loadout_item/belt/lifesaver
+ name = "Lifesaver bag"
+ desc = "The M276 is the standard load-bearing equipment of the TGMC. This configuration mounts a duffel bag filled with a range of injectors and light medical supplies and is common among medics."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/belt/lifesaver/quick
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//FC
+/datum/loadout_item/belt/officer_sword
+ name = "Officers sword"
+ desc = "This appears to be a rather old blade that has been well taken care of, it is probably a family heirloom. \
+ Well made and extremely sharp, despite its probable non-combat purpose. Comes in a leather scabbard that an attached to your waist or armor."
+ ui_icon = "machete"
+ item_typepath = /obj/item/storage/holster/blade/officer/full
+ jobs_supported = list(FIELD_COMMANDER)
+ item_blacklist = list(/obj/item/storage/holster/blade/officer/full = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/belt/fc_pistol
+ name = "P-1911A1-C pistol"
+ desc = "The P-1911A1-C is a custom modified pistol with impressive stopping power for its size. \
+ Light and easy to use one handed, it suffers from a small magazine size and no auto eject feature. Comes in a holster that fits on your waist or armor. Uses .45 ACP ammunition."
+ ui_icon = "m1911c"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/fieldcommander
+ jobs_supported = list(FIELD_COMMANDER)
+ item_blacklist = list(/obj/item/storage/holster/belt/pistol/m4a3/fieldcommander = ITEM_SLOT_SUITSTORE)
+
+//staff officer
+/datum/loadout_item/belt/so_pistol
+ name = "RT-3 pistol"
+ desc = "An RT-3 target pistol, a common sight throughout the bubble and the standard sidearm for noncombat roles in the TGMC. Comes in a holster to fit on your waist. uses 9mm caseless ammunition."
+ ui_icon = "rt3"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/officer
+ jobs_supported = list(STAFF_OFFICER)
+
+//captain
+/datum/loadout_item/belt/smart_pistol
+ name = "SP-13 pistol"
+ desc = "The SP-13 is a IFF-capable sidearm used by the TerraGov Marine Corps. Has good damage, penetration and magazine capacity. \
+ Expensive to manufacture, this sophisticated pistol is only occassionally used by smartgunners, or some higher ranking officers who have the skills to use it. Uses 9x19mm Parabellum ammunition."
+ ui_icon = "pistol"
+ item_typepath = /obj/item/storage/holster/belt/pistol/smart_pistol/full
+ jobs_supported = list(CAPTAIN)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/ears.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/ears.dm
new file mode 100644
index 0000000000000..86c8613a0f4a1
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/ears.dm
@@ -0,0 +1,42 @@
+//ears
+/datum/loadout_item/ears
+ item_slot = ITEM_SLOT_EARS
+
+/datum/loadout_item/ears/empty
+ name = "no headset"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/ears/marine_standard
+ name = "Standard headset"
+ desc = "A headset, allowing for communication with your team and access to the tactical minimap. You're in for a bad time if you don't use this."
+ item_typepath = /obj/item/radio/headset/mainship/marine
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/ears/marine_command
+ name = "Command headset"
+ desc = "A command headset, allowing for communication with all squads and access to the tactical minimap. You're in for a bad time if you don't use this."
+ item_typepath = /obj/item/radio/headset/mainship/mcom
+ jobs_supported = list(FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/eyes.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/eyes.dm
new file mode 100644
index 0000000000000..fdf9f54baa04b
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/eyes.dm
@@ -0,0 +1,61 @@
+/datum/loadout_item/eyes
+ item_slot = ITEM_SLOT_EYES
+
+/datum/loadout_item/eyes/empty
+ name = "no eyewear"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/eyes/ballistic_goggles
+ name = "Ballistic goggles"
+ desc = "Standard issue TGMC goggles. Mostly used to decorate one's helmet."
+ item_typepath = /obj/item/clothing/glasses/mgoggles
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/eyes/health_hud
+ name = "HealthMate HUD"
+ desc = "A heads-up display that scans the humans in view and provides accurate data about their health status. The projector can be attached to compatable eyewear."
+ item_typepath = /obj/item/clothing/glasses/hud/health
+ jobs_supported = list(SQUAD_CORPSMAN, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN, SOM_SQUAD_CORPSMAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/eyes/mesons
+ name = "Meson scanner"
+ desc = "Used to shield the user's eyes from harmful electromagnetic emissions, also used as general safety goggles. \
+ Not adequate as welding protection. Allows the user to see structural information about their surroundings."
+ item_typepath = /obj/item/clothing/glasses/meson
+ jobs_supported = list(SQUAD_ENGINEER, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/eyes/welding
+ name = "Welding goggles"
+ desc = "Protects the eyes from welders, approved by the mad scientist association."
+ item_typepath = /obj/item/clothing/glasses/welding
+ jobs_supported = list(SQUAD_MARINE, SQUAD_ENGINEER, SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN)
+
+/datum/loadout_item/eyes/smartgun_imagers
+ name = "KTLD sight"
+ desc = "A headset and goggles system made to pair with any KTLD weapon, such as the SG type weapons. Has a low-res short range imager, allowing for view of terrain."
+ item_typepath = /obj/item/clothing/glasses/night/m56_goggles
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/feet.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/feet.dm
new file mode 100644
index 0000000000000..235a1cce951e8
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/feet.dm
@@ -0,0 +1,55 @@
+/datum/loadout_item/feet
+ item_slot = ITEM_SLOT_FEET
+ ui_icon = "boots"
+
+/datum/loadout_item/feet/empty
+ name = "no footwear"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/feet/marine_boots
+ name = "Combat boots"
+ desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time."
+ item_typepath = /obj/item/clothing/shoes/marine/full
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/feet/marine_brown_boots
+ name = "Brown boots"
+ desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time."
+ item_typepath = /obj/item/clothing/shoes/marine/brown/full
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+/datum/loadout_item/feet/white_dress
+ name = "Dress shoes"
+ desc = "Fancy white shoes to go with your white dress uniform. Do not come with a combat knife."
+ item_typepath = /obj/item/clothing/shoes/white
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+//Captain
+/datum/loadout_item/feet/captain
+ name = "Captain's shoes"
+ desc = "Has special soles for better trampling those underneath."
+ item_typepath = /obj/item/clothing/shoes/marinechief/captain
+ jobs_supported = list(CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/gloves.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/gloves.dm
new file mode 100644
index 0000000000000..a843259d36831
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/gloves.dm
@@ -0,0 +1,84 @@
+/datum/loadout_item/gloves
+ item_slot = ITEM_SLOT_GLOVES
+
+/datum/loadout_item/gloves/empty
+ name = "no gloves"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/gloves/marine_gloves
+ name = "Combat gloves"
+ desc = "Standard issue marine tactical gloves. It reads: 'knit by Marine Widows Association'."
+ item_typepath = /obj/item/clothing/gloves/marine
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/gloves/marine_black_gloves
+ name = "Blk combat gloves"
+ desc = "Standard issue marine tactical gloves but black! It reads: 'knit by Marine Widows Association'."
+ item_typepath = /obj/item/clothing/gloves/marine/black
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/gloves/marine_fingerless
+ name = "Fingerless gloves"
+ desc = "Standard issue marine tactical gloves but fingerless! It reads: 'knit by Marine Widows Association'."
+ item_typepath = /obj/item/clothing/gloves/marine/fingerless
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/gloves/white_dress
+ name = "Dress gloves"
+ desc = "Fancy white gloves to go with your white dress uniform."
+ item_typepath = /obj/item/clothing/gloves/white
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+//corpsman
+/datum/loadout_item/gloves/defib_gloves
+ name = "Defib gloves"
+ desc = "Advanced medical gloves, these include small electrodes to defibrilate a patient No more bulky units!"
+ purchase_cost = 50
+ item_typepath = /obj/item/clothing/gloves/defibrillator
+ jobs_supported = list(SQUAD_CORPSMAN)
+
+//engineer
+/datum/loadout_item/gloves/insulated
+ name = "Insulated gloves"
+ desc = "Insulated marine tactical gloves that protect against electrical shocks."
+ item_typepath = /obj/item/clothing/gloves/marine/insulated
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//FC
+/datum/loadout_item/gloves/officer_gloves
+ name = "Officer gloves"
+ desc = "Shiny and impressive. They look expensive."
+ item_typepath = /obj/item/clothing/gloves/marine/officer
+ jobs_supported = list(FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//captain
+/datum/loadout_item/gloves/captain_gloves
+ name = "Captain's gloves"
+ desc = "You may like these gloves, but THEY think you are unworthy of them."
+ item_typepath = /obj/item/clothing/gloves/marine/techofficer/captain
+ jobs_supported = list(CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/head.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/head.dm
new file mode 100644
index 0000000000000..1d8e31e44012e
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/head.dm
@@ -0,0 +1,118 @@
+/datum/loadout_item/helmet
+ item_slot = ITEM_SLOT_HEAD
+ ui_icon = "helmet"
+
+/datum/loadout_item/helmet/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat, SLOT_IN_HEAD)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_HEAD)
+
+/datum/loadout_item/helmet/empty
+ name = "no helmet"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/helmet/standard
+ name = "M10X helmet"
+ desc = "A standard TGMC combat helmet. Apply to head for best results."
+ item_typepath = /obj/item/clothing/head/modular/m10x
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/leader
+ name = "M11X helmet"
+ desc = "An upgraded helmet for protecting upgraded brains."
+ item_typepath = /obj/item/clothing/head/modular/m10x/leader
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/surt
+ name = "Surt helmet"
+ desc = "A standard combat helmet with a Surt fireproof module."
+ req_desc = "Requires a suit with a Surt module."
+ item_typepath = /obj/item/clothing/head/modular/m10x/surt
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(/obj/item/clothing/suit/modular/xenonauten/heavy/surt = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/helmet/tyr
+ name = "Tyr helmet"
+ desc = "A standard combat helmet with a Tyr extra armor module."
+ req_desc = "Requires a suit with a Tyr module."
+ ui_icon = "tyr"
+ item_typepath = /obj/item/clothing/head/modular/m10x/tyr
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(/obj/item/clothing/suit/modular/xenonauten/heavy/tyr_two = ITEM_SLOT_OCLOTHING)
+
+
+/datum/loadout_item/helmet/tyr/smartgunner
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/white_dress
+ name = "Dress Cap"
+ desc = "The dress white cap for your dress uniform. Pride is your shield, because this isn't."
+ item_typepath = /obj/item/clothing/head/white_dress
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+/datum/loadout_item/helmet/mimir
+ name = "Mimir helmet"
+ desc = "A standard combat helmet with a Mimir environmental protection module."
+ req_desc = "Requires a suit with a Mimir module."
+ item_typepath = /obj/item/clothing/head/modular/m10x/mimir
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/mimir/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/neuraline, SLOT_IN_HEAD)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/neuraline, SLOT_IN_HEAD)
+
+/datum/loadout_item/helmet/engineer
+ name = "M10X-W helmet"
+ desc = "A standard combat helmet with a welding module."
+ item_typepath = /obj/item/clothing/head/modular/m10x/welding
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
+
+/datum/loadout_item/helmet/field_commander_beret
+ name = "FC beret"
+ desc = "A beret with the field commander insignia emblazoned on it. It commands loyalty and bravery in all who gaze upon it."
+ item_typepath = /obj/item/clothing/head/tgmcberet/fc
+ jobs_supported = list(FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/staff_officer_cap
+ name = "Officer cap"
+ desc = "A hat usually worn by officers in the TGMC. While it has limited combat functionality, some prefer to wear it instead of the standard issue helmet."
+ item_typepath = /obj/item/clothing/head/tgmccap/ro
+ jobs_supported = list(STAFF_OFFICER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/helmet/captain_beret
+ name = "Captain Beret"
+ desc = "A beret worn by ship's captains. You thought it would have been more fancy."
+ item_typepath = /obj/item/clothing/head/tgmcberet/tan
+ jobs_supported = list(CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/mask.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/mask.dm
new file mode 100644
index 0000000000000..48618d354d8c2
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/mask.dm
@@ -0,0 +1,51 @@
+/datum/loadout_item/mask
+ item_slot = ITEM_SLOT_MASK
+
+/datum/loadout_item/mask/empty
+ name = "no mask"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+/datum/loadout_item/mask/standard
+ name = "Std gas mask"
+ desc = "A face-covering mask that can be connected to an air supply. Filters harmful gases from the air."
+ item_typepath = /obj/item/clothing/mask/gas
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/mask/tactical
+ name = "Tac gas mask"
+ desc = "A face-covering mask that can be connected to an air supply. Filters harmful gases from the air. This one is supposedly more tactical than the standard model."
+ item_typepath = /obj/item/clothing/mask/gas/tactical
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, SOM_SQUAD_MARINE, SOM_SQUAD_CORPSMAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+
+/datum/loadout_item/mask/skimask
+ name = "Ski mask"
+ desc = "A stylish skimask, can be recolored. Makes you feel like an operator just looking at it."
+ item_typepath = /obj/item/clothing/mask/gas/modular/skimask
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/mask/coof
+ name = "Combat face mask"
+ desc = "The CFCC is a prime and readied, yet stylish facemask ready to... cover your face."
+ item_typepath = /obj/item/clothing/mask/gas/modular/coofmask
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/pockets.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/pockets.dm
new file mode 100644
index 0000000000000..6937dbcc02c19
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/pockets.dm
@@ -0,0 +1,223 @@
+//r_pocket
+/datum/loadout_item/r_pocket
+ item_slot = ITEM_SLOT_R_POCKET
+
+/datum/loadout_item/r_pocket/empty
+ name = "no right pocket"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/r_pocket/standard_first_aid
+ name = "First aid pouch"
+ desc = "Standard marine first-aid pouch. Contains a basic set of medical supplies."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER)
+
+/datum/loadout_item/r_pocket/standard_first_aid/standard_improved
+ desc = "Standard marine first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol_leader
+ loadout_item_flags = null
+
+/datum/loadout_item/r_pocket/standard_first_aid/improved
+ desc = "Standard marine first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol_leader
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/r_pocket/marine_support_grenades
+ name = "Support nades"
+ desc = "A pouch carrying a set of six standard support grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/combat_patrol
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/r_pocket/marine_standard_grenades
+ name = "Standard nades"
+ desc = "A pouch carrying a set of six standard offensive grenades. Contains HE, lasburster and incendiary grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/standard
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/r_pocket/shotgun
+ name = "Buckshot shells"
+ desc = "A pouch specialized for holding shotgun ammo. Contains buckshot shells."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/shotgun
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER)
+
+/datum/loadout_item/r_pocket/shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/buckshot, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/r_pocket/marine_construction
+ name = "Construction pouch"
+ desc = "A pouch containing an assortment of construction supplies. Allows for the rapid establishment of fortified positions."
+ ui_icon = "materials"
+ item_typepath = /obj/item/storage/pouch/construction
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/r_pocket/marine_construction/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags_empty/half, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags/large_stack, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/full, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/r_pocket/magazine
+ name = "Mag pouch-P"
+ desc = "A pouch containing three ammo magazines. Will contain a primary ammo type where applicable."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/magazine/large
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/minigun/smart_minigun/motion_detector = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/r_pocket/tools
+ name = "Tool pouch"
+ desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool."
+ ui_icon = "construction"
+ item_typepath = /obj/item/storage/pouch/tools/full
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/r_pocket/general
+ name = "General pouch"
+ desc = "A general purpose pouch used to carry small items."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/general/large
+ jobs_supported = list(STAFF_OFFICER, CAPTAIN)
+
+//l_pocket
+/datum/loadout_item/l_pocket
+ item_slot = ITEM_SLOT_L_POCKET
+
+/datum/loadout_item/l_pocket/empty
+ name = "no left pocket"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/l_pocket/standard_first_aid
+ name = "First aid pouch"
+ desc = "Standard marine first-aid pouch. Contains a basic set of medical supplies."
+ ui_icon = "medkit"
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol
+ jobs_supported = list(SQUAD_MARINE, SQUAD_ENGINEER, SQUAD_SMARTGUNNER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/standard_first_aid/standard_improved
+ desc = "Standard marine first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol_leader
+ loadout_item_flags = null
+
+/datum/loadout_item/l_pocket/standard_first_aid/improved
+ desc = "Standard marine first-aid pouch. Contains a improved set of medical supplies."
+ item_typepath = /obj/item/storage/pouch/firstaid/combat_patrol_leader
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/marine_support_grenades
+ name = "Support nades"
+ desc = "A pouch carrying a set of six standard support grenades. Includes smoke grenades of both lethal and nonlethal varieties, as well as stun grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/combat_patrol
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/l_pocket/marine_standard_grenades
+ name = "Standard nades"
+ desc = "A pouch carrying a set of six standard offensive grenades. Contains HE, lasburster and incendiary grenades."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/grenade/standard
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/l_pocket/shotgun
+ name = "Flechette shells"
+ desc = "A pouch specialized for holding shotgun ammo. Contains Flechette shells."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/shotgun
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER)
+
+/datum/loadout_item/l_pocket/shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/flechette, SLOT_IN_L_POUCH)
+
+/datum/loadout_item/l_pocket/marine_construction
+ name = "Construction pouch"
+ desc = "A pouch containing an assortment of construction supplies. Allows for the rapid establishment of fortified positions."
+ ui_icon = "materials"
+ item_typepath = /obj/item/storage/pouch/construction
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/l_pocket/marine_construction/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags_empty/half, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sandbags/large_stack, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/full, SLOT_IN_L_POUCH)
+
+/datum/loadout_item/l_pocket/magazine
+ name = "Mag pouch-S"
+ desc = "A pouch containing three ammo magazines. Will contain a secondary ammo type where applicable."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/magazine/large
+ jobs_supported = list(SQUAD_MARINE, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ item_blacklist = list(
+ /obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/minigun/smart_minigun/motion_detector = ITEM_SLOT_SUITSTORE,
+ )
+
+
+/datum/loadout_item/l_pocket/magazine/medic
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/l_pocket/general
+ name = "General pouch"
+ desc = "A general purpose pouch used to carry small items."
+ ui_icon = "grenade"
+ item_typepath = /obj/item/storage/pouch/general/large
+ jobs_supported = list(STAFF_OFFICER, CAPTAIN)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit.dm
new file mode 100644
index 0000000000000..e384506ead8e7
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit.dm
@@ -0,0 +1,188 @@
+/datum/loadout_item/suit_slot
+ item_slot = ITEM_SLOT_OCLOTHING
+
+/datum/loadout_item/suit_slot/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/isotonic, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclot, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/empty
+ name = "no suit"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/suit_slot/light_shield
+ name = "L shield armor"
+ desc = "Light armor with a Svallin shield module. Provides excellent mobility but lower protection."
+ ui_icon = "light_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/light/shield
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/suit_slot/light_shield/overclocked
+ desc = "Light armor with a Svallin shield module. Provides excellent mobility but lower protection. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/light_shield/overclocked/medic
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked/medic
+ jobs_supported = list(SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_slot/light_shield/overclocked/medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/light_shield/overclocked/engineer
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked/engineer
+ jobs_supported = list(SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_slot/light_shield/overclocked/engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/medium_shield
+ name = "M shield armor"
+ desc = "Medium armor with a Svallin shield module. Provides balanced mobility and protection."
+ ui_icon = "medium_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/shield
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/suit_slot/medium_shield/overclocked
+ desc = "Medium armor with a Svallin shield module. Provides balanced mobility and protection."
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/shield_overclocked
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/medium_shield/overclocked/medic
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/shield_overclocked/medic
+ jobs_supported = list(SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_slot/medium_shield/overclocked/medic/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/medium_shield/overclocked/engineer
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/shield_overclocked/engineer
+ jobs_supported = list(SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_slot/medium_shield/overclocked/engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
+
+/datum/loadout_item/suit_slot/heavy_shield
+ name = "H shield armor"
+ desc = "Heavy armor with a Svallin shield module. Provides excellent protection but lower mobility. The shield module has been overclocked for improved performance."
+ ui_icon = "heavy_armour_shield"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/heavy/shield
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/heavy_shield/overclocked
+ desc = "Heavy armor with a Svallin shield module. Provides excellent protection but lower mobility. The shield module has been overclocked for improved performance."
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/heavy/shield_overclocked
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = null
+
+/datum/loadout_item/suit_slot/heavy_surt
+ name = "H Surt armor"
+ desc = "Heavy armor with a Surt fireproof module. Provides excellent protection and almost total fire immunity, but has poor mobility."
+ ui_icon = "heavy_armour"
+ req_desc = "Requires a FL-84 flamethrower."
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/heavy/surt
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/wide = ITEM_SLOT_SUITSTORE)
+
+/datum/loadout_item/suit_slot/heavy_tyr
+ name = "H Tyr armor"
+ desc = "Heavy armor with a Tyr extra armor module. Provides incredible protection at the cost of with further reduced mobility."
+ req_desc = "Requires a ALF-51B or SMG-25."
+ ui_icon = "tyr"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/heavy/tyr_two
+ jobs_supported = list(SQUAD_MARINE)
+ item_whitelist = list(
+ /obj/item/weapon/gun/rifle/alf_machinecarbine/assault = ITEM_SLOT_SUITSTORE,
+ /obj/item/weapon/gun/smg/m25/magharness = ITEM_SLOT_SUITSTORE,
+ )
+
+/datum/loadout_item/suit_slot/heavy_tyr/smartgunner
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ item_whitelist = null
+
+/datum/loadout_item/suit_slot/medium_valk
+ name = "M Valkyrie armor"
+ desc = "Medium armor with a Valkyrie automedical module. Provides respectable protection, powerful automatic medical assistance, but modest mobility."
+ ui_icon = "medium_armour"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/valk
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+
+/datum/loadout_item/suit_slot/heavy_valk
+ name = "H Valkyrie armor"
+ desc = "Heavy armor with a Valkyrie automedical module. Provides excellent protection, powerful automatic medical assistance, but reduced mobility."
+ ui_icon = "heavy_armour"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/heavy/leader
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/white_dress
+ name = "Dress jacket"
+ desc = "The perfect white jacket to go with your white dress uniform. WARNING: Incompatible with almost all weapons."
+ item_typepath = /obj/item/clothing/suit/white_dress_jacket
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+//corpsman
+/datum/loadout_item/suit_slot/medium_mimir
+ name = "M Mimir armor"
+ desc = "Medium armor with a Mimir environmental protection module. Provides respectable armor and total immunity to chemical attacks, and improved radiological protection. Has modest mobility."
+ ui_icon = "medium_armour"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/mimir
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/medium_mimir/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_SUIT)
+
+//engineer
+/datum/loadout_item/suit_slot/medium_engineer
+ name = "M armor"
+ desc = "Medium armor with engineering storage. Provides balanced armor and mobility."
+ ui_icon = "medium_armour"
+ item_typepath = /obj/item/clothing/suit/modular/xenonauten/engineer
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_slot/medium_engineer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/high, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ wearer.equip_to_slot_or_del(new /obj/item/stack/barbed_wire/half_stack, SLOT_IN_SUIT)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage.dm
new file mode 100644
index 0000000000000..075ed95a295e2
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage.dm
@@ -0,0 +1,61 @@
+/datum/loadout_item/suit_store
+ item_slot = ITEM_SLOT_SUITSTORE
+
+/datum/loadout_item/suit_store/empty
+ name = "no suit stored"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/suit_store/main_gun
+ ///Ammo type this gun will use
+ var/ammo_type
+ ///alt ammo type for this gun
+ var/secondary_ammo_type
+
+/datum/loadout_item/suit_store/main_gun/New()
+ . = ..()
+ var/obj/item/weapon/gun/weapon_type = item_typepath
+ if(!ammo_type)
+ ammo_type = weapon_type::default_ammo_type
+ if(!secondary_ammo_type)
+ secondary_ammo_type = weapon_type::default_ammo_type
+
+/datum/loadout_item/suit_store/main_gun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!ammo_type)
+ return
+ if(istype(wearer.belt, /obj/item/storage/belt))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BELT)
+ if(istype(wearer.l_store, /obj/item/storage/pouch/magazine))
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_L_POUCH)
+ if(istype(wearer.r_store, /obj/item/storage/pouch/magazine))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/corpsman.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/corpsman.dm
new file mode 100644
index 0000000000000..61cbb778d5aa0
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/corpsman.dm
@@ -0,0 +1,298 @@
+/datum/loadout_item/suit_store/main_gun/corpsman
+ jobs_supported = list(SQUAD_CORPSMAN)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ if(loadout.l_store == /obj/item/storage/pouch/magazine/large)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ if(loadout.r_store == /obj/item/storage/pouch/magazine/large)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/laser_carbine
+ name = "Laser carbine"
+ desc = "Equipped with a red dot sight and underbarrel grenade launcher. The TerraGov laser carbine is the high tech equivilent to the AR-18, with extremely good mobility and handling, and powerful medium range damage. \
+ Variable firemodes gives it additional flexibility over its ballistic counterpart. Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/scout
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/corpsman/laser_carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/laser_rifle
+ name = "Laser rifle"
+ desc = "Equipped with amag harness, bayonet and miniflamer. The Terra Experimental laser rifle, is a powerful and flexible weapon thanks to a variety of firemodes. \
+ Has good mobility and excellent falloff, although lacks the power offered by weapons with an underbarrel grenade launcher.\
+ Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle/medic
+
+/datum/loadout_item/suit_store/main_gun/corpsman/laser_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/auto_shotgun
+ name = "SH-15"
+ desc = "Equipped with a mag harness and underbarrel grenade launcher. \
+ The SH-15 automatic shotgun has excellent mobility and handling, and offers powerful damage per shot. Its comparatively slow rate of fire means in a straight gunfight its overall damage output is somewhat lacking.\
+ Uses 12-round 16 gauge magazines with slugs and flechette."
+ ui_icon = "tx15"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_autoshotgun/engineer
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/tx15_flechette
+
+/datum/loadout_item/suit_store/main_gun/corpsman/auto_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/skirmish_rifle
+ name = "AR-21"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. \
+ The AR-21 is an less common rifle in the TGMC, attempting to bridge the gap between lighter, lower calibre rifles and heavier rifles like the BR-64. \
+ Its compromises between the two groups means it fails to particularly outshine any of them, but never the less is a respective and flexible rifle."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_skirmishrifle/standard
+
+/datum/loadout_item/suit_store/main_gun/corpsman/skirmish_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x25mm, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/standard_smg
+ name = "SMG-25"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses 10x20mm caseless ammunition."
+ ui_icon = "m25"
+ item_typepath = /obj/item/weapon/gun/smg/m25/magharness
+
+/datum/loadout_item/suit_store/main_gun/corpsman/standard_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/standard_smg/enhanced
+ name = "SMG-25+"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/m25/ap
+
+/datum/loadout_item/suit_store/main_gun/corpsman/carbine
+ name = "AR-18"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/standard
+
+/datum/loadout_item/suit_store/main_gun/corpsman/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/carbine/enhanced
+ name = "AR-18+"
+ desc = "Equipped with mag harness, extended barrel and vertical grip. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/corpsman/assault_rifle
+ name = "AR-12"
+ desc = "Equipped with mag harness, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses 10x24mm caseless ammunition."
+ ui_icon = "t12"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_assaultrifle/medic
+
+/datum/loadout_item/suit_store/main_gun/corpsman/assault_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/assault_rifle/enhanced
+ name = "AR-12+"
+ desc = "Equipped with mag harness, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+
+/datum/loadout_item/suit_store/main_gun/corpsman/combat_rifle
+ name = "AR-11"
+ desc = "Equipped with a red dot sight and laser sight. The AR-11 is an old rifle of the TGMC, but is now a relatively uncommon sight. \
+ It has a very large magazine capacity, and can inflict incredible damage at long range with its HV ammo, making it particularly effective at well armored targets. \
+ However it suffers from relatively poor handling and mobility, and lacks any underbarrel weapon attachments, making it an effective but less flexible weapon. It uses 4.92×34mm caseless HV ammunition."
+ ui_icon = "tx11"
+ item_typepath = /obj/item/weapon/gun/rifle/tx11/standard
+
+/datum/loadout_item/suit_store/main_gun/corpsman/combat_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/plasma_smg
+ name = "PL-51"
+ desc = "Unlocked for free with the Advanced SMG training perk. Equipped with a red dot sight, bayonet and vertical grip. The PL-51 plasma SMG is a powerful close range weapon, with great mobility and handling. \
+ Has two firemodes, with a standard reflecting shot, or a more powerful AOE overcharged shot. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/standard
+ unlock_cost = 400
+ purchase_cost = 40
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/corpsman/plasma_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/corpsman/plasma_rifle
+ name = "PL-38"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight, bayonet and miniflamer. The PL-38 plasma rifle is a powerful heavy rifle, able to unleash significant damage at any range. \
+ Has three firemodes, with a standard high ROF mode, a piercing shatter shot, or a melting blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/standard
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/corpsman/plasma_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/corpsman/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/engineer.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/engineer.dm
new file mode 100644
index 0000000000000..3bbd2479237ef
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/engineer.dm
@@ -0,0 +1,113 @@
+/datum/loadout_item/suit_store/main_gun/engineer
+ jobs_supported = list(SQUAD_ENGINEER)
+
+/datum/loadout_item/suit_store/main_gun/engineer/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/chem_grenade/razorburn_large, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/chem_grenade/razorburn_large, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/engineer/carbine
+ name = "AR-18"
+ desc = "Equipped with mag harness, extended barrel and vertical grip. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/engineer
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/engineer/carbine/enhanced
+ name = "AR-18+"
+ desc = "Equipped with mag harness, extended barrel and vertical grip. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/engineer/assault_rifle
+ name = "AR-12"
+ desc = "Equipped with mag harness, extended barrel and miniflamer. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses 10x24mm caseless ammunition."
+ ui_icon = "t12"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_assaultrifle/engineer
+
+/datum/loadout_item/suit_store/main_gun/engineer/assault_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/chem_grenade/razorburn_large, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/engineer/assault_rifle/enhanced
+ name = "AR-12+"
+ desc = "Equipped with mag harness, extended barrel and miniflamer. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+
+/datum/loadout_item/suit_store/main_gun/engineer/auto_shotgun
+ name = "SH-15"
+ desc = "Equipped with a mag harness and underbarrel grenade launcher. \
+ The SH-15 automatic shotgun has excellent mobility and handling, and offers powerful damage per shot. Its comparatively slow rate of fire means in a straight gunfight its overall damage output is somewhat lacking.\
+ Uses 12-round 16 gauge magazines with slugs and flechette."
+ ui_icon = "tx15"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_autoshotgun/engineer
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/tx15_flechette
+
+/datum/loadout_item/suit_store/main_gun/engineer/auto_shotgun/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/engineer/combat_rifle
+ name = "AR-11"
+ desc = "Equipped with a red dot sight and laser sight. The AR-11 is an old rifle of the TGMC, but is now a relatively uncommon sight. \
+ It has a very large magazine capacity, and can inflict incredible damage at long range with its HV ammo, making it particularly effective at well armored targets. \
+ However it suffers from relatively poor handling and mobility, and lacks any underbarrel weapon attachments, making it an effective but less flexible weapon. It uses 4.92×34mm caseless HV ammunition."
+ ui_icon = "tx11"
+ item_typepath = /obj/item/weapon/gun/rifle/tx11/standard
+
+/datum/loadout_item/suit_store/main_gun/engineer/laser_carbine
+ name = "Laser carbine"
+ desc = "Equipped with a red dot sight and gyroscopic stabilizer. The TerraGov laser carbine is the high tech equivilent to the AR-18, with extremely good mobility and handling, and powerful medium range damage. \
+ Variable firemodes gives it additional flexibility over its ballistic counterpart. Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/gyro
+
+/datum/loadout_item/suit_store/main_gun/engineer/standard_smg
+ name = "SMG-25"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses 10x20mm caseless ammunition."
+ ui_icon = "m25"
+ item_typepath = /obj/item/weapon/gun/smg/m25/vgrip
+
+/datum/loadout_item/suit_store/main_gun/engineer/standard_smg/enhanced
+ name = "SMG-25+"
+ desc = "Equipped with a mag harness, recoil compensator and vertical grip. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses a mix of standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/m25/ap
+
+/datum/loadout_item/suit_store/main_gun/engineer/plasma_smg
+ name = "PL-51"
+ desc = "Unlocked for free with the Advanced SMG training perk. Equipped with a red dot sight, bayonet and vertical grip. The PL-51 plasma SMG is a powerful close range weapon, with great mobility and handling. \
+ Has two firemodes, with a standard reflecting shot, or a more powerful AOE overcharged shot. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/standard
+ unlock_cost = 400
+ purchase_cost = 40
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/engineer/plasma_rifle
+ name = "PL-38"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight, bayonet and vertical grip. The PL-38 plasma rifle is a powerful heavy rifle, able to unleash significant damage at any range. \
+ Has three firemodes, with a standard high ROF mode, a piercing shatter shot, or a melting blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/v_grip
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/field_commander.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/field_commander.dm
new file mode 100644
index 0000000000000..472fe01842a03
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/field_commander.dm
@@ -0,0 +1,333 @@
+/datum/loadout_item/suit_store/officer_sword
+ name = "Officers sword"
+ desc = "This appears to be a rather old blade that has been well taken care of, it is probably a family heirloom. \
+ Well made and extremely sharp, despite its probable non-combat purpose. Comes in a leather scabbard that an attached to your waist or armor."
+ ui_icon = "machete"
+ item_typepath = /obj/item/storage/holster/blade/officer/full
+ jobs_supported = list(FIELD_COMMANDER)
+ item_blacklist = list(/obj/item/storage/holster/blade/officer/full = ITEM_SLOT_BELT)
+
+/datum/loadout_item/suit_store/officer_sword/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet/fieldcommand, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/fc_pistol
+ name = "P-1911A1-C pistol"
+ desc = "The P-1911A1-C is a custom modified pistol with impressive stopping power for its size. \
+ Light and easy to use one handed, it suffers from a small magazine size and no auto eject feature. Comes in a holster that fits on your waist or armor. Uses .45 ACP ammunition."
+ ui_icon = "m1911c"
+ item_typepath = /obj/item/storage/holster/belt/pistol/m4a3/fieldcommander
+ jobs_supported = list(FIELD_COMMANDER)
+ item_blacklist = list(/obj/item/storage/holster/belt/pistol/m4a3/fieldcommander = ITEM_SLOT_BELT)
+
+/datum/loadout_item/suit_store/fc_pistol/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet/fieldcommand, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander
+ jobs_supported = list(FIELD_COMMANDER)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(loadout.belt == /obj/item/storage/belt/marine)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet/fieldcommand, SLOT_IN_BACKPACK)
+ else
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+/datum/loadout_item/suit_store/main_gun/field_commander/pulse_rifle
+ name = "PR-11"
+ desc = "Equipped with a red dot sight, extended barrel and integrated underbarrel grenade launcher. The PR-11 is a relic from an earlier time. \
+ Larger and more cumbersome than modern rifles and lacking any precision aimming, it makes up for this with its tremendous magazine capacity, making it more akin to a light machinegun that a rifle. Uses 10x24mm caseless ammunition."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/m41a/field_commander
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/field_commander/pulse_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/combat_rifle
+ name = "AR-11"
+ desc = "Equipped with a red dot sight and laser sight. The AR-11 is an old rifle of the TGMC, but is now a relatively uncommon sight. \
+ It has a very large magazine capacity, and can inflict incredible damage at long range with its HV ammo, making it particularly effective at well armored targets. \
+ However it suffers from relatively poor handling and mobility, and lacks any underbarrel weapon attachments, making it an effective but less flexible weapon. It uses 4.92×34mm caseless HV ammunition."
+ ui_icon = "tx11"
+ item_typepath = /obj/item/weapon/gun/rifle/tx11/standard
+
+/datum/loadout_item/suit_store/main_gun/field_commander/combat_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/laser_rifle
+ name = "Laser rifle"
+ desc = "Equipped with a red dot sight, bayonet and miniflamer. The Terra Experimental laser rifle, is a powerful and flexible weapon thanks to a variety of firemodes. \
+ Has good mobility and excellent falloff, although lacks the power offered by weapons with an underbarrel grenade launcher.\
+ Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle/rifleman
+
+/datum/loadout_item/suit_store/main_gun/field_commander/laser_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/laser_mg
+ name = "Laser machinegun"
+ desc = "Equipped with a mag harness, bayonet and underbarrel grenade launcher. The Terra Experimental machine laser gun is a more flexible weapon than its ballistic counterparts. \
+ It has better mobility and handling than ballistic machineguns, which combined with its variable firemodes and underbarrel weaponry makes it effective in a variety of situations, \
+ but still ultimately excels at apply sustained supporting fire. Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser/patrol
+
+/datum/loadout_item/suit_store/main_gun/field_commander/laser_mg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/standard_rifle
+ name = "AR-12"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses 10x24mm caseless ammunition."
+ ui_icon = "t12"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_assaultrifle/rifleman
+
+/datum/loadout_item/suit_store/main_gun/field_commander/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/standard_rifle/enhanced
+ name = "AR-12+"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+
+/datum/loadout_item/suit_store/main_gun/field_commander/carbine
+ name = "AR-18"
+ desc = "Equipped with red dot sight, extended barrel and plasma pistol. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/plasma_pistol
+
+/datum/loadout_item/suit_store/main_gun/field_commander/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/carbine/enhanced
+ name = "AR-18+"
+ desc = "Equipped with red dot sight, extended barrel and plasma pistol. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/field_commander/plasma_smg
+ name = "PL-51"
+ desc = "Unlocked for free with the Advanced SMG training perk. Equipped with a motion sensor, bayonet and vertical grip. The PL-51 plasma SMG is a powerful close range weapon, with great mobility and handling. \
+ Has two firemodes, with a standard reflecting shot, or a more powerful AOE overcharged shot. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/motion_sensor
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/field_commander/plasma_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/field_commander/plasma_rifle
+ name = "PL-38"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight, bayonet and miniflamer. The PL-38 plasma rifle is a powerful heavy rifle, able to unleash significant damage at any range. \
+ Has three firemodes, with a standard high ROF mode, a piercing shatter shot, or a melting blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/standard
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/field_commander/plasma_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/marine.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/marine.dm
new file mode 100644
index 0000000000000..0875eb5b715ca
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/marine.dm
@@ -0,0 +1,815 @@
+/datum/loadout_item/suit_store/main_gun/marine
+ jobs_supported = list(SQUAD_MARINE)
+
+/datum/loadout_item/suit_store/main_gun/marine/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_rifle
+ name = "AR-12"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses 10x24mm caseless ammunition."
+ ui_icon = "t12"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_assaultrifle/rifleman
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_rifle/enhanced
+ name = "AR-12+"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_rifle/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_rifle
+ name = "Laser rifle"
+ desc = "Equipped with a red dot sight, bayonet and miniflamer. The Terra Experimental laser rifle, is a powerful and flexible weapon thanks to a variety of firemodes. \
+ Has good mobility and excellent falloff, although lacks the power offered by weapons with an underbarrel grenade launcher.\
+ Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle/rifleman
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_laser_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_carbine
+ name = "AR-18"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/standard
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_carbine/enhanced
+ name = "AR-18+"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_carbine/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/marine/combat_rifle
+ name = "AR-11"
+ desc = "Equipped with a red dot sight and laser sight. The AR-11 is an old rifle of the TGMC, but is now a relatively uncommon sight. \
+ It has a very large magazine capacity, and can inflict incredible damage at long range with its HV ammo, making it particularly effective at well armored targets. \
+ However it suffers from relatively poor handling and mobility, and lacks any underbarrel weapon attachments, making it an effective but less flexible weapon. It uses 4.92×34mm caseless HV ammunition."
+ ui_icon = "tx11"
+ item_typepath = /obj/item/weapon/gun/rifle/tx11/standard
+
+/datum/loadout_item/suit_store/main_gun/marine/combat_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p492x34mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p492x34mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/combat_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/battle_rifle
+ name = "BR-64"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. \
+ The BR-64 is considered a 'light' marksmen rifle, with good stopping power it can apply effective damage at any range, while still having respectible handling and mobility. Uses 10x26.5smm caseless ammunition."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_br/standard
+
+/datum/loadout_item/suit_store/main_gun/marine/battle_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x265mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/skirmish_rifle
+ name = "AR-21"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. \
+ The AR-21 is an less common rifle in the TGMC, attempting to bridge the gap between lighter, lower calibre rifles and heavier rifles like the BR-64. \
+ Its compromises between the two groups means it fails to particularly outshine any of them, but never the less is a respective and flexible rifle."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_skirmishrifle/standard
+
+/datum/loadout_item/suit_store/main_gun/marine/skirmish_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x25mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/alf
+ name = "ALF-51B"
+ desc = "Equipped with a mag harness, bayonet and vertical grip. The ALF-51B is an unusual weapon, being a heavily modified AR-18 modified to SMG length of barrel, rechambered for a larger caliber, and belt fed. \
+ Combining its powerful close range damage that can slow targets, impressive mobility and huge capacity, it is a devastating close range weapon. \
+ However it suffers from appaling falloff making it highly ineffective at range, and its belt fed nature means it cannot be reloaded quickly, often leaving careless users exposed. Uses 10x25mm caseless ammunition."
+ ui_icon = "alf51b"
+ item_typepath = /obj/item/weapon/gun/rifle/alf_machinecarbine/assault
+
+/datum/loadout_item/suit_store/main_gun/marine/alf/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/alf/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/flashbang/stun, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_gpmg
+ name = "MG-60"
+ desc = "Equipped with a mag harness, extended barrel and bipod. The MG-60 is a powerful machinegun, combining a tremendous capacity good stopping power and blistering rate of fire, it is extremely deadly at any range. \
+ It has terrible mobility and poor accuracy on the move, so is generally used as a static weapon where it can lay down blistering firepower for team mates. It uses 10x26mm caseless ammunition."
+ ui_icon = "t60"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_gpmg/machinegunner
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_gpmg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_gpmg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ if(!isstorage(wearer.back))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_mmg
+ name = "MG-27"
+ desc = "Equipped with an unremovable miniscope and tripod. The MG-27 is large, unwieldy machinegun, with terrible mobility and effectively unmanagable handling outside of point blank range. \
+ However the MG-27 is primary used as a deployed weapon, where it offers devastatingly powerful, accurate and long range damage that far exceeds the lighter MG-60. \
+ Can quickly mow down any target caught out in the open, it is the final word in static weaponry. It uses 10x27mm caseless ammunition."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/standard_mmg/machinegunner
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_mmg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(istype(wearer.belt, /obj/item/storage/holster/m25))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(wearer), SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_mmg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ if(istype(wearer.belt, /obj/item/storage/holster/m25))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_ACCESSORY)
+ else if(isstorage(wearer.back))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_mg
+ name = "Laser machinegun"
+ desc = "Equipped with a mag harness, bayonet and underbarrel grenade launcher. The Terra Experimental machine laser gun is a more flexible weapon than its ballistic counterparts. \
+ It has better mobility and handling than ballistic machineguns, which combined with its variable firemodes and underbarrel weaponry makes it effective in a variety of situations, \
+ but still ultimately excels at apply sustained supporting fire. Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser/patrol
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_mg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_mg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/flamer
+ name = "FL-84"
+ desc = "Equipped with a mag harness, wide nozzle and hydrocannon. The FL-84 flamethrower is a simple and unsubtle weapon, used for area control and urban combat. \
+ Excels at clearing out enclosed or fortified positions, but suffers from poor mobility and relatively limited range, making it of questionable use in open combat. \
+ Uses back or gun mounted fuel tanks."
+ req_desc = "Requires a suit with a Surt module."
+ ui_icon = "m240"
+ item_typepath = /obj/item/weapon/gun/flamer/big_flamer/marinestandard/wide
+ item_whitelist = list(/obj/item/clothing/suit/modular/xenonauten/heavy/surt = ITEM_SLOT_OCLOTHING)
+
+/datum/loadout_item/suit_store/main_gun/marine/flamer/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(istype(wearer.belt, /obj/item/storage/holster/m25))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(wearer), SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/large/X, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/flamer/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ if(istype(wearer.belt, /obj/item/storage/holster/m25))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_ACCESSORY)
+ else if(isstorage(wearer.back))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+
+
+/datum/loadout_item/suit_store/main_gun/marine/shotgun
+ name = "SH-35"
+ desc = "Equipped with a mag harness, bayonet, angled grip and foldable stock. \
+ The SH-35 is the most commonly used shotgun of the TGMC. With good mobility and handling, it has unparalleled close range power when using buckshot. Able to kill or maim all but the most heavily armored targets with a single well aimmed blast. \
+ When using flechette rounds, it can provide surprisingly powerful long range damage with good penetration, although its low rate of fire means its sustained damage is relatively poor. \
+ Uses 12 gauge shells."
+ ui_icon = "t35"
+ item_typepath = /obj/item/weapon/gun/shotgun/pump/t35/standard
+
+/datum/loadout_item/suit_store/main_gun/marine/shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(wearer), SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/shotgun/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/auto_shotgun
+ name = "SH-15"
+ desc = "Equipped with a mag harness, barrel charger and underbarrel grenade launcher. \
+ The SH-15 automatic shotgun has excellent mobility and handling, and offers powerful damage per shot. Its comparatively slow rate of fire means in a straight gunfight its overall damage output is somewhat lacking.\
+ Uses 12-round 16 gauge magazines with slugs and flechette."
+ ui_icon = "tx15"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_autoshotgun/standard
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/tx15_flechette
+
+/datum/loadout_item/suit_store/main_gun/marine/auto_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_carbine
+ name = "Laser carbine"
+ desc = "Equipped with a red dot sight and underbarrel grenade launcher. The TerraGov laser carbine is the high tech equivilent to the AR-18, with extremely good mobility and handling, and powerful medium range damage. \
+ Variable firemodes gives it additional flexibility over its ballistic counterpart. Uses TE power cells that are shared across all TGMC laser weaponry."
+ req_desc = "Requires a light armour suit."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/scout
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/laser_carbine/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_carbine
+ name = "AR-18-scout"
+ desc = "Equipped with motion detector, extended barrel and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. \
+ The motion detector on this example makes it excellent for scouting out enemy positions and tracking down hidden enemies. Uses 10x24mm caseless ammunition."
+ req_desc = "Requires a light armour suit."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/scout
+ item_whitelist = list(
+ /obj/item/clothing/suit/modular/xenonauten/light/shield = ITEM_SLOT_OCLOTHING,
+ /obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked = ITEM_SLOT_OCLOTHING,
+ )
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_carbine/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ if(istype(wearer.back, /obj/item/storage))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_carbine/enhanced
+ name = "AR-18-S+"
+ desc = "Equipped with motion detector, extended barrel and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. \
+ The motion detector on this example makes it excellent for scouting out enemy positions and tracking down hidden enemies. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/smg_and_shield
+ name = "SMG-25 & shield"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer, and comes with a TL-172 defensive shield. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. \
+ The defensive shield provides incredible resilience, allowing the user to soak up tremendous amounts of damage while they or their team mates push the enemy. \
+ Generally used with Tyr heavy armor for maximum survivability. Uses 10x20mm caseless ammunition."
+ ui_icon = "riot_shield"
+ item_typepath = /obj/item/weapon/gun/smg/m25/magharness
+ item_blacklist = list(/obj/item/jetpack_marine/heavy = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/smg_and_shield/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine, SLOT_L_HAND)
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/smg_and_shield/enhanced
+ name = "SMG-25+ & riot shield"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer, and comes with a TL-172 defensive shield. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. \
+ The defensive shield provides incredible resilience, allowing the user to soak up tremendous amounts of damage while they or their team mates push the enemy. \
+ Generally used with Tyr heavy armor for maximum survivability. Uses standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/m25/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_smg
+ name = "SMG-25"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses 10x20mm caseless ammunition."
+ ui_icon = "m25"
+ item_typepath = /obj/item/weapon/gun/smg/m25/magharness
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x20mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ if(istype(wearer.belt, /obj/item/storage/belt))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/standard_smg/enhanced
+ name = "SMG-25+"
+ desc = "Equipped with a mag harness, recoil compensator and gyroscopic stabilizer. SMG-25 submachinegun, is a large capacity smg, able to be be used effectively one or two handed. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/m25/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_rifle
+ name = "BR-8"
+ desc ="Equipped with a red dot sight, extended barrel and vertical grip. The BR-8 is a light specialized scout rifle, mostly used by light infantry and scouts. \
+ It has great mobility and handling, excellent accuracy and perfect damage application at range. Combined with innate IFF and a variety of high powered ammo types, the BR-8 is a weapon to be feared. \
+ Takes specialized overpressured 10x28mm rounds."
+ req_desc = "Requires a light armour suit."
+ ui_icon = "scout"
+ item_typepath = /obj/item/weapon/gun/rifle/tx8/scout
+ item_whitelist = list(
+ /obj/item/clothing/suit/modular/xenonauten/light/shield = ITEM_SLOT_OCLOTHING,
+ /obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked = ITEM_SLOT_OCLOTHING,
+ )
+ purchase_cost = 100
+ quantity = 2
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/scanner(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/scout_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ if(istype(wearer.belt, /obj/item/storage/belt))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx8/incendiary, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx8/incendiary, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx8/impact, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx8/impact, SLOT_IN_BELT)
+
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine
+ name = "AR-18-Suppressed"
+ desc = "Equipped with red dot sight, suppressor and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. \
+ This suppressed variant is typically used for stealth operations, where its quiet firing and lack of tracers can give the user an edge over unsuspecting opponents. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/suppressed
+
+/datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/mirage, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine/enhanced
+ name = "AR-18-Suppressed+"
+ desc = "Equipped with red dot sight, suppressor and underbarrel grenade launcher. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. \
+ This suppressed variant is typically used for stealth operations, where its quiet firing and lack of tracers can give the user an edge over unsuspecting opponents. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine/enhanced/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ return ..()
+
+/datum/loadout_item/suit_store/main_gun/marine/mag_gl
+ name = "GL-54"
+ desc = "Equipped with a motion sensor. The GL-54 is a magazine fed, semi-automatic grenade launcher designed to shoot airbursting smart grenades. \
+ A powerful support weapon, but unwieldy at close range where it can be easily overwhelmed. \
+ Comes with a variety of 20mm grenade types."
+ ui_icon = "ballistic"
+ purchase_cost = 75
+ quantity = 2
+ item_typepath = /obj/item/weapon/gun/rifle/tx54/motion_sensor
+
+/datum/loadout_item/suit_store/main_gun/marine/mag_gl/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/smoke/dense, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/smoke/acid, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/razor, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/mag_gl/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ if(istype(wearer.belt, /obj/item/storage/belt))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/smoke/acid, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/incendiary, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/incendiary, SLOT_IN_BELT)
+
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_smg
+ name = "PL-51"
+ desc = "Unlocked for free with the Advanced SMG training perk. Equipped with a motion sensor, bayonet and vertical grip. The PL-51 plasma SMG is a powerful close range weapon, with great mobility and handling. \
+ Has two firemodes, with a standard reflecting shot, or a more powerful AOE overcharged shot. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/motion_sensor
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_smg/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_rifle
+ name = "PL-38"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight, bayonet and miniflamer. The PL-38 plasma rifle is a powerful heavy rifle, able to unleash significant damage at any range. \
+ Has three firemodes, with a standard high ROF mode, a piercing shatter shot, or a melting blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/standard
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_rifle/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_cannon
+ name = "PL-96"
+ desc = "Unlocked for free with the Heavy weapon specialisation perk. Equipped with a magharness. The PL-96 plasma cannon is massive, cumbersome weapon, designed to unleash devastating damage against all targets. \
+ Has three firemodes, with a plasma wave mode, that scales in damage against larger targets, a shatter blast mode, or an incendiary blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/cannon/mag_harness
+ unlock_cost = 400
+ purchase_cost = 80
+ quantity = 3
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_cannon/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/marine/plasma_cannon/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/bullet/laser, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/smartgunner.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/smartgunner.dm
new file mode 100644
index 0000000000000..44c72d3d4d543
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/smartgunner.dm
@@ -0,0 +1,95 @@
+/datum/loadout_item/suit_store/main_gun/smartgunner
+ jobs_supported = list(SQUAD_SMARTGUNNER)
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smartmachinegun
+ name = "SG-29"
+ desc = "Equipped with a motion sensor and laser sight. The SG-29 is the TGMC's current standard IFF-capable medium machine gun. \
+ It has good mobility for a machinegun, and is extremely effective on the move. Its innate IFF, good damage application and attached motion sensor makes it a powerful support weapon. \
+ Has somewhat poor falloff however, and although it has an excellent capacity, has slow reloading. It uses 10x26mm caseless ammunition. \
+ Requires special training and it cannot turn off IFF. It uses 10x26mm ammunition."
+ ui_icon = "sg29"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smartmachinegun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smart_minigun
+ name = "SG-85"
+ desc = "Equipped with a motion sensor. The SG-85 is a monstrous IFF minigun, able to unleash an incredible torrent of bullets with a tremendous capacity thanks to its back mounted ammo supply. \
+ With excellent armor penetration and minimal falloff, the SG-85 is a supreme support weapon, able to effective apply damage at any range, causing hideous amounts of shrapnel to anyone it doesn't kill."
+ req_desc = "Requires a powerback for power and ammo. It uses 10x26mm caseless ammunition"
+ ui_icon = "smartgun"
+ item_typepath = /obj/item/weapon/gun/minigun/smart_minigun/motion_detector
+ item_whitelist = list(/obj/item/ammo_magazine/minigun_powerpack/smartgun = ITEM_SLOT_BACK)
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smart_minigun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(loadout.belt == /obj/item/storage/belt/sparepouch)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/smart_minigun, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/smart_minigun, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(wearer), SLOT_IN_BELT)
+
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_ACCESSORY)
+
+ else
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smarttargetrifle
+ name = "SG-62"
+ desc = "Equipped with a motio sensor and spotting rifle. The SG-62 is a IFF precision rifle that has accurate, long range stopping power combined with the utility of its attached spotting rifle. \
+ The spotting rifle can use a variety of ammo types to suit a variety of situations, but the gun has relatively poor mobility and handling. Good for the smartgunner that favors precision over volume of fire. \
+ It uses high velocity 10x27mm caseless ammunition and 12x66mm ammunition for the underslung rifle."
+ ui_icon = "smartgun"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_smarttargetrifle/motion
+
+/datum/loadout_item/suit_store/main_gun/smartgunner/smarttargetrifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/highimpact, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/highimpact, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/tungsten, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/tungsten, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/highimpact, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/highimpact, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+
+ if(!istype(wearer.back, /obj/item/storage/backpack/marine/satchel))
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_spottingrifle/tungsten, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/squad_leader.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/squad_leader.dm
new file mode 100644
index 0000000000000..f35179cace5d9
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/suit_storage/squad_leader.dm
@@ -0,0 +1,368 @@
+/datum/loadout_item/suit_store/main_gun/squad_leader
+ jobs_supported = list(SQUAD_LEADER)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_rifle
+ name = "AR-12"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses 10x24mm caseless ammunition."
+ ui_icon = "t12"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_assaultrifle/rifleman
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_rifle/enhanced
+ name = "AR-12+"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. The AR-12 is the former main weapon of the TGMC before it was superceded by the AR-18 for general issue. \
+ A jack of all trades weapon, effect at close and long range, with good capacity and handling, making it a reliable all-rounder. \
+ It does not particularly excel in any area however, and so is overshadowed by other weapons at particular tasks. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/laser_rifle
+ name = "Laser rifle"
+ desc = "Equipped with a red dot sight, bayonet and miniflamer. The Terra Experimental laser rifle, is a powerful and flexible weapon thanks to a variety of firemodes. \
+ Has good mobility and excellent falloff, although lacks the power offered by weapons with an underbarrel grenade launcher.\
+ Uses TE power cells that are shared across all TGMC laser weaponry."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle/rifleman
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/laser_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/carbine
+ name = "AR-18"
+ desc = "Equipped with red dot sight, extended barrel and plasma pistol. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. Uses 10x24mm caseless ammunition."
+ ui_icon = "t18"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_carbine/plasma_pistol
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/carbine/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/carbine/enhanced
+ name = "AR-18+"
+ desc = "Equipped with red dot sight, extended barrel and plasma pistol. The AR-18 is the main weapon of the TGMC, offering excellent mobility and impressive close to medium range damage output. \
+ Compared to the AR-12, it suffers from a comparatively smaller magazine size, and is less effective at longer range. It uses a mix of standard and AP 10x24mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine/ap
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/combat_rifle
+ name = "AR-11"
+ desc = "Equipped with a red dot sight and laser sight. The AR-11 is an old rifle of the TGMC, but is now a relatively uncommon sight. \
+ It has a very large magazine capacity, and can inflict incredible damage at long range with its HV ammo, making it particularly effective at well armored targets. \
+ However it suffers from relatively poor handling and mobility, and lacks any underbarrel weapon attachments, making it an effective but less flexible weapon. It uses 4.92×34mm caseless HV ammunition."
+ ui_icon = "tx11"
+ item_typepath = /obj/item/weapon/gun/rifle/tx11/standard
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/combat_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p492x34mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/battle_rifle
+ name = "BR-64"
+ desc = "Equipped with red dot sight, extended barrel and underbarrel grenade launcher. \
+ The BR-64 is considered a 'light' marksmen rifle, with good stopping power it can apply effective damage at any range, while still having respectible handling and mobility. Uses 10x26.5smm caseless ammunition."
+ ui_icon = "ballistic"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_br/standard
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/battle_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/sticky, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x265mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x265mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/auto_shotgun
+ name = "SH-15"
+ desc = "Equipped with a motion sensor, extended barrel and plasma pistol. \
+ The SH-15 automatic shotgun has excellent mobility and handling, and offers powerful damage per shot. Its comparatively slow rate of fire means in a straight gunfight its overall damage output is somewhat lacking.\
+ Uses 12-round 16 gauge magazines with slugs and flechette."
+ ui_icon = "tx15"
+ item_typepath = /obj/item/weapon/gun/rifle/standard_autoshotgun/plasma_pistol
+ secondary_ammo_type = /obj/item/ammo_magazine/rifle/tx15_flechette
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/auto_shotgun/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/oicw
+ name = "AR-55"
+ desc = "Equipped with a motion sensor, recoil compensator, vertical grip and integrated GL-54. \
+ The AR-55 is effectively a GL-54 with a simplified AR-18 strapped to the bottom. It has all the flexible airbursting power of the GL-54 combined with the reliable damage of an assault rifle. \
+ While even more bulky and cumbersome than just the GL-54 alone, and the rifle component is inferior to the AR-18 it is derived from, the AR-55 is a far more effective weapon than the sum of its parts. \
+ Uses 10x24mm caseless ammunition and 20mm airburst grenades."
+ ui_icon = "tx55"
+ item_typepath = /obj/item/weapon/gun/rifle/tx55/combat_patrol
+ purchase_cost = 100
+ quantity = 2
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/oicw/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p10x24mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/oicw/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ if(loadout.belt == /obj/item/storage/belt/marine)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/incendiary, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54/incendiary, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_BELT)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_BELT)
+ if(loadout.l_store == /obj/item/storage/pouch/magazine/large)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_L_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_L_POUCH)
+ if(loadout.r_store == /obj/item/storage/pouch/magazine/large)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_R_POUCH)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx54, SLOT_IN_R_POUCH)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_smg
+ name = "SMG-25"
+ desc = "Equipped with a mag harness, recoil compensator and plasma pistol. SMG-25 submachinegun, is a large capacity smg, intended to be used two handed to take advantage of the attached plasma pistol. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses 10x20mm caseless ammunition, and comes with multiple ammo types."
+ ui_icon = "m25"
+ item_typepath = /obj/item/weapon/gun/smg/m25/plasma
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ if(!isstorage(wearer.back)) //bruh
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/extended, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new secondary_ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new ammo_type, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/standard_smg/enhanced
+ name = "SMG-25+"
+ desc = "Equipped with a mag harness, recoil compensator and plasma pistol. SMG-25 submachinegun, is a large capacity smg, intended to be used two handed to take advantage of the attached plasma pistol. \
+ Like all smgs, it has excellent mobility and handling, but has poor damage application at longer ranges. Uses standard and AP 10x20mm caseless ammunition."
+ loadout_item_flags = NONE
+ secondary_ammo_type = /obj/item/ammo_magazine/smg/m25/ap
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_smg
+ name = "PL-51"
+ desc = "Unlocked for free with the Advanced SMG training perk. Equipped with a motion sensor, bayonet and vertical grip. The PL-51 plasma SMG is a powerful close range weapon, with great mobility and handling. \
+ Has two firemodes, with a standard reflecting shot, or a more powerful AOE overcharged shot. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/motion_sensor
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_smg/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/m15, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/incendiary, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p492x34mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_rifle
+ name = "PL-38"
+ desc = "Unlocked for free with the Advanced rifle training perk. Equipped with a red dot sight, bayonet and miniflamer. The PL-38 plasma rifle is a powerful heavy rifle, able to unleash significant damage at any range. \
+ Has three firemodes, with a standard high ROF mode, a piercing shatter shot, or a melting blast mode. Like all plasma weapons, it can rapidly build up heat and overheat, rendering it inoperable for a period if used incorrectly."
+ ui_icon = "lasergun"
+ item_typepath = /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/standard
+ unlock_cost = 400
+ purchase_cost = 50
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE
+
+/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_rifle/post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ . = ..()
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign, SLOT_IN_ACCESSORY)
+
+ if(!isstorage(wearer.back))
+ return
+
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/deployable_camera, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/hud_tablet(wearer, /datum/job/terragov/squad/leader, wearer.assigned_squad), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p492x34mm, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/tactical(wearer), SLOT_IN_BACKPACK)
+ wearer.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
diff --git a/code/datums/gamemodes/campaign/loadout_items/_TGMC/uniform.dm b/code/datums/gamemodes/campaign/loadout_items/_TGMC/uniform.dm
new file mode 100644
index 0000000000000..61b4991c8c929
--- /dev/null
+++ b/code/datums/gamemodes/campaign/loadout_items/_TGMC/uniform.dm
@@ -0,0 +1,120 @@
+/datum/loadout_item/uniform
+ item_slot = ITEM_SLOT_ICLOTHING
+
+/datum/loadout_item/uniform/empty
+ name = "no uniform"
+ desc = ""
+ ui_icon = "empty"
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+ jobs_supported = list(
+ SQUAD_MARINE,
+ SQUAD_CORPSMAN,
+ SQUAD_ENGINEER,
+ SQUAD_SMARTGUNNER,
+ SQUAD_LEADER,
+ FIELD_COMMANDER,
+ STAFF_OFFICER,
+ CAPTAIN,
+ SOM_SQUAD_MARINE,
+ SOM_SQUAD_CORPSMAN,
+ SOM_SQUAD_ENGINEER,
+ SOM_SQUAD_VETERAN,
+ SOM_SQUAD_LEADER,
+ SOM_FIELD_COMMANDER,
+ SOM_STAFF_OFFICER,
+ SOM_COMMANDER,
+ )
+
+
+/datum/loadout_item/uniform/marine_standard
+ name = "TGMC uniform"
+ desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented marine uniform. You suspect it's not as robust-proof as advertised."
+ item_typepath = /obj/item/clothing/under/marine/black_vest
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/red_fatigue
+ name = "Big Red fatigues"
+ desc = "Originated from Big Red. Designed for dry, low humid, and Mars-eqse environments, they're meant for recon, stealth, and evac operations. \
+ They come with a built in cassette player hearable only to the user to help pass time, during any possible long waits. They make you feel like one with the desert, \
+ forged by the beating Sun. Rumors had it that it can recycle your sweat and urine for drinkable water!"
+ item_typepath = /obj/item/clothing/under/marine/red_fatigue/black_vest
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+
+/datum/loadout_item/uniform/striped_fatigue
+ name = "Striped fatigues"
+ desc = "A simple set of camo pants and a striped shirt."
+ item_typepath = /obj/item/clothing/under/marine/striped/black_vest
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+
+/datum/loadout_item/uniform/lv_fatigue
+ name = "LV-624 fatigues"
+ desc = "Originated from LV-624. Designed for wet, high humid, and jungle environments, they're meant for recon, stealth, and evac operations. \
+ They come with a built in cassette player hearable only to the user to help pass time, during any possible long waits. \
+ Somewhere, someone is playing 'Fortunate Sons' in the background, and you can smell napalm and Agent Orange in the air..."
+ item_typepath = /obj/item/clothing/under/marine/lv_fatigue/black_vest
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+
+/datum/loadout_item/uniform/orion_fatigue
+ name = "Orion fatigues"
+ desc = "Originated from Orion Military Outpost. Designed for ship and urban environments, they're meant for recon, stealth, and evac operations. \
+ They come with a built in cassette player hearable only to the user to help pass time, during any possible long waits. They're the definition of over-funded ideas, \
+ least they look neat. It is very likely that a boot fresh from boot camp to buy this at the BX with his E-1 pay because of how tacticool it looks."
+ item_typepath = /obj/item/clothing/under/marine/orion_fatigue/black_vest
+ jobs_supported = list(SQUAD_MARINE, SQUAD_SMARTGUNNER, SQUAD_LEADER)
+
+/datum/loadout_item/uniform/white_dress
+ name = "white dress uniform"
+ desc = "A standard-issue TerraGov Marine Corps white dress uniform. \
+ The starch in the fabric chafes a small amount but it pales in comparison to the pride you feel when you first put it on during graduation from boot camp. Doesn't seem to fit perfectly around the waist though."
+ item_typepath = /obj/item/clothing/under/marine/whites
+ jobs_supported = list(SQUAD_MARINE, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_SMARTGUNNER, SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN)
+
+//corpsman
+/datum/loadout_item/uniform/marine_corpsman
+ name = "corpsman fatigues"
+ desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented combat corpsman fatigues. You suspect it's not as robust-proof as advertised."
+ item_typepath = /obj/item/clothing/under/marine/corpsman/corpman_vest
+ jobs_supported = list(SQUAD_CORPSMAN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+/datum/loadout_item/uniform/marine_corpsman/role_post_equip(mob/living/carbon/human/wearer, datum/outfit/quick/loadout)
+ wearer.equip_to_slot_or_del(new /obj/item/bodybag/cryobag, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/roller, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/tweezers_advanced, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/nanoblood, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/spaceacillin, SLOT_IN_ACCESSORY)
+ wearer.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/combat_advanced, SLOT_IN_ACCESSORY)
+
+//engineer
+/datum/loadout_item/uniform/marine_engineer
+ name = "Engineer fatigues"
+ desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented combat engineer fatigues. You suspect it's not as robust-proof as advertised."
+ req_desc = "Requires a tool pouch. You ARE an engineer, right?"
+ item_typepath = /obj/item/clothing/under/marine/engineer/black_vest
+ jobs_supported = list(SQUAD_ENGINEER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//FC
+/datum/loadout_item/uniform/field_commander
+ name = "FC uniform"
+ desc = "A special-issue, kevlar-weaved, hazmat-tested, EMF-augmented worn by a field-grade officer of the TGMC. You suspect it's not as robust-proof as advertised."
+ item_typepath = /obj/item/clothing/under/marine/officer/exec/webbing
+ jobs_supported = list(FIELD_COMMANDER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//Staff officer
+/datum/loadout_item/uniform/staff_officer
+ name = "SO uniform"
+ desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented staff officer uniform. Do the navy proud."
+ item_typepath = /obj/item/clothing/under/marine/officer/bridge
+ jobs_supported = list(STAFF_OFFICER)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
+
+//Captain
+/datum/loadout_item/uniform/captain_officer
+ name = "Captain uniform"
+ desc = "A special-issue, well-ironed, kevlar-weaved, hazmat-tested, EMF-augmented uniform worth of a TerraGov Naval Captain. Even looking at it the wrong way could result in being court-martialed."
+ item_typepath = /obj/item/clothing/under/marine/officer/command
+ jobs_supported = list(CAPTAIN)
+ loadout_item_flags = LOADOUT_ITEM_ROUNDSTART_OPTION|LOADOUT_ITEM_DEFAULT_CHOICE
diff --git a/code/datums/gamemodes/campaign/missions/airbase_raid.dm b/code/datums/gamemodes/campaign/missions/airbase_raid.dm
index 166d180f1a9f4..c9427b83fc7eb 100644
--- a/code/datums/gamemodes/campaign/missions/airbase_raid.dm
+++ b/code/datums/gamemodes/campaign/missions/airbase_raid.dm
@@ -26,8 +26,6 @@
)
starting_faction_additional_rewards = "Disrupt enemy air support for a moderate period of time."
hostile_faction_additional_rewards = "Ensure continued access to close air support. Recon mech and gorgon armor available if you successfully protect this depot."
- ///The mech spawner type to create a mech for the defending team
- var/mech_type = /obj/effect/landmark/campaign/mech_spawner/som
/datum/campaign_mission/destroy_mission/airbase/play_start_intro()
intro_message = list(
@@ -62,13 +60,13 @@
/datum/campaign_mission/destroy_mission/airbase/apply_minor_loss()
winning_faction = hostile_faction
var/datum/faction_stats/winning_team = mode.stat_list[hostile_faction]
- winning_team.add_asset(/obj/effect/landmark/campaign/mech_spawner/som/light)
+ winning_team.add_asset(/datum/campaign_asset/mech/light/som)
winning_team.add_asset(/datum/campaign_asset/equipment/gorgon_armor)
/datum/campaign_mission/destroy_mission/airbase/apply_major_loss()
winning_faction = hostile_faction
var/datum/faction_stats/winning_team = mode.stat_list[hostile_faction]
- winning_team.add_asset(/obj/effect/landmark/campaign/mech_spawner/som/light)
+ winning_team.add_asset(/datum/campaign_asset/mech/light/som)
winning_team.add_asset(/datum/campaign_asset/equipment/gorgon_armor)
/datum/campaign_mission/destroy_mission/airbase/som
@@ -80,5 +78,4 @@
map_light_levels = list(225, 150, 100, 75)
objectives_total = 8
min_destruction_amount = 5
- mech_type = /obj/effect/landmark/campaign/mech_spawner
hostile_faction_additional_rewards = "Ensure continued access to close air support. B18 power armour available if you successfully protect this depot."
diff --git a/code/datums/gamemodes/campaign/missions/asat_capture.dm b/code/datums/gamemodes/campaign/missions/asat_capture.dm
index b34b6c29f1bae..a295e1a7411cb 100644
--- a/code/datums/gamemodes/campaign/missions/asat_capture.dm
+++ b/code/datums/gamemodes/campaign/missions/asat_capture.dm
@@ -2,11 +2,13 @@
/datum/campaign_mission/capture_mission/asat
name = "ASAT capture"
mission_icon = "asat_capture"
- map_name = "Lawanka outpost"
+ map_name = "Lawanka Outpost"
map_file = '_maps/map_files/Lawanka_Outpost/LawankaOutpost.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_RAIN = TRUE)
map_light_colours = list(LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN)
mission_flags = MISSION_DISALLOW_TELEPORT
+ max_game_time = 9 MINUTES
+ game_timer_delay = 90 SECONDS
shutter_open_delay = list(
MISSION_STARTING_FACTION = 90 SECONDS,
MISSION_HOSTILE_FACTION = 0,
@@ -39,17 +41,44 @@
starting_faction_additional_rewards = "Additional ICC support, ability to counteract TGMC drop pod usage"
hostile_faction_additional_rewards = "Preserve the ability to use drop pods uncontested"
- objectives_total = 5
- min_capture_amount = 3
+ objectives_total = 6
+ min_capture_amount = 5
/datum/campaign_mission/capture_mission/asat/load_pre_mission_bonuses()
. = ..()
- spawn_mech(hostile_faction, 0, 0, 3)
- spawn_mech(starting_faction, 0, 2)
+ spawn_mech(hostile_faction, 0, 0, 5)
+ spawn_mech(starting_faction, 0, 1, 1)
+
+ var/datum/faction_stats/attacking_team = mode.stat_list[starting_faction]
+ attacking_team.add_asset(/datum/campaign_asset/asset_disabler/som_cas/instant)
/datum/campaign_mission/capture_mission/asat/load_objective_description()
starting_faction_objective_description = "Major Victory:Capture all [objectives_total] ASAT systems.[min_capture_amount ? " Minor Victory: Capture at least [min_capture_amount] ASAT systems." : ""]"
- hostile_faction_objective_description = "Major Victory:Prevent the capture of all [objectives_total] ASAT systems.[min_capture_amount ? " Minor Victory: Prevent the capture of atleast [min_capture_amount] ASAT systems." : ""]"
+ hostile_faction_objective_description = "Major Victory:Prevent the capture of all [objectives_total] ASAT systems.[min_capture_amount ? " Minor Victory: Prevent the capture of atleast [objectives_total - min_capture_amount + 1] ASAT systems." : ""]"
+
+/datum/campaign_mission/capture_mission/asat/check_mission_progress()
+ if(outcome)
+ return TRUE
+
+ if(!game_timer)
+ return FALSE
+
+ if(!max_time_reached && objectives_remaining)
+ return FALSE
+
+ if(capture_count[MISSION_STARTING_FACTION] >= objectives_total)
+ message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_VICTORY]")
+ outcome = MISSION_OUTCOME_MAJOR_VICTORY
+ else if(min_capture_amount && (capture_count[MISSION_STARTING_FACTION] >= min_capture_amount))
+ message_admins("Mission finished: [MISSION_OUTCOME_MINOR_VICTORY]")
+ outcome = MISSION_OUTCOME_MINOR_VICTORY
+ else if(capture_count[MISSION_STARTING_FACTION] > 0)
+ message_admins("Mission finished: [MISSION_OUTCOME_MINOR_LOSS]")
+ outcome = MISSION_OUTCOME_MINOR_LOSS
+ else
+ message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_LOSS]")
+ outcome = MISSION_OUTCOME_MAJOR_LOSS
+ return TRUE
/datum/campaign_mission/capture_mission/asat/apply_major_victory()
. = ..()
diff --git a/code/datums/gamemodes/campaign/missions/base_rescue.dm b/code/datums/gamemodes/campaign/missions/base_rescue.dm
index d1c53b6c19ce5..a801811de73a8 100644
--- a/code/datums/gamemodes/campaign/missions/base_rescue.dm
+++ b/code/datums/gamemodes/campaign/missions/base_rescue.dm
@@ -3,13 +3,14 @@
name = "NT base rescue"
mission_icon = "nt_rescue"
mission_flags = MISSION_DISALLOW_TELEPORT
- map_name = "NT site B-403"
+ map_name = "NT Site B-403"
map_file = '_maps/map_files/Campaign maps/nt_base/nt_base.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_SNOWSTORM = TRUE)
map_light_colours = list(COLOR_MISSION_BLUE, COLOR_MISSION_BLUE, COLOR_MISSION_BLUE, COLOR_MISSION_BLUE)
map_light_levels = list(225, 150, 100, 75)
objectives_total = 1
min_destruction_amount = 1
+ max_game_time = 15 MINUTES
shutter_open_delay = list(
MISSION_STARTING_FACTION = 60 SECONDS,
MISSION_HOSTILE_FACTION = 0,
@@ -41,6 +42,8 @@
/datum/campaign_mission/destroy_mission/base_rescue/load_mission()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_CODE, PROC_REF(override_code_received))
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_RUNNING, PROC_REF(computer_running))
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_STOP_RUNNING, PROC_REF(computer_stop_running))
/datum/campaign_mission/destroy_mission/base_rescue/set_factions()
attacking_faction = hostile_faction
@@ -48,7 +51,7 @@
/datum/campaign_mission/destroy_mission/base_rescue/unregister_mission_signals()
. = ..()
- UnregisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_CODE)
+ UnregisterSignal(SSdcs, list(COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_CODE, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_RUNNING, COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_STOP_RUNNING))
/datum/campaign_mission/destroy_mission/base_rescue/play_start_intro()
intro_message = list(
@@ -59,8 +62,12 @@
/datum/campaign_mission/destroy_mission/base_rescue/load_pre_mission_bonuses()
. = ..()
- for(var/i = 1 to objectives_total)
- new /obj/item/storage/box/explosive_mines(get_turf(pick(GLOB.campaign_reward_spawners[defending_faction])))
+ spawn_mech(attacking_faction, 0, 0, 4)
+ spawn_mech(defending_faction, 0, 0, 2)
+
+ var/datum/faction_stats/defending_team = mode.stat_list[defending_faction]
+ defending_team.add_asset(/datum/campaign_asset/asset_disabler/tgmc_cas/instant)
+ defending_team.add_asset(/datum/campaign_asset/asset_disabler/tgmc_mortar)
/datum/campaign_mission/destroy_mission/base_rescue/load_mission_brief()
starting_faction_mission_brief = "NanoTrasen has issues an emergency request for assistance at an isolated medical facility located in the Western Ayolan Ranges. \
@@ -69,30 +76,40 @@
hostile_faction_mission_brief = "Recon forces have led us to this secure Nanotrasen facility in the Western Ayolan Ranges. Sympathetic native elements suggest NT have been conducting secret research here to the detriment of the local ecosystem and human settlements. \
Find the security override terminals to override the facility's emergency lockdown. \
Once the lockdown is lifted, destroy what they're working on inside."
+ starting_faction_mission_parameters = "Fire support is unavailable due to the sensitive and costly nature of this NT installation."
+ hostile_faction_mission_parameters = "Teleportation is unavailable in this area due to unknown interference from beneath the NT compound."
/datum/campaign_mission/destroy_mission/base_rescue/load_objective_description()
starting_faction_objective_description = "Major Victory:Protect the NT base from SOM attack. Do not allow them to override the security lockdown and destroy NT's sensitive equipment"
hostile_faction_objective_description = "Major Victory: Override the security lockdown on the NT facility and destroy whatever secrets they are working on"
+/datum/campaign_mission/destroy_mission/base_rescue/start_mission()
+ . = ..()
+ //We do this when the mission starts to stop nerds from wasting the militia roles pregame
+ var/datum/faction_stats/attacking_team = mode.stat_list[attacking_faction]
+ attacking_team.add_asset(/datum/campaign_asset/bonus_job/colonial_militia)
+ attacking_team.faction_assets[/datum/campaign_asset/bonus_job/colonial_militia].attempt_activatation(attacking_team.faction_leader, TRUE)
+
+
/datum/campaign_mission/destroy_mission/base_rescue/apply_major_victory()
. = ..()
- var/datum/faction_stats/winning_team = mode.stat_list[starting_faction]
+ var/datum/faction_stats/winning_team = mode.stat_list[defending_faction]
winning_team.add_asset(/datum/campaign_asset/bonus_job/pmc)
winning_team.add_asset(/datum/campaign_asset/attrition_modifier/corporate_approval)
/datum/campaign_mission/destroy_mission/base_rescue/apply_minor_victory()
. = ..()
- var/datum/faction_stats/winning_team = mode.stat_list[starting_faction]
+ var/datum/faction_stats/winning_team = mode.stat_list[defending_faction]
winning_team.add_asset(/datum/campaign_asset/bonus_job/pmc)
/datum/campaign_mission/destroy_mission/base_rescue/apply_minor_loss()
. = ..()
- var/datum/faction_stats/winning_team = mode.stat_list[hostile_faction]
+ var/datum/faction_stats/winning_team = mode.stat_list[attacking_faction]
winning_team.add_asset(/datum/campaign_asset/bonus_job/colonial_militia)
/datum/campaign_mission/destroy_mission/base_rescue/apply_major_loss()
. = ..()
- var/datum/faction_stats/winning_team = mode.stat_list[hostile_faction]
+ var/datum/faction_stats/winning_team = mode.stat_list[attacking_faction]
winning_team.add_asset(/datum/campaign_asset/bonus_job/colonial_militia)
winning_team.add_asset(/datum/campaign_asset/attrition_modifier/local_approval)
@@ -103,6 +120,15 @@
map_text_broadcast(attacking_faction, message_to_play, "[color] override broadcast", /atom/movable/screen/text/screen_text/picture/potrait/unknown)
map_text_broadcast(defending_faction, message_to_play, "[color] override broadcast", /atom/movable/screen/text/screen_text/picture/potrait/unknown)
+///Code computer is actively running a segment
+/datum/campaign_mission/destroy_mission/base_rescue/proc/computer_running(datum/source, obj/machinery/computer/nt_access/code_computer)
+ SIGNAL_HANDLER
+ pause_mission_timer(REF(code_computer))
+
+///Code computer stops running a segment
+/datum/campaign_mission/destroy_mission/base_rescue/proc/computer_stop_running(datum/source, obj/machinery/computer/nt_access/code_computer)
+ SIGNAL_HANDLER
+ resume_mission_timer(REF(code_computer))
/obj/effect/landmark/campaign_structure/weapon_x
name = "weapon X spawner"
@@ -140,13 +166,14 @@
return ..()
/obj/structure/weapon_x_pod/update_icon_state()
+ . = ..()
if(occupant)
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]_open"
-/obj/structure/weapon_x_pod/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X != occupant)
+/obj/structure/weapon_x_pod/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker != occupant)
return
release_occupant()
diff --git a/code/datums/gamemodes/campaign/missions/destroy_mission.dm b/code/datums/gamemodes/campaign/missions/destroy_mission.dm
index 99445561bbdd6..13d541a36d861 100644
--- a/code/datums/gamemodes/campaign/missions/destroy_mission.dm
+++ b/code/datums/gamemodes/campaign/missions/destroy_mission.dm
@@ -101,7 +101,7 @@
if(mode.stat_list[attacking_faction].active_attrition_points)
return FALSE //attacking team still has more bodies to throw into the fight
var/list/player_list = count_humans(count_flags = COUNT_IGNORE_ALIVE_SSD)
- if(length(player_list[attacking_faction == starting_faction ? 1 : 3]))
+ if(length(player_list[attacking_faction == starting_faction ? 1 : 2]))
return FALSE //attacking team still has living guys
if(min_destruction_amount && objectives_destroyed >= min_destruction_amount) //Destroyed at least the minimum required
diff --git a/code/datums/gamemodes/campaign/missions/fire_support_raid.dm b/code/datums/gamemodes/campaign/missions/fire_support_raid.dm
index fe806aceb2fd9..ef1943b6e9213 100644
--- a/code/datums/gamemodes/campaign/missions/fire_support_raid.dm
+++ b/code/datums/gamemodes/campaign/missions/fire_support_raid.dm
@@ -3,11 +3,13 @@
name = "Fire support raid"
mission_icon = "mortar_raid"
mission_flags = MISSION_DISALLOW_DROPPODS
- map_name = "Jungle outpost SR-422"
+ map_name = "Jungle Outpost SR-422"
map_file = '_maps/map_files/Campaign maps/jungle_outpost/jungle_outpost.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_RAIN = TRUE)
map_light_colours = list(LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN)
- objectives_total = 10
+ max_game_time = 10 MINUTES
+ game_timer_delay = 90 SECONDS
+ objectives_total = 9
min_destruction_amount = 7
shutter_open_delay = list(
MISSION_STARTING_FACTION = 90 SECONDS,
@@ -43,6 +45,12 @@
for(var/i = 1 to objectives_total)
new /obj/item/storage/box/explosive_mines(get_turf(pick(GLOB.campaign_reward_spawners[defending_faction])))
+ var/datum/faction_stats/attacking_team = mode.stat_list[starting_faction]
+ if(starting_faction == FACTION_TERRAGOV)
+ attacking_team.add_asset(/datum/campaign_asset/asset_disabler/tgmc_cas/instant)
+ else if(starting_faction == FACTION_SOM)
+ attacking_team.add_asset(/datum/campaign_asset/asset_disabler/som_cas/instant)
+
/datum/campaign_mission/destroy_mission/fire_support_raid/load_mission_brief()
starting_faction_mission_brief = "A [hostile_faction] fire support position has been identified in this area. This key location provides fire support to [hostile_faction] forces across the region. \
By destroying this outpost we can silence their guns and greatly weaken the enemy's forces. \
@@ -95,6 +103,6 @@
map_traits = list(ZTRAIT_AWAY = TRUE)
map_light_colours = list(COLOR_MISSION_RED, COLOR_MISSION_RED, COLOR_MISSION_RED, COLOR_MISSION_RED)
map_light_levels = list(225, 150, 100, 75)
- objectives_total = 8
- min_destruction_amount = 6
+ objectives_total = 5
+ min_destruction_amount = 4
hostile_faction_additional_rewards = "Protect our fire support options to ensure continued access to mortar support. Combat robots and fire support is available if you successfully defend this outpost."
diff --git a/code/datums/gamemodes/campaign/missions/mech_wars.dm b/code/datums/gamemodes/campaign/missions/mech_wars.dm
index 9c34a2a8ac380..558bb7b7d6eb5 100644
--- a/code/datums/gamemodes/campaign/missions/mech_wars.dm
+++ b/code/datums/gamemodes/campaign/missions/mech_wars.dm
@@ -9,7 +9,7 @@
map_light_levels = list(225, 150, 100, 75)
starting_faction_objective_description = "Major Victory: Wipe out all hostiles in the area of operation. Minor Victory: Eliminate more hostiles than you lose."
hostile_faction_objective_description = "Major Victory: Wipe out all hostiles in the area of operation. Minor Victory: Eliminate more hostiles than you lose."
- mission_start_delay = 5 MINUTES //since there is actual mech prep time required
+ mission_start_delay = 3 MINUTES //since there is actual mech prep time required
starting_faction_additional_rewards = "Mechanised units will be allocated to your battalion for use in future missions."
hostile_faction_additional_rewards = "Mechanised units will be allocated to your battalion for use in future missions."
@@ -39,7 +39,7 @@
spawner = pick(GLOB.campaign_mech_spawners[faction])
new_mech = spawner.spawn_mech()
GLOB.campaign_structures += new_mech
- RegisterSignal(new_mech, COMSIG_QDELETING, TYPE_PROC_REF(/datum/campaign_mission, remove_mission_object))
+ RegisterSignal(new_mech, COMSIG_QDELETING, PROC_REF(on_mech_destruction))
//anti mech infantry weapons
if(i % 2)
@@ -75,54 +75,16 @@
winning_team.add_asset(/datum/campaign_asset/mech/heavy/som)
winning_team.add_asset(/datum/campaign_asset/mech/som)
-//mech spawn points
-/obj/effect/landmark/campaign/mech_spawner
- name = "tgmc med mech spawner"
- icon_state = "mech"
- var/faction = FACTION_TERRAGOV
- var/list/colors = list(ARMOR_PALETTE_SPACE_CADET, ARMOR_PALETTE_GREYISH_TURQUOISE, VISOR_PALETTE_MAGENTA)
- var/obj/vehicle/sealed/mecha/combat/greyscale/mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/assault/noskill
-
-/obj/effect/landmark/campaign/mech_spawner/Initialize(mapload)
- . = ..()
- GLOB.campaign_mech_spawners[faction] += list(src)
-
-/obj/effect/landmark/campaign/mech_spawner/Destroy()
- GLOB.campaign_mech_spawners[faction] -= src
- return ..()
-
-/obj/effect/landmark/campaign/mech_spawner/proc/spawn_mech()
- var/obj/vehicle/sealed/mecha/combat/greyscale/new_mech = new mech_type(loc)
- for(var/i in new_mech.limbs)
- var/datum/mech_limb/limb = new_mech.limbs[i]
- limb.update_colors(arglist(colors))
- new_mech.update_icon()
- return new_mech
-
-/obj/effect/landmark/campaign/mech_spawner/heavy
- name = "tgmc heavy mech spawner"
- icon_state = "mech_heavy"
- mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/vanguard/noskill
-
-/obj/effect/landmark/campaign/mech_spawner/light
- name = "tgmc light mech spawner"
- icon_state = "mech_light"
- mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/recon/noskill
-
-/obj/effect/landmark/campaign/mech_spawner/som
- name = "som med mech spawner"
- faction = FACTION_SOM
- colors = list(ARMOR_PALETTE_GINGER, ARMOR_PALETTE_BLACK, VISOR_PALETTE_SYNDIE_GREEN)
-
-/obj/effect/landmark/campaign/mech_spawner/som/heavy
- name = "som heavy mech spawner"
- icon_state = "mech_heavy"
- mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/vanguard/noskill
-
-/obj/effect/landmark/campaign/mech_spawner/som/light
- name = "som light mech spawner"
- icon_state = "mech_light"
- mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/recon/noskill
+///Cleans up after a mech is destroyed
+/datum/campaign_mission/tdm/mech_wars/proc/on_mech_destruction(obj/vehicle/sealed/mecha/combat/greyscale/dead_mech)
+ SIGNAL_HANDLER
+ remove_mission_object(dead_mech)
+ if(outcome)
+ return
+ if(dead_mech.faction == hostile_faction)
+ start_team_cap_points += 10
+ else if(dead_mech.faction == starting_faction)
+ hostile_team_cap_points += 10
/datum/campaign_mission/tdm/mech_wars/som
name = "Mech war"
diff --git a/code/datums/gamemodes/campaign/missions/patrol_mission.dm b/code/datums/gamemodes/campaign/missions/patrol_mission.dm
index 0cb5f18bcd12c..62306fc261272 100644
--- a/code/datums/gamemodes/campaign/missions/patrol_mission.dm
+++ b/code/datums/gamemodes/campaign/missions/patrol_mission.dm
@@ -9,7 +9,7 @@
starting_faction_objective_description = "Major Victory: Wipe out all hostiles in the AO or capture and hold the sensor towers for a points victory. Minor Victory: Eliminate more hostiles than you lose."
hostile_faction_objective_description = "Major Victory: Wipe out all hostiles in the AO or capture and hold the sensor towers for a points victory. Minor Victory: Eliminate more hostiles than you lose."
max_game_time = 15 MINUTES
- game_timer_delay = 5 MINUTES
+ game_timer_delay = 3 MINUTES
victory_point_rewards = list(
MISSION_OUTCOME_MAJOR_VICTORY = list(2, 0),
MISSION_OUTCOME_MINOR_VICTORY = list(1, 0),
@@ -35,40 +35,6 @@
starting_faction_additional_rewards = "If the enemy force is wiped out entirely, additional supplies can be diverted to your battalion."
hostile_faction_additional_rewards = "If the enemy force is wiped out entirely, additional supplies can be diverted to your battalion."
- major_victory_reward_table = list(
- /obj/effect/supply_drop/medical_basic = 7,
- /obj/effect/supply_drop/marine_sentry = 5,
- /obj/effect/supply_drop/recoilless_rifle = 3,
- /obj/effect/supply_drop/armor_upgrades = 5,
- /obj/effect/supply_drop/mmg = 4,
- /obj/effect/supply_drop/zx_shotgun = 3,
- /obj/effect/supply_drop/minigun = 3,
- /obj/effect/supply_drop/scout = 3,
- )
- minor_victory_reward_table = list(
- /obj/effect/supply_drop/medical_basic = 7,
- /obj/effect/supply_drop/marine_sentry = 5,
- /obj/effect/supply_drop/recoilless_rifle = 3,
- /obj/effect/supply_drop/armor_upgrades = 5,
- /obj/effect/supply_drop/mmg = 4,
- )
- minor_loss_reward_table = list(
- /obj/effect/supply_drop/medical_basic = 7,
- /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope = 5,
- /obj/effect/supply_drop/som_rpg = 3,
- /obj/effect/supply_drop/som_armor_upgrades = 5,
- /obj/effect/supply_drop/charger = 4,
- )
- major_loss_reward_table = list(
- /obj/effect/supply_drop/medical_basic = 7,
- /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope = 5,
- /obj/effect/supply_drop/som_rpg = 3,
- /obj/effect/supply_drop/som_armor_upgrades = 5,
- /obj/effect/supply_drop/charger = 4,
- /obj/effect/supply_drop/culverin = 3,
- /obj/effect/supply_drop/blink_kit = 3,
- /obj/effect/supply_drop/som_shotgun_burst = 3,
- )
///Point limit to win the game via objectives
var/capture_point_target = 400
///starting team's point count
@@ -81,6 +47,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_CAPTURED, PROC_REF(objective_captured))
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_CAP_STARTED, PROC_REF(objective_cap_started))
+
/datum/campaign_mission/tdm/unregister_mission_signals()
. = ..()
UnregisterSignal(SSdcs, list(COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_CAPTURED, COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_CAP_STARTED))
@@ -90,7 +57,7 @@
MISSION_STARTING_FACTION = "[map_name] " + "[GAME_YEAR]-[time2text(world.realtime, "MM-DD")] [stationTimestamp("hh:mm")] " + "Eliminate all [hostile_faction] resistance in the AO. Reinforcements are limited so preserve your forces as best you can. Good hunting!",
MISSION_HOSTILE_FACTION = "[map_name] " + "[GAME_YEAR]-[time2text(world.realtime, "MM-DD")] [stationTimestamp("hh:mm")] " + "Eliminate all [starting_faction] resistance in the AO. Reinforcements are limited so preserve your forces as best you can. Good hunting!",
)
- . = ..()
+ return ..()
/datum/campaign_mission/tdm/get_status_tab_items(mob/source, list/items)
. = ..()
@@ -215,20 +182,21 @@
map_text_broadcast(losing_team, "[objective] was activated by the enemy. Get it offline!", "Activation cancelled")
///test missions
-/datum/campaign_mission/tdm/lv624
+/datum/campaign_mission/tdm/orion
name = "Combat patrol 2"
- map_name = "Orion outpost"
+ map_name = "Orion Outpost"
map_file = '_maps/map_files/Orion_Military_Outpost/orionoutpost.dmm'
map_light_colours = list(COLOR_MISSION_YELLOW, COLOR_MISSION_YELLOW, COLOR_MISSION_YELLOW, COLOR_MISSION_YELLOW)
map_light_levels = list(225, 150, 100, 75)
/datum/campaign_mission/tdm/first_mission
name = "First Contact"
- map_name = "Jungle outpost SR-422"
+ map_name = "Jungle Outpost SR-422"
map_file = '_maps/map_files/Campaign maps/jungle_outpost/jungle_outpost.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_RAIN = TRUE)
map_light_colours = list(LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN)
map_light_levels = list(200, 100, 75, 50)
+ mission_start_delay = 3 MINUTES
/datum/campaign_mission/tdm/first_mission/end_mission()
. = ..()
diff --git a/code/datums/gamemodes/campaign/missions/phoron_capture.dm b/code/datums/gamemodes/campaign/missions/phoron_capture.dm
index 82e948d4e5054..9fb6074dfffe0 100644
--- a/code/datums/gamemodes/campaign/missions/phoron_capture.dm
+++ b/code/datums/gamemodes/campaign/missions/phoron_capture.dm
@@ -2,7 +2,7 @@
/datum/campaign_mission/capture_mission/phoron_capture
name = "Phoron retrieval"
mission_icon = "phoron_raid"
- map_name = "Jungle outpost SR-422"
+ map_name = "Jungle Outpost SR-422"
map_file = '_maps/map_files/Campaign maps/jungle_outpost/jungle_outpost.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_RAIN = TRUE)
map_light_colours = list(LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN)
diff --git a/code/datums/gamemodes/campaign/missions/raiding_base.dm b/code/datums/gamemodes/campaign/missions/raiding_base.dm
index d035a7e3c4a34..e68fba26316a4 100644
--- a/code/datums/gamemodes/campaign/missions/raiding_base.dm
+++ b/code/datums/gamemodes/campaign/missions/raiding_base.dm
@@ -1,97 +1,180 @@
-//placeholder
/datum/campaign_mission/raiding_base
- name = "Combat patrol"
+ name = "Raiding Base"
mission_icon = "raiding_base"
- map_name = "Orion Outpost"
- map_file = '_maps/map_files/Campaign maps/jungle_outpost/jungle_outpost.dmm'
- starting_faction_objective_description = null
- hostile_faction_objective_description = null
- max_game_time = 20 MINUTES
+ map_name = "Raiding base Zulu"
+ map_file = '_maps/map_files/Campaign maps/som_raid_base/som_raiding_base.dmm'
+ map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_RAIN = TRUE)
+ map_light_colours = list(LIGHT_COLOR_PALE_GREEN, LIGHT_COLOR_PALE_GREEN, COLOR_MISSION_RED, COLOR_MISSION_RED)
+ starting_faction_objective_description = "Major Victory: Set and defend an orbital beacon inside the facility until a precision orbital strike can be called in."
+ hostile_faction_objective_description = "Major Victory: Prevent the enemy from activating an orbital beacon inside the facility."
+ intro_message = list(
+ MISSION_STARTING_FACTION = "Infiltrate the SOM base, then plant and defend an orbital beacon until we can drop the hammer on them from orbit!",
+ MISSION_HOSTILE_FACTION = "Stop TGMC forces from infiltrating the base. Prevent them from activating an orbital beacon at all costs!",
+ )
+ mission_flags = MISSION_DISALLOW_DROPPODS
+ max_game_time = 12 MINUTES
+ mission_start_delay = 90 SECONDS
+ shutter_open_delay = list(
+ MISSION_STARTING_FACTION = 90 SECONDS,
+ MISSION_HOSTILE_FACTION = 0,
+ )
victory_point_rewards = list(
- MISSION_OUTCOME_MAJOR_VICTORY = list(3, 0),
+ MISSION_OUTCOME_MAJOR_VICTORY = list(2, 0),
MISSION_OUTCOME_MINOR_VICTORY = list(1, 0),
MISSION_OUTCOME_DRAW = list(0, 0),
MISSION_OUTCOME_MINOR_LOSS = list(0, 1),
- MISSION_OUTCOME_MAJOR_LOSS = list(0, 3),
+ MISSION_OUTCOME_MAJOR_LOSS = list(0, 2),
)
attrition_point_rewards = list(
- MISSION_OUTCOME_MAJOR_VICTORY = list(20, 5),
- MISSION_OUTCOME_MINOR_VICTORY = list(15, 10),
- MISSION_OUTCOME_DRAW = list(10, 10),
- MISSION_OUTCOME_MINOR_LOSS = list(10, 15),
- MISSION_OUTCOME_MAJOR_LOSS = list(5, 20),
+ MISSION_OUTCOME_MAJOR_VICTORY = list(20, 20),
+ MISSION_OUTCOME_MINOR_VICTORY = list(0, 0),
+ MISSION_OUTCOME_DRAW = list(0, 0),
+ MISSION_OUTCOME_MINOR_LOSS = list(0, 0),
+ MISSION_OUTCOME_MAJOR_LOSS = list(10, 30),
)
- starting_faction_mission_brief = null
- hostile_faction_mission_brief = null
- starting_faction_additional_rewards = null
- hostile_faction_additional_rewards = null
-
-/datum/campaign_mission/raiding_base/play_start_intro()
- intro_message = list(
- MISSION_STARTING_FACTION = "[map_name] " + "[GAME_YEAR]-[time2text(world.realtime, "MM-DD")] [stationTimestamp("hh:mm")] " + "Eliminate all [hostile_faction] resistance in the AO. Reinforcements are limited so preserve your forces as best you can. Good hunting!",
- MISSION_HOSTILE_FACTION = "[map_name] " + "[GAME_YEAR]-[time2text(world.realtime, "MM-DD")] [stationTimestamp("hh:mm")] " + "Eliminate all [starting_faction] resistance in the AO. Reinforcements are limited so preserve your forces as best you can. Good hunting!",
+ starting_faction_mission_brief = "We have finally been able to track down a hidden SOM outpost which they have been using as a base of operations to raid our supply lines, wrecking havoc on our logistics. \
+ Your unit has been tasked with ensuring the complete and utter destruction of this base and everything within it. \
+ Infiltrate the facility, then deploy one of the orbital beacons you have been supplied with. \
+ Defend the beacon until the TGS Horizon can secure a target lock and deploy a thermobaric bunker buster to wipe the outpost off the face of the planet."
+ hostile_faction_mission_brief = "Intelligence has picked up a TGMC plan to assault Raiding base Zulu. This base has been key to our sabotage and disruption efforts, significantly degrading TGMC supply lines. \
+ Intel suggests that the TGMC are seeking to infiltrate the base to deploy a orbital beacon, in order to call down an orbital strike. \
+ Prevent TGMC forces from entering the base, and destroy any orbital beacon they try to deploy."
+ starting_faction_additional_rewards = "Remove negative effects on our logistics"
+ hostile_faction_additional_rewards = "Allow us to continue degrading TGMC logistics"
+ outro_message = list(
+ MISSION_OUTCOME_MAJOR_VICTORY = list(
+ MISSION_STARTING_FACTION = "Major victory Confirming good hit. Successful destruction of target facility. Outstanding marines!",
+ MISSION_HOSTILE_FACTION = "Major loss We've lost Zulu, any survivors, fallback to exfil point Charlie, retreat!",
+ ),
+ MISSION_OUTCOME_MAJOR_LOSS = list(
+ MISSION_STARTING_FACTION = "Major loss SOM interceptors are inbound, all forces fallback, this operation is a loss.",
+ MISSION_HOSTILE_FACTION = "Major victory Reinforcements are almost here and enemy forces are falling back, you've done Mars proud today marines.",
+ ),
)
+ ///Records whether the OB has been called
+ var/ob_called = FALSE
+ ///Count of beacons still in play
+ var/beacons_remaining = 4
+
+/datum/campaign_mission/raiding_base/get_status_tab_items(mob/source, list/items)
. = ..()
+ items += "Beacons remaining: [beacons_remaining]"
+
+/datum/campaign_mission/raiding_base/load_pre_mission_bonuses()
+ spawn_mech(starting_faction, 0, 0, 3)
+ spawn_mech(hostile_faction, 0, 2)
+ new /obj/item/storage/box/crate/loot/materials_pack(get_turf(pick(GLOB.campaign_reward_spawners[hostile_faction])))
+ for(var/i = 1 to beacons_remaining)
+ new /obj/item/explosive/plastique(get_turf(pick(GLOB.campaign_reward_spawners[hostile_faction])))
+ new /obj/item/explosive/plastique(get_turf(pick(GLOB.campaign_reward_spawners[hostile_faction])))
+ new /obj/item/campaign_beacon/bunker_buster(get_turf(pick(GLOB.campaign_reward_spawners[starting_faction])))
+
+/datum/campaign_mission/raiding_base/start_mission()
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_ACTIVATION, PROC_REF(beacon_placed))
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_TRIGGERED, PROC_REF(beacon_triggered))
/datum/campaign_mission/raiding_base/check_mission_progress()
if(outcome)
return TRUE
if(!game_timer)
- return
+ return FALSE
- ///pulls the number of both factions, dead or alive
- var/list/player_list = count_humans(count_flags = COUNT_IGNORE_ALIVE_SSD)
- var/num_team_one = length(player_list[1])
- var/num_team_two = length(player_list[2])
- var/num_dead_team_one = length(player_list[3])
- var/num_dead_team_two = length(player_list[4])
-
- if(num_team_two && num_team_one && !max_time_reached)
- return //fighting is ongoing
-
- //major victor for wiping out the enemy, or draw if both sides wiped simultaneously somehow
- if(!num_team_two)
- if(!num_team_one)
- message_admins("Mission finished: [MISSION_OUTCOME_DRAW]") //everyone died at the same time, no one wins
- outcome = MISSION_OUTCOME_DRAW
- return TRUE
- message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_VICTORY]") //starting team wiped the hostile team
+ if(ob_called)
+ message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_VICTORY]") //Attackers dropped the hammer
outcome = MISSION_OUTCOME_MAJOR_VICTORY
return TRUE
- if(!num_team_one)
- message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_LOSS]") //hostile team wiped the starting team
- outcome = MISSION_OUTCOME_MAJOR_LOSS
- return TRUE
+ var/attacker_lost
- //minor victories for more kills or draw for equal kills
- if(num_dead_team_two > num_dead_team_one)
- message_admins("Mission finished: [MISSION_OUTCOME_MINOR_VICTORY]") //starting team got more kills
- outcome = MISSION_OUTCOME_MINOR_VICTORY
- return TRUE
- if(num_dead_team_one > num_dead_team_two)
- message_admins("Mission finished: [MISSION_OUTCOME_MINOR_LOSS]") //hostile team got more kills
- outcome = MISSION_OUTCOME_MINOR_LOSS
- return TRUE
+ if(!length(GLOB.campaign_objectives) || max_time_reached)
+ attacker_lost = TRUE
+ else
+ var/list/player_list = count_humans(count_flags = COUNT_IGNORE_ALIVE_SSD)
+ var/num_team_one = length(player_list[1])
+ var/datum/faction_stats/attacker_stats = mode.stat_list[starting_faction]
+ if(!num_team_one && !attacker_stats.active_attrition_points)
+ attacker_lost = TRUE
- message_admins("Mission finished: [MISSION_OUTCOME_DRAW]") //equal number of kills, or any other edge cases
- outcome = MISSION_OUTCOME_DRAW
+ if(!attacker_lost)
+ return FALSE
+ message_admins("Mission finished: [MISSION_OUTCOME_MAJOR_LOSS]") //Attackers run out of beacons, time or bodies
+ outcome = MISSION_OUTCOME_MAJOR_LOSS
return TRUE
-//todo: remove these if nothing new is added
-/datum/campaign_mission/raiding_base/apply_major_victory()
+/datum/campaign_mission/raiding_base/unregister_mission_signals()
. = ..()
+ UnregisterSignal(SSdcs, list(COMSIG_GLOB_CAMPAIGN_OB_BEACON_ACTIVATION, COMSIG_GLOB_CAMPAIGN_OB_BEACON_TRIGGERED))
-/datum/campaign_mission/raiding_base/apply_minor_victory()
+/datum/campaign_mission/raiding_base/apply_major_victory()
. = ..()
+ winning_faction = starting_faction
+ var/datum/faction_stats/winning_team = mode.stat_list[starting_faction]
+ winning_team.remove_asset(/datum/campaign_asset/attrition_modifier/malus_strong)
+ winning_team.remove_asset(/datum/campaign_asset/attrition_modifier/malus_standard)
+ //We don't have enough missions in the pool yet to activate this
+ //GLOB.campaign_mission_pool[hostile_faction] -= /datum/campaign_mission/destroy_mission/supply_raid/som
+ //GLOB.campaign_mission_pool[hostile_faction] -= /datum/campaign_mission/destroy_mission/supply_raid
-/datum/campaign_mission/raiding_base/apply_draw()
- winning_faction = pick(starting_faction, hostile_faction)
-
-/datum/campaign_mission/raiding_base/apply_minor_loss()
- . = ..()
/datum/campaign_mission/raiding_base/apply_major_loss()
. = ..()
+ winning_faction = hostile_faction
+ var/datum/faction_stats/winning_team = mode.stat_list[hostile_faction]
+ if(hostile_faction == FACTION_TERRAGOV)
+ winning_team.add_asset(/datum/campaign_asset/equipment/power_armor)
+ else if(hostile_faction == FACTION_SOM)
+ winning_team.add_asset(/datum/campaign_asset/mech/light/som)
+ winning_team.add_asset(/datum/campaign_asset/equipment/gorgon_armor)
+
+///Returns a list of areas in which the beacon can be deployed
+/datum/campaign_mission/raiding_base/proc/get_valid_beacon_areas()
+ return list(
+ /area/campaign/som_raiding/outpost/command,
+ /area/campaign/som_raiding/outpost/command/captain,
+ /area/campaign/som_raiding/outpost/command/telecom,
+ /area/campaign/som_raiding/outpost/command/cic,
+ /area/campaign/som_raiding/outpost/command/north,
+ /area/campaign/som_raiding/outpost/command/living,
+ /area/campaign/som_raiding/outpost/medbay,
+ /area/campaign/som_raiding/outpost/central_corridor,
+ )
+
+///Reacts to an OB beacon being successfully triggered
+/datum/campaign_mission/raiding_base/proc/beacon_placed(datum/source, obj/structure/campaign_objective/destruction_objective/bunker_buster/beacon)
+ SIGNAL_HANDLER
+ RegisterSignal(beacon, COMSIG_QDELETING, PROC_REF(beacon_destroyed))
+ pause_mission_timer(REF(beacon))
+ var/area/deployed_area = get_area(beacon)
+ map_text_broadcast(starting_faction, "Confirming beacon deployed in [deployed_area]. Defend it until we can secure a target lock marines!", "TGS Horizon", /atom/movable/screen/text/screen_text/picture/potrait/pod_officer, "sound/effects/alert.ogg")
+ map_text_broadcast(hostile_faction, "Orbital beacon detected in [deployed_area]. Destroy that beacon before they can secure a target lock!", "Overwatch", sound_effect = "sound/effects/alert.ogg")
+
+///Handles a beacon being destroyed. Separate from normal objective destruction for convenience as we want the specific beacon ref
+/datum/campaign_mission/raiding_base/proc/beacon_destroyed(obj/structure/campaign_objective/destruction_objective/bunker_buster/beacon)
+ SIGNAL_HANDLER
+ UnregisterSignal(beacon, COMSIG_QDELETING)
+ resume_mission_timer(REF(beacon))
+ beacons_remaining --
+ if(outcome)
+ return
+ var/beacons_destroyed = initial(beacons_remaining) - beacons_remaining
+ map_text_broadcast(starting_faction, "We've lost [beacons_destroyed] beacon[beacons_destroyed > 1 ? "s" : null], get it together!", "Overwatch")
+ map_text_broadcast(hostile_faction, "[beacons_destroyed] beacon[beacons_destroyed > 1 ? "s" : null] destroyed, keep up the good work!", "Overwatch")
+
+///Reacts to an OB beacon being successfully triggered
+/datum/campaign_mission/raiding_base/proc/beacon_triggered(datum/source, obj/structure/campaign_objective/destruction_objective/bunker_buster/beacon, activation_delay)
+ SIGNAL_HANDLER
+ pause_mission_timer() //stops the game from ending if it comes down to the wire
+ addtimer(CALLBACK(src, PROC_REF(beacon_effect), beacon, beacon.loc), activation_delay)
+
+///Handles the actual detonation effects
+/datum/campaign_mission/raiding_base/proc/beacon_effect(obj/structure/campaign_objective/destruction_objective/bunker_buster/beacon, turf/location)
+ ob_called = TRUE
+ resume_mission_timer(src, TRUE)
+ //We handle this here instead of the beacon structure because it could be destroyed before this triggers
+ explosion(location, 45, flame_range = 45)
+ if(QDELETED(beacon))
+ return
+ qdel(beacon)
diff --git a/code/datums/gamemodes/campaign/missions/supply_raid.dm b/code/datums/gamemodes/campaign/missions/supply_raid.dm
index 3ceb9bea15922..45b1843d8f4de 100644
--- a/code/datums/gamemodes/campaign/missions/supply_raid.dm
+++ b/code/datums/gamemodes/campaign/missions/supply_raid.dm
@@ -3,7 +3,7 @@
name = "Supply Depot raid"
mission_icon = "supply_depot"
mission_flags = MISSION_DISALLOW_DROPPODS
- map_name = "Rocinante base"
+ map_name = "Rocinante Base"
map_file = '_maps/map_files/Campaign maps/som_base/sombase.dmm'
map_traits = list(ZTRAIT_AWAY = TRUE, ZTRAIT_SNOWSTORM = TRUE)
map_light_colours = list(COLOR_MISSION_BLUE, COLOR_MISSION_BLUE, COLOR_MISSION_BLUE, COLOR_MISSION_BLUE)
@@ -45,6 +45,11 @@
/datum/campaign_mission/destroy_mission/supply_raid/load_pre_mission_bonuses()
. = ..()
spawn_mech(defending_faction, 0, 1)
+ var/datum/faction_stats/attacking_team = mode.stat_list[starting_faction]
+ if(starting_faction == FACTION_TERRAGOV)
+ attacking_team.add_asset(/datum/campaign_asset/asset_disabler/tgmc_cas/instant)
+ else if(starting_faction == FACTION_SOM)
+ attacking_team.add_asset(/datum/campaign_asset/asset_disabler/som_cas/instant)
/datum/campaign_mission/destroy_mission/supply_raid/apply_major_victory()
winning_faction = starting_faction
@@ -62,7 +67,7 @@
if(hostile_faction == FACTION_TERRAGOV)
winning_team.add_asset(/datum/campaign_asset/equipment/power_armor)
else if(hostile_faction == FACTION_SOM)
- winning_team.add_asset(/obj/effect/landmark/campaign/mech_spawner/som/light)
+ winning_team.add_asset(/datum/campaign_asset/mech/light/som)
winning_team.add_asset(/datum/campaign_asset/equipment/gorgon_armor)
/datum/campaign_mission/destroy_mission/supply_raid/apply_major_loss()
@@ -71,16 +76,16 @@
if(hostile_faction == FACTION_TERRAGOV)
winning_team.add_asset(/datum/campaign_asset/equipment/power_armor)
else if(hostile_faction == FACTION_SOM)
- winning_team.add_asset(/obj/effect/landmark/campaign/mech_spawner/som/light)
+ winning_team.add_asset(/datum/campaign_asset/mech/light/som)
winning_team.add_asset(/datum/campaign_asset/equipment/gorgon_armor)
/datum/campaign_mission/destroy_mission/supply_raid/som
mission_flags = MISSION_DISALLOW_TELEPORT
- map_name = "Orion outpost"
+ map_name = "Orion Outpost"
map_file = '_maps/map_files/Campaign maps/orion_2/orionoutpost_2.dmm'
map_light_colours = list(COLOR_MISSION_RED, COLOR_MISSION_RED, COLOR_MISSION_RED, COLOR_MISSION_RED)
map_traits = list(ZTRAIT_AWAY = TRUE)
map_light_levels = list(225, 150, 100, 75)
objectives_total = 8
- min_destruction_amount = 5
+ min_destruction_amount = 6
hostile_faction_additional_rewards = "Prevent the degradation of our attrition generation. B18 power armour available if you successfully protect this depot."
diff --git a/code/datums/gamemodes/campaign/outfit_holder.dm b/code/datums/gamemodes/campaign/outfit_holder.dm
new file mode 100644
index 0000000000000..97f6233f440c7
--- /dev/null
+++ b/code/datums/gamemodes/campaign/outfit_holder.dm
@@ -0,0 +1,138 @@
+//holds a record of loadout_item datums, and the actual loadout itself
+/datum/outfit_holder
+ var/role
+ ///Assoc list of loadout_items by slot
+ var/list/datum/loadout_item/equipped_things = list()
+ ///The actual loadout to be equipped
+ var/datum/outfit/quick/loadout
+ ///Cost of the loadout to equip
+ var/loadout_cost = 0
+ ///Items available to be equipped
+ var/list/list/datum/loadout_item/available_list = list()
+ ///Items available to be purchased
+ var/list/list/datum/loadout_item/purchasable_list = list()
+
+/datum/outfit_holder/New(new_role)
+ . = ..()
+ role = new_role
+ loadout = new /datum/outfit/quick
+ for(var/slot in GLOB.campaign_loadout_slots)
+ available_list["[slot]"] = list()
+ purchasable_list["[slot]"] = list()
+ for(var/datum/loadout_item/loadout_item AS in GLOB.campaign_loadout_items_by_role[role])
+ if(!loadout_item.name) //various parent types
+ continue
+ if(loadout_item.item_slot != slot)
+ continue
+ if(loadout_item.loadout_item_flags & LOADOUT_ITEM_DEFAULT_CHOICE)
+ equip_loadout_item(loadout_item)
+ if(loadout_item.loadout_item_flags & LOADOUT_ITEM_ROUNDSTART_OPTION)
+ available_list["[loadout_item.item_slot]"] += loadout_item
+ continue
+ if(loadout_item.loadout_item_flags & LOADOUT_ITEM_ROUNDSTART_UNLOCKABLE)
+ purchasable_list["[loadout_item.item_slot]"] += loadout_item
+
+/datum/outfit_holder/Destroy(force, ...)
+ equipped_things = null
+ available_list = null
+ purchasable_list = null
+ QDEL_NULL(loadout)
+ return ..()
+
+///Equips the loadout to a mob
+/datum/outfit_holder/proc/equip_loadout(mob/living/carbon/human/owner)
+ loadout.equip(owner)
+ for(var/slot in equipped_things)
+ var/datum/loadout_item/thing_to_check = equipped_things["[slot]"]
+ if(!thing_to_check)
+ continue
+ if(thing_to_check.quantity > 0)
+ thing_to_check.quantity --
+ thing_to_check.post_equip(owner, loadout)
+
+///Adds a new loadout_item to the available list
+/datum/outfit_holder/proc/unlock_new_option(datum/loadout_item/new_item)
+ available_list["[new_item.item_slot]"] |= new_item
+ purchasable_list["[new_item.item_slot]"] -= new_item
+
+///Adds a new loadout_item to the purchasable list
+/datum/outfit_holder/proc/allow_new_option(datum/loadout_item/new_item)
+ if(!istype(new_item))
+ return
+ if(new_item in purchasable_list["[new_item.item_slot]"])
+ return
+ if(new_item in available_list["[new_item.item_slot]"])
+ return
+ purchasable_list["[new_item.item_slot]"] += new_item
+
+///Removes loadout_item entirely from being equipped
+/datum/outfit_holder/proc/remove_option(datum/loadout_item/removed_item)
+ if(!istype(removed_item))
+ return
+ var/removed_item_slot = "[removed_item.item_slot]"
+ available_list[removed_item_slot] -= removed_item
+ purchasable_list[removed_item_slot] -= removed_item
+ if(equipped_things[removed_item_slot] == removed_item)
+ equip_loadout_item(available_list[removed_item_slot][1])
+ return TRUE
+
+///Tries to add a datum if valid
+/datum/outfit_holder/proc/attempt_equip_loadout_item(datum/loadout_item/new_item)
+ if(!new_item.item_checks(src))
+ return FALSE
+ equip_loadout_item(new_item)
+ return TRUE
+
+///Actually adds an item to a loadout
+/datum/outfit_holder/proc/equip_loadout_item(datum/loadout_item/new_item)
+ var/slot_bit = "[new_item.item_slot]"
+ loadout_cost -= equipped_things[slot_bit]?.purchase_cost
+ equipped_things[slot_bit] = new_item //adds the datum
+ loadout_cost += equipped_things[slot_bit]?.purchase_cost
+
+ switch(new_item.item_slot) //adds it to the loadout itself
+ if(ITEM_SLOT_OCLOTHING)
+ loadout.wear_suit = new_item?.item_typepath
+ if(ITEM_SLOT_ICLOTHING)
+ loadout.w_uniform = new_item?.item_typepath
+ if(ITEM_SLOT_GLOVES)
+ loadout.gloves = new_item?.item_typepath
+ if(ITEM_SLOT_EYES)
+ loadout.glasses = new_item?.item_typepath
+ if(ITEM_SLOT_EARS)
+ loadout.ears = new_item?.item_typepath
+ if(ITEM_SLOT_MASK)
+ loadout.mask = new_item?.item_typepath
+ if(ITEM_SLOT_HEAD)
+ loadout.head = new_item?.item_typepath
+ if(ITEM_SLOT_FEET)
+ loadout.shoes = new_item?.item_typepath
+ if(ITEM_SLOT_ID)
+ loadout.id = new_item?.item_typepath
+ if(ITEM_SLOT_BELT)
+ loadout.belt = new_item?.item_typepath
+ if(ITEM_SLOT_BACK)
+ loadout.back = new_item?.item_typepath
+ if(ITEM_SLOT_R_POCKET)
+ loadout.r_store = new_item?.item_typepath
+ if(ITEM_SLOT_L_POCKET)
+ loadout.l_store = new_item?.item_typepath
+ if(ITEM_SLOT_SUITSTORE)
+ loadout.suit_store = new_item?.item_typepath
+ else
+ CRASH("Invalid item slot specified [slot_bit]")
+ return TRUE
+
+///scans the entire loadout for validity
+/datum/outfit_holder/proc/check_full_loadout()
+ . = TRUE
+ for(var/slot in equipped_things)
+ var/datum/loadout_item/thing_to_check = equipped_things["[slot]"]
+ if(!thing_to_check)
+ continue
+ if(thing_to_check.quantity == 0)
+ return FALSE
+ if(length(thing_to_check.item_whitelist) && !thing_to_check.whitelist_check(src))
+ return FALSE
+ if(length(thing_to_check.item_blacklist) && !thing_to_check.blacklist_check(src))
+ return FALSE
diff --git a/code/datums/gamemodes/campaign/perks.dm b/code/datums/gamemodes/campaign/perks.dm
new file mode 100644
index 0000000000000..53db3189653a3
--- /dev/null
+++ b/code/datums/gamemodes/campaign/perks.dm
@@ -0,0 +1,433 @@
+GLOBAL_LIST_INIT_TYPED(campaign_perk_list, /datum/perk, init_glob_perk_list()) //this may or may not be even needed
+
+/proc/init_glob_perk_list()
+ . = list()
+ for(var/perk_type in subtypesof(/datum/perk))
+ var/datum/perk/perk = new perk_type
+ .[perk_type] = perk
+
+//List of all loadout_item datums by job, excluding ones that must be unlocked
+GLOBAL_LIST_INIT(campaign_perks_by_role, init_campaign_perks_by_role())
+
+/proc/init_campaign_perks_by_role()
+ . = list()
+ for(var/job in GLOB.campaign_jobs)
+ .[job] = list()
+ for(var/i in GLOB.campaign_perk_list)
+ var/datum/perk/perk = GLOB.campaign_perk_list[i]
+ if(!(job in perk.jobs_supported))
+ continue
+ .[job] += perk
+
+/*
+Will need a way to org perks (and other stuff) by faction and/or specific role.
+Needed both for a purchase list and effected list (if one perk impacts multiple roles, unless we keep everything entirely separate)
+**/
+/datum/perk
+ ///Name of the perk
+ var/name = "base perk name"
+ ///Brief description of the perk
+ var/desc = "desc here"
+ ///Addition desc for special reqs such as other perks
+ var/req_desc
+ ///UI icon for this perk
+ var/ui_icon
+ ///Cost to purchase this perk
+ var/unlock_cost = 0
+ ///Job types that this perk is available to. no list implies this works for any job
+ var/list/jobs_supported
+ ///This applies to all campaign jobs
+ var/all_jobs = FALSE
+ ///Any perks required before this one can be obtained
+ var/list/datum/perk/prereq_perks
+
+/datum/perk/New()
+ . = ..()
+ if(all_jobs)
+ jobs_supported = GLOB.campaign_jobs
+
+///Any one off bonuses for unlocking this perk
+/datum/perk/proc/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ return
+
+///Applies perk benefits
+/datum/perk/proc/apply_perk(mob/living/carbon/owner)
+ return
+
+///Removes perk benefits
+/datum/perk/proc/remove_perk(mob/living/carbon/owner)
+ return
+
+/datum/perk/shield_overclock
+ name = "Shield overlock"
+ desc = "Overclocking a shield module beyond manufacturing specifications results in a more powerful shield at that cost of burning out sensitive components after weeks of use instead of months. \
+ May void the warranty. Also unlocks shield modules for roles that do not already have access to it."
+ ui_icon = "overclock"
+ all_jobs = TRUE
+ unlock_cost = 800
+
+/datum/perk/shield_overclock/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(owner_stats.faction == FACTION_TERRAGOV)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/light_shield/overclocked, /datum/loadout_item/suit_slot/light_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/medium_shield/overclocked, /datum/loadout_item/suit_slot/medium_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/heavy_shield/overclocked, /datum/loadout_item/suit_slot/heavy_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/medium_shield/overclocked/engineer, /datum/loadout_item/suit_slot/medium_engineer, jobs_supported)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_slot/light_shield/overclocked/medic, SQUAD_CORPSMAN, owner)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_slot/medium_shield/overclocked/medic, SQUAD_CORPSMAN, owner)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_slot/light_shield/overclocked/engineer, SQUAD_ENGINEER, owner)
+
+ else if(owner_stats.faction == FACTION_SOM)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_light_shield/overclocked, /datum/loadout_item/suit_slot/som_light_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_light_shield/overclocked/veteran, /datum/loadout_item/suit_slot/som_light_shield/veteran, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_medium_shield/overclocked, /datum/loadout_item/suit_slot/som_medium_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_heavy_shield/overclocked, /datum/loadout_item/suit_slot/som_heavy_shield, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_heavy_shield/breacher/overclocked, /datum/loadout_item/suit_slot/som_heavy_shield/breacher, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_light_shield/overclocked/medic, /datum/loadout_item/suit_slot/som_medic/light, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_medium_shield/overclocked/medic, /datum/loadout_item/suit_slot/som_medic, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_light_shield/overclocked/engineer, /datum/loadout_item/suit_slot/som_engineer/light, jobs_supported)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_slot/som_medium_shield/overclocked/engineer, /datum/loadout_item/suit_slot/som_engineer, jobs_supported)
+
+//perks that give a trait
+/datum/perk/trait
+ ///List of traits provided by this perk
+ var/list/traits
+
+/datum/perk/trait/apply_perk(mob/living/carbon/owner)
+ owner.add_traits(traits, type)
+
+/datum/perk/trait/remove_perk(mob/living/carbon/owner)
+ owner.remove_traits(traits, type)
+
+/datum/perk/trait/hp_boost
+ name = "Improved constitution"
+ desc = "Through disciplined training and hypno indoctrination, your body is able to tolerate higher levels of trauma. +25 max health, +25 pain resistance."
+ ui_icon = "health_1"
+ all_jobs = TRUE
+ unlock_cost = 800
+ traits = list(TRAIT_LIGHT_PAIN_RESIST)
+ ///How much this perk increases your maxhp by
+ var/health_mod = 25
+
+/datum/perk/trait/hp_boost/apply_perk(mob/living/carbon/owner)
+ . = ..()
+ owner.maxHealth += health_mod
+
+/datum/perk/trait/hp_boost/remove_perk(mob/living/carbon/owner)
+ . = ..()
+ owner.maxHealth -= health_mod
+
+/datum/perk/trait/hp_boost/two
+ name = "Extreme constitution"
+ desc = "Military grade biological augmentations are used to harden your body against grievous bodily harm. Provides an addition +25 max health and +10 pain resistance."
+ req_desc = "Requires Improved constitution."
+ ui_icon = "health_2"
+ prereq_perks = list(/datum/perk/trait/hp_boost)
+ traits = list(TRAIT_MEDIUM_PAIN_RESIST)
+ unlock_cost = 1000
+
+/datum/perk/trait/quiet
+ name = "Light footed"
+ desc = "Quiet when running, silent when walking."
+ ui_icon = "soft_footed"
+ traits = list(TRAIT_LIGHT_STEP)
+ all_jobs = TRUE
+ unlock_cost = 300
+
+/datum/perk/trait/axe_master
+ name = "Axe master"
+ desc = "You are able to wield a breaching axe with considerable skill. Grants access to a special sweep attack when wielded, and allows some roles to select an axe as a back stored weapon."
+ req_desc = "Requires Melee specialisation."
+ ui_icon = "axe"
+ traits = list(TRAIT_AXE_EXPERT)
+ jobs_supported = list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ unlock_cost = 450
+ prereq_perks = list(/datum/perk/skill_mod/melee/two)
+
+/datum/perk/trait/axe_master/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/boarding_axe, jobs_supported, owner, 0)
+
+/datum/perk/trait/sword_master
+ name = "Sword master"
+ desc = "You are able to wield a sword with considerable skill. Grants access to a special lunge attack when wielding any sword, and allows some roles to select a sword as a back or suit stored weapon."
+ req_desc = "Requires Melee specialisation."
+ ui_icon = "sword"
+ traits = list(TRAIT_SWORD_EXPERT)
+ jobs_supported = list(SQUAD_MARINE, SQUAD_LEADER, FIELD_COMMANDER, SOM_SQUAD_MARINE, SOM_SQUAD_ENGINEER, SOM_SQUAD_VETERAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER)
+ unlock_cost = 450
+ prereq_perks = list(/datum/perk/skill_mod/melee/two)
+
+/datum/perk/trait/sword_master/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/machete, jobs_supported, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/belt/energy_sword, jobs_supported, owner, 0)
+
+//skill modifying perks
+/datum/perk/skill_mod
+ var/cqc
+ var/melee_weapons
+ var/firearms
+ var/pistols
+ var/shotguns
+ var/rifles
+ var/smgs
+ var/heavy_weapons
+ var/smartgun
+ var/engineer
+ var/construction
+ var/leadership
+ var/medical
+ var/surgery
+ var/pilot
+ var/police
+ var/powerloader
+ var/large_vehicle
+ var/stamina
+
+/datum/perk/skill_mod/New()
+ . = ..()
+
+/datum/perk/skill_mod/apply_perk(mob/living/carbon/owner)
+ owner.set_skills(owner.skills.modifyRating(cqc, melee_weapons, firearms, pistols, shotguns, rifles, smgs, heavy_weapons, smartgun, \
+ engineer, construction, leadership, medical, surgery, pilot, police, powerloader, large_vehicle, stamina))
+
+/datum/perk/skill_mod/remove_perk(mob/living/carbon/owner)
+ owner.set_skills(owner.skills.modifyRating(-cqc, -melee_weapons, -firearms, -pistols, -shotguns, -rifles, -smgs, -heavy_weapons, -smartgun, \
+ -engineer, -construction, -leadership, -medical, -surgery, -pilot, -police, -powerloader, -large_vehicle, -stamina))
+
+/datum/perk/skill_mod/cqc
+ name = "Hand to hand expertise"
+ desc = "Advanced hand to hand combat training gives you an edge when you need to punch someone in the face. Improved unarmed damage and stun chance."
+ ui_icon = "cqc_1"
+ cqc = 1
+ all_jobs = TRUE
+ unlock_cost = 250
+
+/datum/perk/skill_mod/cqc/two
+ name = "Hand to hand specialisation"
+ desc = "Muscle augments combined with specialised hand to hand combat training turn your body into a lethal weapon. Greatly improved unarmed damage and stun chance."
+ req_desc = "Requires Hand to hand expertise."
+ ui_icon = "cqc_2"
+ unlock_cost = 350
+ prereq_perks = list(/datum/perk/skill_mod/cqc)
+
+/datum/perk/skill_mod/melee
+ name = "Melee expertise"
+ desc = "Improved damage with melee weapons."
+ ui_icon = "melee_1"
+ melee_weapons = 1
+ all_jobs = TRUE
+ unlock_cost = 300
+
+/datum/perk/skill_mod/melee/two
+ name = "Melee specialisation"
+ desc = "Greatly improved damage with melee weapons."
+ req_desc = "Requires Melee expertise."
+ ui_icon = "melee_2"
+ prereq_perks = list(/datum/perk/skill_mod/melee)
+ unlock_cost = 400
+
+/datum/perk/skill_mod/firearms
+ name = "Advanced firearm training"
+ desc = "Improved handling for all firearms. A prerequisite for all gun skills perks, and increases the speed of tactical reloads."
+ ui_icon = "firearms"
+ firearms = 1
+ all_jobs = TRUE
+ unlock_cost = 400
+
+/datum/perk/skill_mod/pistols
+ name = "Advanced pistol training"
+ desc = "Improved damage, accuracy and scatter with pistol type firearms."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "pistols"
+ pistols = 1
+ all_jobs = TRUE
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 400
+
+/datum/perk/skill_mod/shotguns
+ name = "Advanced shotgun training"
+ desc = "Improved damage, accuracy and scatter with shotgun type firearms. Unlocks access to a shotgun secondary weapon in the backslot for some roles."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "shotguns"
+ shotguns = 1
+ all_jobs = TRUE
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 600
+
+/datum/perk/skill_mod/shotguns/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/som_shotgun, jobs_supported, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/marine_shotgun, jobs_supported, owner, 0)
+
+/datum/perk/skill_mod/rifles
+ name = "Advanced rifle training"
+ desc = "Improved damage, accuracy and scatter with rifle type firearms. Unlocks new weapons and ammo types for some roles."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "rifles"
+ rifles = 1
+ all_jobs = TRUE
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 1000
+
+/datum/perk/skill_mod/rifles/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ if(owner_stats.faction == FACTION_TERRAGOV)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/marine/standard_rifle, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/standard_carbine/enhanced, /datum/loadout_item/suit_store/main_gun/marine/standard_carbine, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/scout_carbine/enhanced, /datum/loadout_item/suit_store/main_gun/marine/scout_carbine, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine/enhanced, /datum/loadout_item/suit_store/main_gun/marine/suppressed_carbine, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/corpsman/carbine/enhanced, /datum/loadout_item/suit_store/main_gun/corpsman/carbine, SQUAD_CORPSMAN)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/corpsman/assault_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/corpsman/assault_rifle, SQUAD_CORPSMAN)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/engineer/carbine/enhanced, /datum/loadout_item/suit_store/main_gun/engineer/carbine, SQUAD_ENGINEER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/engineer/assault_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/engineer/assault_rifle, SQUAD_ENGINEER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/squad_leader/carbine/enhanced, /datum/loadout_item/suit_store/main_gun/squad_leader/carbine, SQUAD_LEADER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/squad_leader/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/squad_leader/standard_rifle, SQUAD_LEADER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/field_commander/carbine/enhanced, /datum/loadout_item/suit_store/main_gun/field_commander/carbine, FIELD_COMMANDER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/field_commander/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/field_commander/standard_rifle, FIELD_COMMANDER)
+
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/marine/plasma_rifle, SQUAD_MARINE, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/corpsman/plasma_rifle, SQUAD_CORPSMAN, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/engineer/plasma_rifle, SQUAD_ENGINEER, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_rifle, SQUAD_LEADER, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/field_commander/plasma_rifle, FIELD_COMMANDER, owner, 0)
+
+ else if(owner_stats.faction == FACTION_SOM)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/som_marine/standard_rifle, SOM_SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/som_marine/suppressed_rifle, SOM_SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_medic/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/som_medic/standard_rifle, SOM_SQUAD_CORPSMAN)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle/enhanced, /datum/loadout_item/suit_store/main_gun/som_engineer/standard_rifle, SOM_SQUAD_ENGINEER)
+
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/som_marine/volkite_charger, SOM_SQUAD_MARINE, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/som_medic/volkite_charger, SOM_SQUAD_CORPSMAN, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/som_engineer/volkite_charger, SOM_SQUAD_ENGINEER, owner, 0)
+
+/datum/perk/skill_mod/smgs
+ name = "Advanced SMG training"
+ desc = "Improved damage, accuracy and scatter with SMG type firearms. Unlocks new weapons and ammo types for some roles."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "smgs"
+ smgs = 1
+ all_jobs = TRUE
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 500
+
+/datum/perk/skill_mod/smgs/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ if(owner_stats.faction == FACTION_TERRAGOV)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/standard_smg/enhanced, /datum/loadout_item/suit_store/main_gun/marine/standard_smg, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/marine/smg_and_shield/enhanced, /datum/loadout_item/suit_store/main_gun/marine/smg_and_shield, SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/corpsman/standard_smg/enhanced, /datum/loadout_item/suit_store/main_gun/corpsman/standard_smg, SQUAD_CORPSMAN)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/engineer/standard_smg/enhanced, /datum/loadout_item/suit_store/main_gun/engineer/standard_smg, SQUAD_ENGINEER)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/squad_leader/standard_smg/enhanced, /datum/loadout_item/suit_store/main_gun/squad_leader/standard_smg, SQUAD_LEADER)
+
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/marine/plasma_smg, SQUAD_MARINE, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/corpsman/plasma_smg, SQUAD_CORPSMAN, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/engineer/plasma_smg, SQUAD_ENGINEER, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/squad_leader/plasma_smg, SQUAD_LEADER, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/field_commander/plasma_smg, FIELD_COMMANDER, owner, 0)
+ else if(owner_stats.faction == FACTION_SOM)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_marine/smg/enhanced, /datum/loadout_item/suit_store/main_gun/som_marine/smg, SOM_SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield/enhanced, /datum/loadout_item/suit_store/main_gun/som_marine/smg_and_shield, SOM_SQUAD_MARINE)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_marine/smg/enhanced, /datum/loadout_item/suit_store/main_gun/som_marine/smg, SOM_SQUAD_CORPSMAN)
+ owner_stats.replace_loadout_option(/datum/loadout_item/suit_store/main_gun/som_engineer/smg/enhanced, /datum/loadout_item/suit_store/main_gun/som_engineer/smg, SOM_SQUAD_ENGINEER)
+
+/datum/perk/skill_mod/heavy_weapons
+ name = "Heavy weapon specialisation"
+ desc = "Improved damage, accuracy and scatter with heavy weapon type firearms. Unlocks new weapons and ammo types for some roles."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "heavy"
+ heavy_weapons = 1
+ all_jobs = TRUE
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 800
+
+/datum/perk/skill_mod/heavy_weapons/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ if(owner_stats.faction == FACTION_TERRAGOV)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/tgmc_heam_rocket_bag, SQUAD_MARINE, owner, 0)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/suit_store/main_gun/marine/plasma_cannon, SQUAD_MARINE, owner, 0)
+ else if(owner_stats.faction == FACTION_SOM)
+ owner_stats.unlock_loadout_item(/datum/loadout_item/back/som_heat_rocket_bag, SOM_SQUAD_VETERAN, owner, 0)
+
+/datum/perk/skill_mod/smartgun
+ name = "Advanced smartgun training"
+ desc = "Improved damage, accuracy and scatter with smartguns type firearms."
+ req_desc = "Requires Advanced firearm training."
+ ui_icon = "smartguns"
+ smartgun = 1
+ jobs_supported = list(SQUAD_SMARTGUNNER, CAPTAIN)
+ prereq_perks = list(/datum/perk/skill_mod/firearms)
+ unlock_cost = 800
+
+/datum/perk/skill_mod/construction
+ name = "Advanced construction training"
+ desc = "Faster construction times when building. Some items may no longer have a penalty delay when constructing."
+ ui_icon = "construction"
+ construction = 2
+ all_jobs = TRUE
+ unlock_cost = 300
+
+/datum/perk/skill_mod/leadership
+ name = "Advanced leadership training"
+ desc = "Advanced leadership training and battlefield experience resulting in an improved ability to command and control the soldiers under your command. Improved effectiveness and range when issuing orders."
+ ui_icon = "leadership"
+ leadership = 1
+ jobs_supported = list(SQUAD_LEADER, FIELD_COMMANDER, STAFF_OFFICER, CAPTAIN, SOM_SQUAD_LEADER, SOM_STAFF_OFFICER, SOM_FIELD_COMMANDER, SOM_COMMANDER)
+ unlock_cost = 1100
+
+/datum/perk/skill_mod/medical
+ name = "Advanced medical training"
+ desc = "Faster at applying medical items. Some items may no longer have a penalty delay. Unlocks access to improved first aid pouches if not already available."
+ ui_icon = "medical"
+ medical = 2
+ all_jobs = TRUE
+ unlock_cost = 300
+
+/datum/perk/skill_mod/medical/unlock_bonus(mob/living/carbon/owner, datum/individual_stats/owner_stats)
+ if(!istype(owner_stats))
+ return
+ if(owner_stats.faction == FACTION_TERRAGOV)
+ for(var/job_type in owner_stats.loadouts)
+ owner_stats.replace_loadout_option(/datum/loadout_item/r_pocket/standard_first_aid/standard_improved, /datum/loadout_item/r_pocket/standard_first_aid, job_type)
+ owner_stats.replace_loadout_option(/datum/loadout_item/l_pocket/standard_first_aid/standard_improved, /datum/loadout_item/l_pocket/standard_first_aid, job_type)
+
+ else if(owner_stats.faction == FACTION_SOM)
+ for(var/job_type in owner_stats.loadouts)
+ owner_stats.replace_loadout_option(/datum/loadout_item/r_pocket/som_standard_first_aid/standard_improved, /datum/loadout_item/r_pocket/som_standard_first_aid, job_type)
+ owner_stats.replace_loadout_option(/datum/loadout_item/l_pocket/som_standard_first_aid/standard_improved, /datum/loadout_item/l_pocket/som_standard_first_aid, job_type)
+
+/datum/perk/skill_mod/stamina
+ name = "Improved stamina"
+ desc = "Superior physical conditioning results in overall improved stamina. Improved max stamina, stamina regen rate, and reduces the delay before stamina begins to regenerate after stamina loss."
+ ui_icon = "stamina_1"
+ stamina = 1
+ all_jobs = TRUE
+ unlock_cost = 600
+ ///How much this perk increases your max_stam by
+ var/stam_mod = 10
+
+/datum/perk/skill_mod/stamina/apply_perk(mob/living/carbon/owner)
+ . = ..()
+ owner.max_stamina += stam_mod
+ owner.max_stamina_buffer += stam_mod
+
+/datum/perk/skill_mod/stamina/remove_perk(mob/living/carbon/owner)
+ . = ..()
+ owner.max_stamina -= stam_mod
+ owner.max_stamina_buffer -= stam_mod
+
+/datum/perk/skill_mod/stamina/two
+ name = "Extreme stamina"
+ desc = "Greatly stamina regen rate, and further reduces the delay before stamina begins to regenerate."
+ desc = "Mechanically augmented physical conditioning results in significantly enhanced overall stamina. Further improved max stamina, stamina regen rate, and reduced delay before stamina begins to regenerate after stamina loss."
+ req_desc = "Requires Improved stamina."
+ ui_icon = "stamina_2"
+ prereq_perks = list(/datum/perk/skill_mod/stamina)
+ unlock_cost = 800
diff --git a/code/datums/gamemodes/campaign/rewards/allies.dm b/code/datums/gamemodes/campaign/rewards/allies.dm
index 1e8c0dbb69d0c..bdd861e0f816e 100644
--- a/code/datums/gamemodes/campaign/rewards/allies.dm
+++ b/code/datums/gamemodes/campaign/rewards/allies.dm
@@ -22,6 +22,7 @@
desc = "A colonial militia squad to augment our forces"
detailed_desc = "A large number of militia job slots are opened at no attrition cost. \
A local colonial militia sympathetic to our cause has offered a squad to support our troops. Equipped with lesser arms and armor than our own troops, but fairly numerous."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/militia_reinforcement
ui_icon = "militia"
bonus_job_list = list(
/datum/job/som/mercenary/militia/leader = 1,
@@ -34,6 +35,7 @@
desc = "A squad of freelance guns for hire to support our forces"
detailed_desc = "A moderate number of freelancer job slots are opened at no attrition cost. \
A contract has been bought for a squad of freelancers to augment our forces. With comparable equipment and training, they can help turn the tables when our forces are stretched thin."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/freelancer_reinforcement
ui_icon = "freelancers"
bonus_job_list = list(
/datum/job/freelancer/leader/campaign_bonus = 1,
@@ -47,6 +49,7 @@
desc = "A squad of ICC soldiers to support our forces"
detailed_desc = "A moderate number of ICC job slots are opened at no attrition cost. \
The ICC have authorised a small, local detachment of their troops to aid us in our conflict. They are well armed and armored, and could prove a valuable advantage in a fight."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/icc_reinforcement
ui_icon = "icc"
bonus_job_list = list(
/datum/job/icc/leader/campaign_bonus = 1,
@@ -60,6 +63,7 @@
desc = "An elite PMC team to assist in a joint operation"
detailed_desc = "A small number of PMC job slots are opened at no attrition cost. \
NanoTrasen have authorised a small team of their PMC contractors to assist us in combat. With superior arms and armor, they a powerful tactical asset."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/pmc_reinforcement
ui_icon = "pmc"
bonus_job_list = list(
/datum/job/pmc/leader/campaign_bonus = 1,
@@ -72,6 +76,7 @@
desc = "A shipment of combat robots to bolster your forces"
detailed_desc = "A four combat robot job slots are opened at no attrition cost. \
Combat robots are tough to kill, being immune to pain and chemicals, and resist both fire and radiation. They suffer from low mobility however."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/robot_reinforcement
ui_icon = "combat_robots"
cost = 6
bonus_job_list = list(
diff --git a/code/datums/gamemodes/campaign/rewards/campaign_asset_jobs.dm b/code/datums/gamemodes/campaign/rewards/campaign_asset_jobs.dm
index 1c7ff3d727c0a..bdd7ad68fd62e 100644
--- a/code/datums/gamemodes/campaign/rewards/campaign_asset_jobs.dm
+++ b/code/datums/gamemodes/campaign/rewards/campaign_asset_jobs.dm
@@ -444,20 +444,20 @@ What you lack in equipment and military training you make up in bravery and conv
job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_BOLD_NAME_ON_SELECTION|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS
job_cost = 0
outfits = list(
- /datum/outfit/job/freelancer/standard/campaign,
/datum/outfit/job/freelancer/standard/one/campaign,
/datum/outfit/job/freelancer/standard/two/campaign,
+ /datum/outfit/job/freelancer/standard/three/campaign,
)
-/datum/outfit/job/freelancer/standard/campaign
- ears = /obj/item/radio/headset/mainship
-
/datum/outfit/job/freelancer/standard/one/campaign
ears = /obj/item/radio/headset/mainship
/datum/outfit/job/freelancer/standard/two/campaign
ears = /obj/item/radio/headset/mainship
+/datum/outfit/job/freelancer/standard/three/campaign
+ ears = /obj/item/radio/headset/mainship
+
/datum/job/freelancer/medic/campaign_bonus
faction = FACTION_TERRAGOV
@@ -474,15 +474,15 @@ What you lack in equipment and military training you make up in bravery and conv
comm_title = "FL"
job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_BOLD_NAME_ON_SELECTION|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS
outfits = list(
- /datum/outfit/job/freelancer/grenadier/campaign,
/datum/outfit/job/freelancer/grenadier/one/campaign,
+ /datum/outfit/job/freelancer/grenadier/two/campaign,
)
job_cost = 0
-/datum/outfit/job/freelancer/grenadier/campaign
+/datum/outfit/job/freelancer/grenadier/one/campaign
ears = /obj/item/radio/headset/mainship
-/datum/outfit/job/freelancer/grenadier/one/campaign
+/datum/outfit/job/freelancer/grenadier/two/campaign
ears = /obj/item/radio/headset/mainship
/datum/job/freelancer/leader/campaign_bonus
@@ -490,15 +490,15 @@ What you lack in equipment and military training you make up in bravery and conv
comm_title = "FL"
job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_BOLD_NAME_ON_SELECTION|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS
outfits = list(
- /datum/outfit/job/freelancer/leader/campaign,
/datum/outfit/job/freelancer/leader/one/campaign,
+ /datum/outfit/job/freelancer/leader/two/campaign,
)
job_cost = 0
-/datum/outfit/job/freelancer/leader/campaign
+/datum/outfit/job/freelancer/leader/one/campaign
ears = /obj/item/radio/headset/mainship
-/datum/outfit/job/freelancer/leader/one/campaign
+/datum/outfit/job/freelancer/leader/two/campaign
ears = /obj/item/radio/headset/mainship
//PMC
@@ -652,7 +652,6 @@ Fight for TGMC, and attempt to achieve all objectives given to you."})
H.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
/datum/outfit/job/tgmc/campaign_robot/machine_gunner
- r_store = /obj/item/storage/pouch/pistol
belt = /obj/item/storage/belt/sparepouch
suit_store = /obj/item/weapon/gun/rifle/standard_gpmg/machinegunner
@@ -674,12 +673,10 @@ Fight for TGMC, and attempt to achieve all objectives given to you."})
H.equip_to_slot_or_del(new /obj/item/stack/cable_coil, SLOT_IN_BACKPACK)
H.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
H.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/marine/deployable, SLOT_IN_BACKPACK)
H.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_BACKPACK)
/datum/outfit/job/tgmc/campaign_robot/guardian
- r_store = /obj/item/storage/pouch/pistol
- belt = /obj/item/storage/belt/marine/te_cells
suit_store = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/gyro
r_hand = /obj/item/weapon/shield/riot/marine
@@ -703,9 +700,8 @@ Fight for TGMC, and attempt to achieve all objectives given to you."})
/datum/outfit/job/tgmc/campaign_robot/jetpack
wear_suit = /obj/item/clothing/suit/modular/robot/heavy/shield
r_store = /obj/item/storage/pouch/magazine/large
- belt = /obj/item/storage/belt/marine/te_cells
suit_store = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/mag_harness
- back = /obj/item/jetpack_marine
+ back = /obj/item/jetpack_marine/heavy
/datum/outfit/job/tgmc/campaign_robot/jetpack/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
. = ..()
@@ -720,8 +716,6 @@ Fight for TGMC, and attempt to achieve all objectives given to you."})
H.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_R_POUCH)
/datum/outfit/job/tgmc/campaign_robot/laser_mg
- r_store = /obj/item/storage/pouch/pistol
- belt = /obj/item/storage/belt/marine/te_cells
suit_store = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser/patrol
/datum/outfit/job/tgmc/campaign_robot/laser_mg/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
diff --git a/code/datums/gamemodes/campaign/rewards/disablers.dm b/code/datums/gamemodes/campaign/rewards/disablers.dm
index 9091d2f4b5c93..4baca3435c22e 100644
--- a/code/datums/gamemodes/campaign/rewards/disablers.dm
+++ b/code/datums/gamemodes/campaign/rewards/disablers.dm
@@ -9,18 +9,28 @@
var/list/types_disabled
///Rewards currently disabled. Recorded to reenable later
var/list/types_currently_disabled = list()
+ ///Does this apply instantly?
+ var/instant_use = FALSE
/datum/campaign_asset/asset_disabler/immediate_effect()
- RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_LOADED, PROC_REF(trigger_disabler))
+ if(instant_use)
+ trigger_disabler()
+ else
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_LOADED, PROC_REF(trigger_disabler))
+
+ RegisterSignal(faction, COMSIG_CAMPAIGN_NEW_ASSET, PROC_REF(disable_asset))
/datum/campaign_asset/asset_disabler/deactivate()
+ if(!uses)
+ UnregisterSignal(SSdcs, list(COMSIG_GLOB_CAMPAIGN_MISSION_LOADED, COMSIG_CAMPAIGN_NEW_ASSET))
+ asset_flags &= ~ASSET_DEBUFF
for(var/datum/campaign_asset/asset_type AS in types_currently_disabled)
asset_type.asset_flags &= ~ASSET_DISABLED
types_currently_disabled.Cut()
UnregisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_ENDED)
///Handles the actual disabling activation
-/datum/campaign_asset/asset_disabler/proc/trigger_disabler()
+/datum/campaign_asset/asset_disabler/proc/trigger_disabler(datum/source)
SIGNAL_HANDLER
var/datum/game_mode/hvh/campaign/mode = SSticker.mode
var/datum/campaign_mission/current_mission = mode.current_mission
@@ -28,20 +38,23 @@
return
for(var/i in faction.faction_assets)
- var/datum/campaign_asset/asset_type = faction.faction_assets[i]
- if(!asset_type)
- continue
- if(asset_type.type in types_disabled)
- asset_type.asset_flags |= ASSET_DISABLED
- types_currently_disabled += asset_type
+ disable_asset(asset = faction.faction_assets[i])
RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_ENDED, TYPE_PROC_REF(/datum/campaign_asset, deactivate))
uses --
- if(!uses)
- UnregisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_LOADED)
- asset_flags &= ~ASSET_DEBUFF
SEND_SIGNAL(src, COMSIG_CAMPAIGN_DISABLER_ACTIVATION)
+
+///Actually disables an asset
+/datum/campaign_asset/asset_disabler/proc/disable_asset(datum/source, datum/campaign_asset/asset)
+ SIGNAL_HANDLER
+ if(!istype(asset))
+ return
+ if(!(asset.type in types_disabled))
+ return
+ asset.asset_flags |= ASSET_DISABLED
+ types_currently_disabled += asset
+
/datum/campaign_asset/asset_disabler/tgmc_cas
name = "CAS disabled"
desc = "CAS fire support temporarily disabled"
@@ -50,6 +63,11 @@
types_disabled = list(/datum/campaign_asset/fire_support)
blacklist_mission_flags = MISSION_DISALLOW_FIRESUPPORT
+/datum/campaign_asset/asset_disabler/tgmc_cas/instant
+ uses = 1
+ instant_use = TRUE
+ detailed_desc = "Hostile assets in the AO are preventing the use of close air support during this mission."
+
/datum/campaign_asset/asset_disabler/som_cas
name = "CAS disabled"
desc = "CAS fire support temporarily disabled"
@@ -58,6 +76,11 @@
types_disabled = list(/datum/campaign_asset/fire_support/som_cas)
blacklist_mission_flags = MISSION_DISALLOW_FIRESUPPORT
+/datum/campaign_asset/asset_disabler/som_cas/instant
+ uses = 1
+ instant_use = TRUE
+ detailed_desc = "Hostile assets in the AO are preventing the use of close air support during this mission."
+
/datum/campaign_asset/asset_disabler/tgmc_mortar
name = "Mortar support disabled"
desc = "Mortar fire support temporarily disabled"
diff --git a/code/datums/gamemodes/campaign/rewards/drop_pods.dm b/code/datums/gamemodes/campaign/rewards/drop_pods.dm
index 18fd7896e164d..5977d47439fd2 100644
--- a/code/datums/gamemodes/campaign/rewards/drop_pods.dm
+++ b/code/datums/gamemodes/campaign/rewards/drop_pods.dm
@@ -2,6 +2,7 @@
name = "Enable drop pods"
desc = "Enables the use of drop pods for the current or next mission"
detailed_desc = "Repositions the ship to allow for orbital drop pod insertion during the current or next mission."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/pod_officer
ui_icon = "droppod_active"
uses = 3
cost = 9
@@ -28,6 +29,7 @@
name = "Rearm drop pod bays"
desc = "replace all used drop pods"
detailed_desc = "Replace all drop pods that have been previously deployed with refurbished units or ones from fleet storage, ready for immediate use."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/pod_officer
ui_icon = "droppod_refresh"
uses = 1
cost = 10
@@ -51,6 +53,7 @@
name = "Disable drop pods"
desc = "Prevents the enemy from using drop pods in the current or next mission"
detailed_desc = "Ground to Space weapon systems are activated to prevent TGMC close orbit support ships from positioning themselves for drop pod orbital assaults during the current or next mission."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/pod_officer
ui_icon = "droppod_broken"
uses = 2
asset_flags = ASSET_ACTIVATED_EFFECT|ASSET_ACTIVE_MISSION_ONLY
diff --git a/code/datums/gamemodes/campaign/rewards/equipment.dm b/code/datums/gamemodes/campaign/rewards/equipment.dm
index 5c03d0408d58a..6744713d215c0 100644
--- a/code/datums/gamemodes/campaign/rewards/equipment.dm
+++ b/code/datums/gamemodes/campaign/rewards/equipment.dm
@@ -1,5 +1,6 @@
//Parent for all 'spawn stuff' assets
/datum/campaign_asset/equipment
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/tgmc_req
asset_flags = ASSET_ACTIVATED_EFFECT|ASSET_SL_AVAILABLE
///list of objects to spawn when this asset is activated
var/list/obj/equipment_to_spawn = list()
@@ -27,6 +28,7 @@
name = "Gorgon consignment"
desc = "Five sets of Gorgon power armor"
detailed_desc = "Activatable by squad leaders. Your battalion has been assigned a number of Gorgon power armor sets, available at your request. Gorgon armor is the SOM's elite infantry armor, providing superior protection and an automedical system without significantly compromising on speed."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "gorgon"
uses = 5
cost = 12
@@ -56,6 +58,7 @@
)
/datum/campaign_asset/equipment/medkit_basic/som
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
equipment_to_spawn = list(
/obj/item/storage/pouch/firstaid/som/full,
/obj/item/storage/pouch/firstaid/som/full,
@@ -80,6 +83,9 @@
/obj/item/storage/box/crate/loot/materials_pack,
)
+/datum/campaign_asset/equipment/materials_pack/som
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
+
/datum/campaign_asset/equipment/ballistic_tgmc
name = "ballistic weapon cache"
desc = "Ballistic weapons and ammo"
@@ -101,6 +107,7 @@
name = "ballistic weapon cache"
desc = "Ballistic weapons and ammo"
detailed_desc = "A number of standard ballistic weapons and ammo to match."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "ballistic"
uses = 1
cost = 3
@@ -132,6 +139,7 @@
name = "Volkite weapon cache"
desc = "Volkite weapon cache and ammo"
detailed_desc = "A volkite caliver and charger, with accompanying ammo. Able to deflagrate targets, making them deadly against tightly packed opponents."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "volkite"
uses = 1
cost = 4
@@ -188,6 +196,7 @@
name = "Shotgun cache"
desc = "Shotgun and ammo"
detailed_desc = "A V-51 and ammo to match."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "shotgun"
uses = 1
cost = 2
@@ -247,6 +256,7 @@
name = "Lorica heavy armour"
desc = "Heavy armor upgrades"
detailed_desc = "A pair of heavy armor suits equipped with 'Lorica' armour upgrades. Premier protection, but somewhat cumbersome."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "lorica"
uses = 2
cost = 4
@@ -259,6 +269,7 @@
name = "Defensive shields"
desc = "Heavy shields to hide behind"
detailed_desc = "A pair of heavy riot shields. Able to withstand a tremendous amount of punishment at the cost of occupying a hand and slowing you down."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "riot_shield"
uses = 2
cost = 3
@@ -271,6 +282,7 @@
name = "Grenade resupply"
desc = "An assortment of grenades"
detailed_desc = "A variety of different grenade types. Throw towards enemy."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "grenade"
uses = 2
cost = 6
@@ -291,10 +303,14 @@
/obj/item/storage/box/explosive_mines/antitank,
)
+/datum/campaign_asset/equipment/at_mines/som
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
+
/datum/campaign_asset/equipment/tac_bino_som
name = "Tactical binoculars"
desc = "One set of tactical binoculars"
detailed_desc = "Tactical binoculars for seeing into the distance and calling down air support."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_req
ui_icon = "binoculars"
uses = 1
cost = 3
diff --git a/code/datums/gamemodes/campaign/rewards/fire_support.dm b/code/datums/gamemodes/campaign/rewards/fire_support.dm
index af20acbe2f719..e7b0be6429883 100644
--- a/code/datums/gamemodes/campaign/rewards/fire_support.dm
+++ b/code/datums/gamemodes/campaign/rewards/fire_support.dm
@@ -37,6 +37,7 @@
name = "Mortar support"
desc = "Mortar teams are activated to provide firesupport for this mission"
detailed_desc = "Activatable by squad leaders. A limited number of mortar strikes are available via tactical binoculars for this mission. Excellent for disrupting dug in enemy positions."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/tgmc_mortar
ui_icon = "mortar"
asset_flags = ASSET_ACTIVATED_EFFECT|ASSET_ACTIVE_MISSION_ONLY|ASSET_DISABLE_ON_MISSION_END|ASSET_SL_AVAILABLE
cost = 6
diff --git a/code/datums/gamemodes/campaign/rewards/mechs.dm b/code/datums/gamemodes/campaign/rewards/mechs.dm
index 06b21376ae52d..716fede63b57c 100644
--- a/code/datums/gamemodes/campaign/rewards/mechs.dm
+++ b/code/datums/gamemodes/campaign/rewards/mechs.dm
@@ -35,3 +35,65 @@
/datum/campaign_asset/mech/heavy/som
spawner_type = /obj/effect/landmark/campaign/mech_spawner/som/heavy
+
+//mech spawn points
+/obj/effect/landmark/campaign/mech_spawner
+ name = "tgmc med mech spawner"
+ icon_state = "mech"
+ ///Faction associated with this spawner
+ var/faction = FACTION_TERRAGOV
+ ///Colours to paint mechs from this spawner
+ var/list/colors = list(ARMOR_PALETTE_SPACE_CADET, ARMOR_PALETTE_GREYISH_TURQUOISE)
+ ///Colours to paint mech heads from this spawner for better visual clarity
+ var/list/head_colors = list(ARMOR_PALETTE_STORM, ARMOR_PALETTE_GREYISH_TURQUOISE, VISOR_PALETTE_SYNDIE_GREEN)
+ ///Mech type for this spawner
+ var/obj/vehicle/sealed/mecha/combat/greyscale/mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/assault/noskill
+
+/obj/effect/landmark/campaign/mech_spawner/Initialize(mapload)
+ . = ..()
+ GLOB.campaign_mech_spawners[faction] += list(src)
+
+/obj/effect/landmark/campaign/mech_spawner/Destroy()
+ GLOB.campaign_mech_spawners[faction] -= src
+ return ..()
+
+///Creates and sets up the mech
+/obj/effect/landmark/campaign/mech_spawner/proc/spawn_mech()
+ var/obj/vehicle/sealed/mecha/combat/greyscale/new_mech = new mech_type(loc)
+ for(var/i in new_mech.limbs)
+ var/datum/mech_limb/limb = new_mech.limbs[i]
+ limb.update_colors(arglist(istype(limb, /datum/mech_limb/head) ? head_colors : colors))
+ new_mech.update_icon()
+ return new_mech
+
+/obj/effect/landmark/campaign/mech_spawner/heavy
+ name = "tgmc heavy mech spawner"
+ icon_state = "mech_heavy"
+ head_colors = list(ARMOR_PALETTE_RED, ARMOR_PALETTE_GREYISH_TURQUOISE, VISOR_PALETTE_SYNDIE_GREEN)
+ mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/vanguard/noskill
+
+/obj/effect/landmark/campaign/mech_spawner/light
+ name = "tgmc light mech spawner"
+ icon_state = "mech_light"
+ head_colors = list(ARMOR_PALETTE_SPACE_CADET, ARMOR_PALETTE_GREYISH_TURQUOISE, VISOR_PALETTE_SYNDIE_GREEN)
+ mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/recon/noskill
+
+/obj/effect/landmark/campaign/mech_spawner/som
+ name = "som med mech spawner"
+ faction = FACTION_SOM
+ colors = list(ARMOR_PALETTE_GINGER, ARMOR_PALETTE_ANGELIC)
+ head_colors = list(ARMOR_PALETTE_ANGELIC, ARMOR_PALETTE_GREY, VISOR_PALETTE_SYNDIE_GREEN)
+
+/obj/effect/landmark/campaign/mech_spawner/som/heavy
+ name = "som heavy mech spawner"
+ icon_state = "mech_heavy"
+ colors = list(ARMOR_PALETTE_GINGER, ARMOR_PALETTE_MAGENTA)
+ head_colors = list(ARMOR_PALETTE_MAGENTA, ARMOR_PALETTE_GRAPE, VISOR_PALETTE_ELITE_ORANGE)
+ mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/vanguard/noskill
+
+/obj/effect/landmark/campaign/mech_spawner/som/light
+ name = "som light mech spawner"
+ icon_state = "mech_light"
+ colors = list(ARMOR_PALETTE_GINGER, ARMOR_PALETTE_BLACK)
+ head_colors = list(ARMOR_PALETTE_GINGER, ARMOR_PALETTE_BLACK, VISOR_PALETTE_SYNDIE_GREEN)
+ mech_type = /obj/vehicle/sealed/mecha/combat/greyscale/recon/noskill
diff --git a/code/datums/gamemodes/campaign/rewards/reserves.dm b/code/datums/gamemodes/campaign/rewards/reserves.dm
index 6c6151c0a219f..558c4e2d9db7f 100644
--- a/code/datums/gamemodes/campaign/rewards/reserves.dm
+++ b/code/datums/gamemodes/campaign/rewards/reserves.dm
@@ -52,7 +52,13 @@
for(var/mob/candidate AS in GLOB.player_list)
if(candidate.faction != faction.faction)
continue
- mode.player_death_times -= candidate.key
+ if(candidate.stat != DEAD)
+ continue
+ mode.player_death_times -= candidate.ckey
+ deltimer(mode.respawn_timers[candidate.ckey])
+ mode.respawn_timers[candidate.ckey] = null
+ mode.player_respawn(candidate)
+
to_chat(candidate, "Tactical reserves mobilised. You can now respawn immediately if possible.")
candidate.playsound_local(null, 'sound/ambience/votestart.ogg', 50)
diff --git a/code/datums/gamemodes/campaign/rewards/teleporter.dm b/code/datums/gamemodes/campaign/rewards/teleporter.dm
index 293eebddbd247..afb477b690e74 100644
--- a/code/datums/gamemodes/campaign/rewards/teleporter.dm
+++ b/code/datums/gamemodes/campaign/rewards/teleporter.dm
@@ -3,6 +3,7 @@
name = "Enable Teleporter Array"
desc = "Enables the use of the Teleporter Array for the current or next mission"
detailed_desc = "Established a link between our Teleporter Array and its master Bluespace drive, allowing its operation during the current or next mission."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_scientist
ui_icon = "tele_active"
uses = 2
cost = 5
@@ -43,6 +44,7 @@
name = "Teleporter Array charges"
desc = "+2 uses of the Teleporter Array"
detailed_desc = "Central command have allocated the battalion with two additional uses of the Teleporter Array. Its extremely costly to run and demand is high across the conflict zone, so make them count."
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_scientist
ui_icon = "tele_uses"
uses = 3
cost = 6
@@ -61,6 +63,7 @@
desc = "Teleporter Array has been permenantly disabled"
detailed_desc = "The Bluespace drive powering all Teleporter Arrays in the conflict zone has been destroyed, rending all Teleporter Arrays inoperable. You'll have to deploy the old fashion way from here on out."
asset_flags = ASSET_IMMEDIATE_EFFECT|ASSET_DEBUFF
+ asset_portrait = /atom/movable/screen/text/screen_text/picture/potrait/som_scientist
ui_icon = "tele_broken"
/datum/campaign_asset/teleporter_disabled/immediate_effect()
diff --git a/code/datums/gamemodes/combat_patrol.dm b/code/datums/gamemodes/combat_patrol.dm
index e7706758be558..f1ec6c67a9367 100644
--- a/code/datums/gamemodes/combat_patrol.dm
+++ b/code/datums/gamemodes/combat_patrol.dm
@@ -1,7 +1,7 @@
/datum/game_mode/hvh/combat_patrol
name = "Combat Patrol"
config_tag = "Combat Patrol"
- flags_round_type = MODE_LATE_OPENING_SHUTTER_TIMER|MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY
+ round_type_flags = MODE_LATE_OPENING_SHUTTER_TIMER|MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY
shutters_drop_time = 3 MINUTES
whitelist_ship_maps = list(MAP_COMBAT_PATROL_BASE)
blacklist_ship_maps = null
diff --git a/code/datums/gamemodes/crash.dm b/code/datums/gamemodes/crash.dm
index 34116d1318123..36214a67cc923 100644
--- a/code/datums/gamemodes/crash.dm
+++ b/code/datums/gamemodes/crash.dm
@@ -1,8 +1,8 @@
/datum/game_mode/infestation/crash
name = "Crash"
config_tag = "Crash"
- flags_round_type = MODE_INFESTATION|MODE_XENO_SPAWN_PROTECT|MODE_DEAD_GRAB_FORBIDDEN|MODE_DISALLOW_RAILGUN
- flags_xeno_abilities = ABILITY_CRASH
+ round_type_flags = MODE_INFESTATION|MODE_XENO_SPAWN_PROTECT|MODE_DEAD_GRAB_FORBIDDEN|MODE_DISALLOW_RAILGUN
+ xeno_abilities_flags = ABILITY_CRASH
valid_job_types = list(
/datum/job/terragov/squad/standard = -1,
/datum/job/terragov/squad/engineer = 1,
@@ -105,7 +105,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_NUKE_DIFFUSED, PROC_REF(on_nuclear_diffuse))
RegisterSignal(SSdcs, COMSIG_GLOB_NUKE_START, PROC_REF(on_nuke_started))
- if(!(flags_round_type & MODE_INFESTATION))
+ if(!(round_type_flags & MODE_INFESTATION))
return
for(var/i in GLOB.alive_xeno_list_hive[XENO_HIVE_NORMAL])
@@ -120,7 +120,12 @@
/datum/game_mode/infestation/crash/announce()
to_chat(world, span_round_header("The current map is - [SSmapping.configs[GROUND_MAP].map_name]!"))
- priority_announce("Scheduled for landing in T-10 Minutes. Prepare for landing. Known hostiles near LZ. Detonation Protocol Active, planet disposable. Marines disposable.", type = ANNOUNCEMENT_PRIORITY)
+ priority_announce(
+ message = "Scheduled for landing in T-10 Minutes. Prepare for landing. Known hostiles near LZ. Detonation Protocol Active, planet disposable. Marines disposable.",
+ title = "Good morning, marines.",
+ type = ANNOUNCEMENT_PRIORITY,
+ color_override = "red"
+ )
playsound(shuttle, 'sound/machines/warning-buzzer.ogg', 75, 0, 30)
diff --git a/code/datums/gamemodes/extended.dm b/code/datums/gamemodes/extended.dm
index 6babe060702e7..747b3b1d53118 100644
--- a/code/datums/gamemodes/extended.dm
+++ b/code/datums/gamemodes/extended.dm
@@ -1,13 +1,16 @@
/datum/game_mode/extended
name = "Extended"
config_tag = "Extended"
- flags_xeno_abilities = ABILITY_NUCLEARWAR
+ xeno_abilities_flags = ABILITY_NUCLEARWAR
valid_job_types = list(
/datum/job/terragov/command/captain = 1,
/datum/job/terragov/command/fieldcommander = 1,
/datum/job/terragov/command/staffofficer = 4,
- /datum/job/terragov/command/pilot = 2,
+ /datum/job/terragov/command/pilot = 1,
+ /datum/job/terragov/command/transportofficer = 1,
/datum/job/terragov/command/mech_pilot = 0,
+ /datum/job/terragov/command/assault_crewman = 2,
+ /datum/job/terragov/command/transport_crewman = 1,
/datum/job/terragov/engineering/chief = 1,
/datum/job/terragov/engineering/tech = 1,
/datum/job/terragov/requisitions/officer = 1,
diff --git a/code/datums/gamemodes/hvh.dm b/code/datums/gamemodes/hvh.dm
index 36998667944e8..ecb7cd077f5ef 100644
--- a/code/datums/gamemodes/hvh.dm
+++ b/code/datums/gamemodes/hvh.dm
@@ -1,24 +1,25 @@
//The base setup for HvH gamemodes, not for actual use
/datum/game_mode/hvh
name = "HvH base mode"
- flags_round_type = MODE_LATE_OPENING_SHUTTER_TIMER|MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY|MODE_TWO_HUMAN_FACTIONS
+ round_type_flags = MODE_LATE_OPENING_SHUTTER_TIMER|MODE_TWO_HUMAN_FACTIONS|MODE_HUMAN_ONLY|MODE_TWO_HUMAN_FACTIONS
shutters_drop_time = 3 MINUTES
- flags_xeno_abilities = ABILITY_CRASH
+ xeno_abilities_flags = ABILITY_CRASH
factions = list(FACTION_TERRAGOV, FACTION_SOM)
valid_job_types = list(
- /datum/job/terragov/squad/engineer = 4,
+ /datum/job/terragov/squad/engineer = 8,
/datum/job/terragov/squad/corpsman = 8,
/datum/job/terragov/squad/smartgunner = 4,
/datum/job/terragov/squad/leader = 4,
/datum/job/terragov/squad/standard = -1,
/datum/job/som/squad/leader = 4,
- /datum/job/som/squad/veteran = 2,
- /datum/job/som/squad/engineer = 4,
+ /datum/job/som/squad/veteran = 4,
+ /datum/job/som/squad/engineer = 8,
/datum/job/som/squad/medic = 8,
/datum/job/som/squad/standard = -1,
)
job_points_needed_by_job_type = list(
- /datum/job/som/squad/veteran = 5, //Every 5 non vets join, a new vet slot opens
+ /datum/job/terragov/squad/smartgunner = 5,
+ /datum/job/som/squad/veteran = 5,
)
/// Time between two bioscan
var/bioscan_interval = 3 MINUTES
@@ -28,13 +29,6 @@
for(var/z_num in SSmapping.areas_in_z)
set_z_lighting(z_num)
-/datum/game_mode/hvh/scale_roles()
- . = ..()
- if(!.)
- return
- var/datum/job/scaled_job = SSjob.GetJobType(/datum/job/som/squad/veteran)
- scaled_job.job_points_needed = 5 //Every 5 non vets join, a new vet slot opens
-
//sets TGMC and SOM squads
/datum/game_mode/hvh/set_valid_squads()
SSjob.active_squads[FACTION_TERRAGOV] = list()
@@ -157,7 +151,7 @@
Sensors indicate [num_tgmc_delta || "no"] unknown lifeform signature[num_tgmc_delta > 1 ? "s":""] present in the area of operations[tgmc_location ? ", including one at: [tgmc_location]":""]"}
if(announce_som)
- priority_announce(som_scan_input, som_scan_name, sound = 'sound/AI/bioscan.ogg', receivers = (som_list + GLOB.observer_list))
+ priority_announce(som_scan_input, som_scan_name, sound = 'sound/AI/bioscan.ogg', color_override = "orange", receivers = (som_list + GLOB.observer_list))
//announcement for TGMC
var/marine_scan_name = "Long Range Tactical Bioscan Status"
@@ -166,14 +160,14 @@ Sensors indicate [num_tgmc_delta || "no"] unknown lifeform signature[num_tgmc_de
Sensors indicate [num_som_delta || "no"] unknown lifeform signature[num_som_delta > 1 ? "s":""] present in the area of operations[som_location ? ", including one at: [som_location]":""]"}
if(announce_marines)
- priority_announce(marine_scan_input, marine_scan_name, sound = 'sound/AI/bioscan.ogg', receivers = (tgmc_list + GLOB.observer_list))
+ priority_announce(marine_scan_input, marine_scan_name, sound = 'sound/AI/bioscan.ogg', color_override = "blue", receivers = (tgmc_list + GLOB.observer_list))
log_game("Bioscan. [num_tgmc] active TGMC personnel[tgmc_location ? " Location: [tgmc_location]":""] and [num_som] active SOM personnel[som_location ? " Location: [som_location]":""]")
for(var/i in GLOB.observer_list)
var/mob/M = i
- to_chat(M, "
Detailed Information
")
- to_chat(M, {"[num_som] SOM alive.
+ to_chat(M, "Detailed Information")
+ to_chat(M, {"[num_som] SOM alive.
[num_tgmc] Marine\s alive."})
message_admins("Bioscan - Marines: [num_tgmc] active TGMC personnel[tgmc_location ? " .Location:[tgmc_location]":""]")
diff --git a/code/datums/gamemodes/infestation.dm b/code/datums/gamemodes/infestation.dm
index de2e61a0d4d26..f0cb0c4b90148 100644
--- a/code/datums/gamemodes/infestation.dm
+++ b/code/datums/gamemodes/infestation.dm
@@ -23,7 +23,7 @@
weed_type = pickweight(GLOB.weed_prob_list)
new weed_type(T)
for(var/turf/T AS in GLOB.xeno_resin_wall_turfs)
- T.ChangeTurf(/turf/closed/wall/resin, T.type)
+ T.ChangeTurf(/turf/closed/wall/resin/regenerating, T.type)
for(var/i in GLOB.xeno_resin_door_turfs)
new /obj/structure/mineral_door/resin(i)
for(var/i in GLOB.xeno_tunnel_spawn_turfs)
@@ -52,9 +52,8 @@
/datum/game_mode/infestation/announce_bioscans(show_locations = TRUE, delta = 2, ai_operator = FALSE, announce_humans = TRUE, announce_xenos = TRUE, send_fax = TRUE)
if(ai_operator)
- var/mob/living/silicon/ai/bioscanning_ai = usr
#ifndef TESTING
-
+ var/mob/living/silicon/ai/bioscanning_ai = usr
if((bioscanning_ai.last_ai_bioscan + COOLDOWN_AI_BIOSCAN) > world.time)
to_chat(bioscanning_ai, "Bioscan instruments are still recalibrating from their last use.")
return
@@ -108,15 +107,19 @@
for(var/i in GLOB.alive_xeno_list_hive[XENO_HIVE_NORMAL])
var/mob/M = i
SEND_SOUND(M, S)
- to_chat(M, span_xenoannounce("The Queen Mother reaches into your mind from worlds away."))
- to_chat(M, span_xenoannounce("To my children and their Queen. I sense [numHostsShipr ? "approximately [numHostsShipr]":"no"] host[numHostsShipr > 1 ? "s":""] in the metal hive[BIOSCAN_LOCATION(show_locations, hostLocationS)], [numHostsPlanet || "none"] scattered elsewhere[BIOSCAN_LOCATION(show_locations, hostLocationP)] and [numHostsTransitr ? "approximately [numHostsTransitr]":"no"] host[numHostsTransitr > 1 ? "s":""] on the metal bird in transit."))
+ to_chat(M, assemble_alert(
+ title = "Queen Mother Report",
+ subtitle = "The Queen Mother reaches into your mind...",
+ message = "To my children and their Queen, I sense [numHostsShipr ? "approximately [numHostsShipr]":"no"] host[numHostsShipr > 1 ? "s":""] in the metal hive[BIOSCAN_LOCATION(show_locations, hostLocationS)], [numHostsPlanet || "none"] scattered elsewhere[BIOSCAN_LOCATION(show_locations, hostLocationP)] and [numHostsTransitr ? "approximately [numHostsTransitr]":"no"] host[numHostsTransitr > 1 ? "s":""] on the metal bird in transit.",
+ color_override = "purple"
+ ))
var/name = "[MAIN_AI_SYSTEM] Bioscan Status"
var/input = {"Bioscan complete. Sensors indicate [numXenosShip || "no"] unknown lifeform signature[numXenosShip > 1 ? "s":""] present on the ship[BIOSCAN_LOCATION(show_locations, xenoLocationS)], [numXenosPlanetr ? "approximately [numXenosPlanetr]":"no"] signature[numXenosPlanetr > 1 ? "s":""] located elsewhere[BIOSCAN_LOCATION(show_locations, xenoLocationP)] and [numXenosTransit || "no"] unknown lifeform signature[numXenosTransit > 1 ? "s":""] in transit."}
var/ai_name = "[usr] Bioscan Status"
if(ai_operator)
- priority_announce(input, ai_name, sound = 'sound/AI/bioscan.ogg')
+ priority_announce(input, ai_name, sound = 'sound/AI/bioscan.ogg', color_override = "grey", receivers = (GLOB.alive_human_list + GLOB.ai_list))
log_game("Bioscan. Humans: [numHostsPlanet] on the planet[hostLocationP ? " Location:[hostLocationP]":""] and [numHostsShip] on the ship.[hostLocationS ? " Location: [hostLocationS].":""] Xenos: [numXenosPlanetr] on the planet and [numXenosShip] on the ship[xenoLocationP ? " Location:[xenoLocationP]":""] and [numXenosTransit] in transit.")
switch(GLOB.current_orbit)
@@ -131,7 +134,7 @@
return
if(announce_humans)
- priority_announce(input, name, sound = 'sound/AI/bioscan.ogg')
+ priority_announce(input, name, sound = 'sound/AI/bioscan.ogg', color_override = "grey", receivers = (GLOB.alive_human_list + GLOB.ai_list)) // Hide this from observers, they have their own detailed alert.
if(send_fax)
var/fax_message = generate_templated_fax("Combat Information Center", "[MAIN_AI_SYSTEM] Bioscan Status", "", input, "", MAIN_AI_SYSTEM)
@@ -141,13 +144,18 @@
for(var/i in GLOB.observer_list)
var/mob/M = i
- to_chat(M, "
Detailed Information
")
- to_chat(M, {"[numXenosPlanet] xeno\s on the planet.
+ to_chat(M, assemble_alert(
+ title = "Detailed Bioscan",
+ message = {"[numXenosPlanet] xeno\s on the planet.
[numXenosShip] xeno\s on the ship.
+[numXenosTransit] xeno\s in transit.
+
[numHostsPlanet] human\s on the planet.
[numHostsShip] human\s on the ship.
-[numHostsTransit] human\s in transit.
-[numXenosTransit] xeno\s in transit."})
+[numHostsTransit] human\s in transit."},
+ color_override = "purple",
+ minor = TRUE
+ ))
message_admins("Bioscan - Humans: [numHostsPlanet] on the planet[hostLocationP ? ". Location:[hostLocationP]":""]. [numHostsShipr] on the ship.[hostLocationS ? " Location: [hostLocationS].":""]. [numHostsTransitr] in transit.")
message_admins("Bioscan - Xenos: [numXenosPlanetr] on the planet[numXenosPlanetr > 0 && xenoLocationP ? ". Location:[xenoLocationP]":""]. [numXenosShip] on the ship.[xenoLocationS ? " Location: [xenoLocationS].":""] [numXenosTransitr] in transit.")
@@ -289,7 +297,12 @@
if(!SSmapping.configs[GROUND_MAP].announce_text)
return
- priority_announce(SSmapping.configs[GROUND_MAP].announce_text, SSmapping.configs[SHIP_MAP].map_name)
+ priority_announce(
+ title = "High Command Update",
+ subtitle = "Good morning, marines.",
+ message = "Cryosleep disengaged by TGMC High Command.
@@ -99,6 +108,7 @@ What you lack alone, you gain standing shoulder to shoulder with the men and wom
/datum/job/terragov/squad/corpsman = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
job_points_needed = 5
html_description = {"
@@ -137,10 +147,12 @@ Your squaddies will look to you when it comes to construction in the field of ba
new_human.wear_id.paygrade = "E3"
if(1501 to 6000) // 25 hrs
new_human.wear_id.paygrade = "E4"
- if(6001 to 60000) // 100 hrs
+ if(6001 to 18000) // 100 hrs
new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
if(60001 to INFINITY) // 1000 hrs
- new_human.wear_id.paygrade = "E9" //If you play way too much TGMC. 1000 hours.
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
//Squad Corpsman
/datum/job/terragov/squad/corpsman
@@ -157,6 +169,7 @@ Your squaddies will look to you when it comes to construction in the field of ba
jobworth = list(
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
/datum/job/xenomorph = LARVA_POINTS_REGULAR,
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_MEDIUM,
/datum/job/terragov/squad/engineer = SMARTIE_POINTS_REGULAR,
@@ -197,10 +210,12 @@ You may not be a fully-fledged doctor, but you stand between life and death when
new_human.wear_id.paygrade = "E3"
if(1501 to 6000) // 25 hrs
new_human.wear_id.paygrade = "E4"
- if(6001 to 60000) // 100 hrs
+ if(6001 to 18000) // 100 hrs
new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
if(60001 to INFINITY) // 1000 hrs
- new_human.wear_id.paygrade = "E9" //If you play way too much TGMC. 1000 hours.
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
//Squad Smartgunner
/datum/job/terragov/squad/smartgunner
@@ -248,10 +263,12 @@ You may not be a fully-fledged doctor, but you stand between life and death when
new_human.wear_id.paygrade = "E3"
if(1501 to 6000) // 25 hrs
new_human.wear_id.paygrade = "E4"
- if(6001 to 60000) // 100 hrs
+ if(6001 to 18000) // 100 hrs
new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
if(60001 to INFINITY) // 1000 hrs
- new_human.wear_id.paygrade = "E9" //If you play way too much TGMC. 1000 hours.
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
/datum/outfit/job/marine/smartgunner
name = SQUAD_SMARTGUNNER
@@ -275,7 +292,7 @@ You may not be a fully-fledged doctor, but you stand between life and death when
exp_type = EXP_TYPE_REGULAR_ALL
job_flags = JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS
jobworth = list(
- /datum/job/xenomorph = LARVA_POINTS_STRONG,
+ /datum/job/xenomorph = LARVA_POINTS_REGULAR,
)
job_points_needed = 10 //Redefined via config.
@@ -301,8 +318,8 @@ You can serve a variety of roles, so choose carefully."})
comm_title = JOB_COMM_TITLE_SQUAD_LEADER
total_positions = 4
supervisors = "the acting field commander"
- access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP)
- minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP)
+ access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE)
+ minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE)
skills_type = /datum/skills/sl
display_order = JOB_DISPLAY_ORDER_SQUAD_LEADER
outfit = /datum/outfit/job/marine/leader
@@ -316,6 +333,7 @@ You can serve a variety of roles, so choose carefully."})
/datum/job/terragov/squad/engineer = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Hard
@@ -294,7 +265,7 @@ You are in charge of logistics and the overwatch system. You are also in line to
new_human.wear_id.paygrade = "O5"
/datum/job/terragov/command/staffofficer/campaign
- outfit = /datum/outfit/job/command/staffofficer/campaign
+ outfit = /datum/outfit/job/command/staffofficer_campaign
multiple_outfits = FALSE
/datum/outfit/job/command/staffofficer
@@ -321,15 +292,97 @@ You are in charge of logistics and the overwatch system. You are also in line to
r_store = /obj/item/storage/pouch/general/large
l_store = /obj/item/binoculars/tactical
-/datum/outfit/job/command/staffofficer/campaign
- l_store = /obj/item/binoculars/fire_support/campaign
+/datum/outfit/job/command/staffofficer_campaign
+ name = STAFF_OFFICER
+ jobtype = /datum/job/terragov/command/staffofficer
+
+ id = /obj/item/card/id/silver
+
+//Transport Officer
+/datum/job/terragov/command/transportofficer
+ title = TRANSPORT_OFFICER
+ paygrade = "WO"
+ comm_title = "TO"
+ total_positions = 1
+ access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE)
+ minimal_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_MEDBAY)
+ skills_type = /datum/skills/transportofficer
+ display_order = JOB_DISPLAY_ORDER_TRANSPORT_OFFICER
+ outfit = /datum/outfit/job/command/transportofficer
+ exp_requirements = XP_REQ_EXPERT
+ exp_type = EXP_TYPE_REGULAR_ALL
+ job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD
+ jobworth = list(
+ /datum/job/xenomorph = LARVA_POINTS_SHIPSIDE_STRONG,
+ /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
+ /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
+ /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
+ )
+ html_description = {"
+ Difficulty: Hard
+ You answer to the acting Command Staff
+ Unlock Requirement: 100 hours
+ Gamemode Availability: Nuclear War
+ Duty: Pilot the Tadpole, a versatile dropship capable of fulfilling roles ranging from ambulance to mobile bunker.
+ "}
+ minimap_icon = "transportofficer"
+
+/datum/job/terragov/command/transportofficer/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE)
+ . = ..()
+ if(!ishuman(new_mob))
+ return
+ var/mob/living/carbon/human/new_human = new_mob
+ var/playtime_mins = user?.client?.get_exp(title)
+ if(!playtime_mins || playtime_mins < 1 )
+ return
+ switch(playtime_mins)
+ if(0 to 600) // starting
+ new_human.wear_id.paygrade = "WO"
+ if(601 to 3000) // 10 hrs
+ new_human.wear_id.paygrade = "CWO"
+ if(3001 to 6000) // 50 hrs
+ new_human.wear_id.paygrade = "O1"
+ if(6001 to INFINITY) // 100 hrs
+ new_human.wear_id.paygrade = "O2"
+
+/datum/job/terragov/command/transportofficer/radio_help_message(mob/M)
+ . = ..()
+ to_chat(M, {"Your job is to support marines mobile dropship support with the Tadpole.
+You are to ensure the Tadpole's survival and to transport marines around, acting as a mobile bunker. In the case of it's death, you may perform the role of Combat Engineer.
+"})
+
+/datum/outfit/job/command/transportofficer
+ name = TRANSPORT_OFFICER
+ jobtype = /datum/job/terragov/command/transportofficer
+
+ id = /obj/item/card/id/silver
+ belt = /obj/item/storage/belt/utility/full
+ ears = /obj/item/radio/headset/mainship/mcom
+ w_uniform = /obj/item/clothing/under/marine/officer/pilot
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/pilot
+ shoes = /obj/item/clothing/shoes/marine/full
+ gloves = /obj/item/clothing/gloves/marine/insulated
+ glasses = /obj/item/clothing/glasses/welding/superior
+ head = /obj/item/clothing/head/helmet/marine/pilot
+ r_store = /obj/item/storage/pouch/construction
+ l_store = /obj/item/hud_tablet/transportofficer
+ back = /obj/item/storage/backpack/marine/engineerpack
+ suit_store = /obj/item/storage/holster/belt/pistol/m4a3/vp70
+
+/datum/outfit/job/command/transportofficer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ H.equip_to_slot_or_hand(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_R_POUCH)
+ H.equip_to_slot_or_hand(new /obj/item/stack/sheet/plasteel/large_stack, SLOT_IN_R_POUCH)
+ H.equip_to_slot_or_hand(new /obj/item/stack/sandbags/large_stack, SLOT_IN_R_POUCH)
+ H.equip_to_slot_or_hand(new /obj/item/stack/barbed_wire/full, SLOT_IN_R_POUCH)
//Pilot Officer
/datum/job/terragov/command/pilot
title = PILOT_OFFICER
paygrade = "WO"
comm_title = "PO"
- total_positions = 2
+ total_positions = 1
access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT)
minimal_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_MEDBAY)
skills_type = /datum/skills/pilot
@@ -343,13 +396,14 @@ You are in charge of logistics and the overwatch system. You are also in line to
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Medium
You answer to the acting Command Staff
Unlock Requirement: Starting Role
Gamemode Availability: Nuclear War
- Duty: Choose between the Condor, a modular attack aircraft that provides close air support with a variety of weapons ranging from the inbuilt gatling to wing mounted rockets; or the Tadpole, a versatile dropship capable of fulfilling roles ranging from ambulance to mobile bunker.
+ Duty: Pilot the Condor, a modular attack aircraft that provides close air support with a variety of weapons ranging from the inbuilt gatling to wing mounted rockets.
"}
minimap_icon = "pilot"
@@ -374,9 +428,9 @@ You are in charge of logistics and the overwatch system. You are also in line to
/* RUTGMC DELETION
/datum/job/terragov/command/pilot/radio_help_message(mob/M)
. = ..()
- to_chat(M, {"Your job is to support marines with either close air support via the Condor, or mobile dropship support with the Tadpole.
-While you are in charge of all aerial crafts the Alamo does not require supervision outside of turning automatic mode on or off at crucial times, and you are expected to choose between the Condor and Tadpole.
-Though you are a warrant officer, your authority is limited to the dropship and your chosen aerial craft, where you have authority over the enlisted personnel.
+ to_chat(M, {"Your job is to support marines with either close air support via the Condor.
+You are expected to use the Condor as the Alamo is able to be ran automatically, though at some points you will be required to take control of the Alamo for the operation's success, though highly unlikey.
+Though you are a warrant officer, your authority is limited to the dropship and the Condor, where you have authority over the enlisted personnel.
"})
*/
@@ -415,6 +469,7 @@ Though you are a warrant officer, your authority is limited to the dropship and
jobworth = list(
/datum/job/xenomorph = LARVA_POINTS_REGULAR,
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty:Very Hard
@@ -439,12 +494,16 @@ You can serve your Division in a variety of roles, so choose carefully."})
if(!playtime_mins || playtime_mins < 1 )
return
switch(playtime_mins)
- if(0 to 1500) //starting
+ if(0 to 1500) // starting
new_human.wear_id.paygrade = "E3"
- if(1500 to 7500) // 25 hrs
+ if(1501 to 6000) // 25 hrs
new_human.wear_id.paygrade = "E4"
- if(7501 to INFINITY) // 125 hrs
+ if(6001 to 18000) // 100 hrs
new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
+ if(60001 to INFINITY) // 1000 hrs
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
/datum/outfit/job/command/mech_pilot
name = MECH_PILOT
@@ -460,6 +519,146 @@ You can serve your Division in a variety of roles, so choose carefully."})
shoes = /obj/item/clothing/shoes/marine/full
gloves = /obj/item/clothing/gloves/marine
+//tank/arty driver+gunner
+/datum/job/terragov/command/assault_crewman
+ title = ASSAULT_CREWMAN
+ req_admin_notify = TRUE
+ paygrade = "E3"
+ comm_title = "AC"
+ total_positions = 0
+ skills_type = /datum/skills/assault_crewman
+ access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC)
+ minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO)
+ display_order = JOB_DISPLAY_ORDER_MECH_PILOT
+ outfit = /datum/outfit/job/command/assault_crewman
+ exp_requirements = XP_REQ_EXPERT
+ exp_type = EXP_TYPE_REGULAR_ALL
+ job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP
+ job_points_needed = 999 //50
+ jobworth = list(
+ /datum/job/xenomorph = LARVA_POINTS_REGULAR,
+ /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
+ )
+ html_description = {"
+ Difficulty:Very Hard
+ You answer to the acting Command Staff
+ Unlock Requirement: Starting Role
+ Gamemode Availability: Nuclear War
+ Duty: Provide heavy fire support
+ "}
+ minimap_icon = "assault_crew"
+
+/datum/job/terragov/command/assault_crewman/add_job_points(amount)
+ . = ..()
+ if(total_positions % 2)
+ add_job_positions(1) //always 2 there are, a master and an apprentice
+
+/datum/job/terragov/command/assault_crewman/radio_help_message(mob/M)
+ . = ..()
+ to_chat(M, {"You are an Assault Crewman. You operate the TGMC's armored assault vehicles along with your partner, and in some cases a \"willing\" loader. Make sure that you work as a team to advance the front!"})
+
+/datum/job/terragov/command/assault_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE)
+ . = ..()
+ if(!ishuman(new_mob))
+ return
+ var/mob/living/carbon/human/new_human = new_mob
+ var/playtime_mins = user?.client?.get_exp(title)
+ if(!playtime_mins || playtime_mins < 1 )
+ return
+ switch(playtime_mins)
+ if(0 to 1500) // starting
+ new_human.wear_id.paygrade = "E3"
+ if(1501 to 6000) // 25 hrs
+ new_human.wear_id.paygrade = "E4"
+ if(6001 to 18000) // 100 hrs
+ new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
+ if(60001 to INFINITY) // 1000 hrs
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
+
+/datum/outfit/job/command/assault_crewman
+ name = ASSAULT_CREWMAN
+ jobtype = /datum/job/terragov/command/assault_crewman
+
+ id = /obj/item/card/id/dogtag
+ belt = /obj/item/storage/belt/utility/full
+ glasses = /obj/item/clothing/glasses/welding
+ ears = /obj/item/radio/headset/mainship/mcom
+ w_uniform = /obj/item/clothing/under/marine/officer/assault_crewman
+ wear_suit = /obj/item/clothing/suit/storage/marine/assault_crewman
+ head = /obj/item/clothing/head/helmet/marine/assault_crewman
+ shoes = /obj/item/clothing/shoes/marine/full
+ gloves = /obj/item/clothing/gloves/marine
+
+
+//apc/jeep driver
+/datum/job/terragov/command/transport_crewman
+ title = TRANSPORT_CREWMAN
+ req_admin_notify = TRUE
+ paygrade = "E3"
+ comm_title = "TC"
+ total_positions = 0
+ skills_type = /datum/skills/transport_crewman
+ access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC)
+ minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO)
+ display_order = JOB_DISPLAY_ORDER_MECH_PILOT
+ outfit = /datum/outfit/job/command/transport_crewman
+ exp_requirements = XP_REQ_EXPERT
+ exp_type = EXP_TYPE_REGULAR_ALL
+ job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP
+ job_points_needed = 40
+ jobworth = list(
+ /datum/job/xenomorph = LARVA_POINTS_REGULAR,
+ /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
+ )
+ html_description = {"
+ Difficulty:Very Hard
+ You answer to the acting Command Staff
+ Unlock Requirement: Starting Role
+ Gamemode Availability: Nuclear War
+ Duty: Transport and support the frontline troops
+ "}
+ minimap_icon = "transport_crew"
+
+/datum/job/terragov/command/transport_crewman/radio_help_message(mob/M)
+ . = ..()
+ to_chat(M, {"You are a Transport Crewman. You operate the TGMC's transport vehciles to ensure that marines and equipment gets to the front in a timely and safe manner."})
+
+/datum/job/terragov/command/transport_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE)
+ . = ..()
+ if(!ishuman(new_mob))
+ return
+ var/mob/living/carbon/human/new_human = new_mob
+ var/playtime_mins = user?.client?.get_exp(title)
+ if(!playtime_mins || playtime_mins < 1 )
+ return
+ switch(playtime_mins)
+ if(0 to 1500) // starting
+ new_human.wear_id.paygrade = "E3"
+ if(1501 to 6000) // 25 hrs
+ new_human.wear_id.paygrade = "E4"
+ if(6001 to 18000) // 100 hrs
+ new_human.wear_id.paygrade = "E5"
+ if(18001 to 60000) // 300 hrs
+ new_human.wear_id.paygrade = "E6"
+ if(60001 to INFINITY) // 1000 hrs
+ new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours.
+
+/datum/outfit/job/command/transport_crewman
+ name = TRANSPORT_CREWMAN
+ jobtype = /datum/job/terragov/command/transport_crewman
+
+ id = /obj/item/card/id/dogtag
+ belt = /obj/item/storage/belt/utility/full
+ glasses = /obj/item/clothing/glasses/welding
+ ears = /obj/item/radio/headset/mainship/mcom
+ w_uniform = /obj/item/clothing/under/marine/officer/transport_crewman
+ wear_suit = /obj/item/clothing/suit/storage/marine/transport_crewman
+ head = /obj/item/clothing/head/helmet/marine/transport_crewman
+ shoes = /obj/item/clothing/shoes/marine/full
+ gloves = /obj/item/clothing/gloves/marine
+
/datum/job/terragov/engineering
job_category = JOB_CAT_ENGINEERING
selection_color = "#fff5cc"
@@ -487,6 +686,7 @@ You can serve your Division in a variety of roles, so choose carefully."})
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Hard
@@ -561,6 +761,7 @@ You are also next in the chain of command, should the bridge crew fall in the li
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Medium
@@ -639,6 +840,7 @@ requisitions line and later on to be ready to send supplies for marines who are
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Medium
@@ -690,6 +892,10 @@ A happy ship is a well-functioning ship."})
head = /obj/item/clothing/head/tgmccap/req
r_store = /obj/item/storage/pouch/general/large
+/datum/outfit/job/requisitions/officer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ H.equip_to_slot_or_hand(new /obj/item/supplytablet, SLOT_IN_R_POUCH)
+
/datum/job/terragov/medical
job_category = JOB_CAT_MEDICAL
selection_color = "#BBFFBB"
@@ -722,6 +928,7 @@ A happy ship is a well-functioning ship."})
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Hard
@@ -806,6 +1013,7 @@ Make sure that the doctors and nurses are doing their jobs and keeping the marin
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Medium
@@ -892,6 +1100,7 @@ You are also an expert when it comes to medication and treatment. If you do not
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Medium
@@ -978,6 +1187,7 @@ It is also recommended that you gear up like a regular marine, or your 'internsh
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Hard (varies)
@@ -1052,6 +1262,7 @@ Use your office fax machine to communicate with corporate headquarters or to acq
/datum/job/xenomorph = LARVA_POINTS_SHIPSIDE_STRONG,
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Soul Crushing
@@ -1132,6 +1343,7 @@ In addition, being a Synthetic gives you knowledge in every field and specializa
/datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR,
/datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR,
/datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR,
+ /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR,
)
html_description = {"
Difficulty: Easy
diff --git a/code/datums/jobs/job/sons_of_mars_shipside.dm b/code/datums/jobs/job/sons_of_mars_shipside.dm
index e0145fab067a7..f20430dcb229e 100644
--- a/code/datums/jobs/job/sons_of_mars_shipside.dm
+++ b/code/datums/jobs/job/sons_of_mars_shipside.dm
@@ -49,12 +49,6 @@ Godspeed, commander! And remember, you are not above the law."})
jobtype = /datum/job/som/command/commander
id = /obj/item/card/id/gold
- belt = /obj/item/storage/holster/belt/pistol/m4a3/som/fancy/fieldcommander
- ears = /obj/item/radio/headset/mainship/som/command
- w_uniform = /obj/item/clothing/under/som/officer/senior
- shoes = /obj/item/clothing/shoes/marinechief/som
- gloves = /obj/item/clothing/gloves/marine/som/officer
- r_store = /obj/item/storage/pouch/general/large/som
/datum/outfit/job/som/command/commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
. = ..()
@@ -135,43 +129,6 @@ Make the SOM proud!"})
jobtype = /datum/job/som/command/fieldcommander
id = /obj/item/card/id/dogtag/fc
- belt = /obj/item/storage/holster/belt/pistol/m4a3/som/fancy/fieldcommander
- ears = /obj/item/radio/headset/mainship/som/command
- w_uniform = /obj/item/clothing/under/som/officer/webbing
- wear_suit = /obj/item/clothing/suit/modular/som/heavy/leader/officer
- shoes = /obj/item/clothing/shoes/marine/som/knife
- gloves = /obj/item/clothing/gloves/marine/som/officer
- mask = /obj/item/clothing/mask/gas
- head = /obj/item/clothing/head/modular/som/leader/officer
- glasses = /obj/item/clothing/glasses/hud/health
- r_store = /obj/item/storage/pouch/firstaid/som/combat_patrol_leader
- l_store = /obj/item/storage/pouch/grenade/som/combat_patrol
- suit_store = /obj/item/weapon/twohanded/fireaxe/som
- back = /obj/item/storage/backpack/satchel/som
-
-/datum/outfit/job/som/command/fieldcommander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- . = ..()
- H.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/russian_red, SLOT_IN_HEAD)
- H.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_HEAD)
-
- H.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_SUIT)
- H.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_SUIT)
- H.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/isotonic, SLOT_IN_SUIT)
- H.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclot, SLOT_IN_SUIT)
- H.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_SUIT)
-
- H.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
- H.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_BACKPACK)
-
- H.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
- H.equip_to_slot_or_del(new /obj/item/explosive/grenade/som, SLOT_IN_ACCESSORY)
- H.equip_to_slot_or_del(new /obj/item/storage/box/MRE/som, SLOT_IN_ACCESSORY)
- H.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/small, SLOT_IN_ACCESSORY)
- H.equip_to_slot_or_del(new /obj/item/binoculars/fire_support/campaign/som, SLOT_IN_ACCESSORY)
//Staff Officer
/datum/job/som/command/staffofficer
@@ -227,13 +184,6 @@ You are in charge of logistics and the overwatch system. You are also in line to
jobtype = /datum/job/som/command/staffofficer
id = /obj/item/card/id/silver
- belt = /obj/item/storage/holster/belt/pistol/m4a3/som/serpenta
- ears = /obj/item/radio/headset/mainship/som/command
- w_uniform = /obj/item/clothing/under/som/officer
- shoes = /obj/item/clothing/shoes/marinechief/som
- gloves = /obj/item/clothing/gloves/marine/som/officer
- r_store = /obj/item/storage/pouch/general/large/som
- l_store = /obj/item/binoculars/fire_support/campaign/som
//Pilot Officer
/datum/job/som/command/pilot
diff --git a/code/datums/jobs/job/special_forces.dm b/code/datums/jobs/job/special_forces.dm
index aeb95a49372ca..30ceb9899ad24 100644
--- a/code/datums/jobs/job/special_forces.dm
+++ b/code/datums/jobs/job/special_forces.dm
@@ -19,10 +19,10 @@
id = /obj/item/card/id/silver
belt = /obj/item/storage/belt/marine
ears = /obj/item/radio/headset/distress/dutch
- mask = /obj/item/clothing/mask/gas/swat
- w_uniform = /obj/item/clothing/under/syndicate/tacticool/holster
+ mask = /obj/item/clothing/mask/gas/specops
+ w_uniform = /obj/item/clothing/under/marine/specops
shoes = /obj/item/clothing/shoes/combat
- wear_suit = /obj/item/clothing/suit/armor/bulletproof
+ wear_suit = /obj/item/clothing/suit/storage/marine/specops
gloves = /obj/item/clothing/gloves/marine/veteran/pmc
head = /obj/item/clothing/head/modular/m10x
suit_store = /obj/item/weapon/gun/smg/m25/elite/suppressed
@@ -78,10 +78,10 @@
id = /obj/item/card/id/silver
belt = /obj/item/storage/belt/marine
ears = /obj/item/radio/headset/distress/dutch
- mask = /obj/item/clothing/mask/gas/swat
- w_uniform = /obj/item/clothing/under/syndicate/tacticool/holster
+ mask = /obj/item/clothing/mask/gas/specops
+ w_uniform = /obj/item/clothing/under/marine/specops
shoes = /obj/item/clothing/shoes/combat
- wear_suit = /obj/item/clothing/suit/armor/bulletproof
+ wear_suit = /obj/item/clothing/suit/storage/marine/specops/support
gloves = /obj/item/clothing/gloves/marine/veteran/pmc
head = /obj/item/clothing/head/modular/m10x
suit_store = /obj/item/weapon/gun/smg/m25/elite/suppressed/breacher
@@ -133,10 +133,10 @@
id = /obj/item/card/id/silver
belt = /obj/item/storage/belt/marine
ears = /obj/item/radio/headset/distress/dutch
- mask = /obj/item/clothing/mask/gas/swat
- w_uniform = /obj/item/clothing/under/syndicate/tacticool/holster
+ mask = /obj/item/clothing/mask/gas/specops
+ w_uniform = /obj/item/clothing/under/marine/specops
shoes = /obj/item/clothing/shoes/combat
- wear_suit = /obj/item/clothing/suit/armor/bulletproof
+ wear_suit = /obj/item/clothing/suit/storage/marine/specops/support
gloves = /obj/item/clothing/gloves/marine/veteran/pmc
head = /obj/item/clothing/head/modular/m10x/welding
suit_store = /obj/item/weapon/gun/smg/m25/elite/suppressed
@@ -179,6 +179,51 @@
H.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_R_POUCH)
H.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_R_POUCH)
+//Special forces Medic
+/datum/job/special_forces/medic
+ title = "Special Response Force Medic"
+ outfit = /datum/outfit/job/special_forces/medic
+ skills_type = /datum/skills/combat_medic/special_forces
+/datum/outfit/job/special_forces/medic
+ name = "Special Response Force Medic"
+ jobtype = /datum/job/special_forces/medic
+
+ glasses = /obj/item/clothing/glasses/night
+ id = /obj/item/card/id/silver
+ ears = /obj/item/radio/headset/distress/dutch
+ w_uniform = /obj/item/clothing/under/marine/specops
+ belt = /obj/item/storage/belt/lifesaver/full
+ wear_suit = /obj/item/clothing/suit/storage/marine/specops/medic
+ head = /obj/item/clothing/head/modular/m10x
+ shoes = /obj/item/clothing/shoes/combat
+ gloves = /obj/item/clothing/gloves/marine/veteran/pmc
+ glasses = /obj/item/clothing/glasses/hud/health
+ suit_store = /obj/item/weapon/gun/smg/m25/elite/suppressed
+ r_store = /obj/item/storage/pouch/medical_injectors/medic
+ l_store = /obj/item/storage/pouch/magazine/large
+ back = /obj/item/storage/backpack/lightpack
+
+
+/datum/outfit/job/special_forces/medic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+
+ H.equip_to_slot_or_del(new /obj/item/clothing/glasses/mgoggles, SLOT_IN_HEAD)
+
+ H.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_BACKPACK)
+ H.equip_to_slot_or_del(new /obj/item/healthanalyzer, SLOT_IN_BACKPACK)
+ H.equip_to_slot_or_del(new /obj/item/roller, SLOT_IN_BACKPACK)
+ H.equip_to_slot_or_del(new /obj/item/tweezers, SLOT_IN_BACKPACK)
+ H.equip_to_slot_or_del(new /obj/item/tool/crowbar, SLOT_IN_BACKPACK)
+
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/g22, SLOT_IN_ACCESSORY)
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/g22, SLOT_IN_ACCESSORY)
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/g22, SLOT_IN_ACCESSORY)
+ H.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/g22(H), SLOT_IN_ACCESSORY)
+
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/ap, SLOT_IN_L_POUCH)
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/ap, SLOT_IN_L_POUCH)
+ H.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/m25/ap, SLOT_IN_L_POUCH)
+
//Special forces Leader
/datum/job/special_forces/leader
title = "Special Response Force Leader"
@@ -193,11 +238,11 @@
id = /obj/item/card/id/silver
belt = /obj/item/storage/belt/marine
ears = /obj/item/radio/headset/distress/dutch
- mask = /obj/item/clothing/mask/gas/swat
- w_uniform = /obj/item/clothing/under/syndicate/tacticool/holster
+ mask = /obj/item/clothing/mask/gas/specops
+ w_uniform = /obj/item/clothing/under/marine/specops
glasses = /obj/item/clothing/glasses/night
shoes = /obj/item/clothing/shoes/combat
- wear_suit = /obj/item/clothing/suit/armor/bulletproof
+ wear_suit = /obj/item/clothing/suit/storage/marine/specops/leader
gloves = /obj/item/clothing/gloves/marine/veteran/pmc
head = /obj/item/clothing/head/beret/sec
suit_store = /obj/item/weapon/gun/rifle/m16/spec_op
diff --git a/code/datums/jobs/job/terragov.dm b/code/datums/jobs/job/terragov.dm
index 57b1e7326d4cd..787a27bb8cda2 100644
--- a/code/datums/jobs/job/terragov.dm
+++ b/code/datums/jobs/job/terragov.dm
@@ -16,7 +16,7 @@
/datum/job/terragov/return_spawn_type(datum/preferences/prefs)
switch(prefs?.species)
if("Combat Robot")
- if(!(SSticker.mode?.flags_round_type & MODE_HUMAN_ONLY))
+ if(!(SSticker.mode?.round_type_flags & MODE_HUMAN_ONLY))
switch(prefs?.robot_type)
if("Basic")
return /mob/living/carbon/human/species/robot
diff --git a/code/datums/jobs/job/xenomorph.dm b/code/datums/jobs/job/xenomorph.dm
index fc911cd953246..017b58ae89389 100644
--- a/code/datums/jobs/job/xenomorph.dm
+++ b/code/datums/jobs/job/xenomorph.dm
@@ -41,7 +41,7 @@
return TRUE
/datum/job/xenomorph/add_job_positions(amount)
- if(!(SSticker.mode.flags_round_type & MODE_XENO_SPAWN_PROTECT))
+ if(!(SSticker.mode.round_type_flags & MODE_XENO_SPAWN_PROTECT))
if(free_xeno_at_start > 0)
free_xeno_at_start--
return
diff --git a/code/datums/jobs/squads.dm b/code/datums/jobs/squads.dm
index dec013864a24b..b61225e7a5e9f 100644
--- a/code/datums/jobs/squads.dm
+++ b/code/datums/jobs/squads.dm
@@ -298,7 +298,7 @@
R.use_command = FALSE
var/obj/item/card/id/ID = squad_leader.get_idcard()
if(istype(ID))
- ID.access -= list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP)
+ ID.access -= list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE)
to_chat(squad_leader, "You're no longer the Squad Leader for [src]!")
var/mob/living/carbon/human/H = squad_leader
@@ -323,7 +323,7 @@
squad_leader.comm_title = "aSL"
var/obj/item/card/id/ID = squad_leader.get_idcard()
if(istype(ID))
- ID.access += list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP)
+ ID.access += list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE)
if(istype(squad_leader.wear_ear, /obj/item/radio/headset/mainship/marine))
var/obj/item/radio/headset/mainship/marine/R = squad_leader.wear_ear
@@ -421,8 +421,8 @@ GLOBAL_LIST_EMPTY_TYPED(custom_squad_radio_freqs, /datum/squad)
var/freq = FREQ_CUSTOM_SQUAD_MIN + 2 * length(GLOB.custom_squad_radio_freqs)
if(freq > FREQ_CUSTOM_SQUAD_MAX)
return
-
- var/new_id = lowertext(squad_name) + "_squad"
+ var/lowertext_name = lowertext(squad_name)
+ var/new_id = lowertext_name + "_squad"
if(SSjob.squads[new_id])
return
@@ -436,6 +436,21 @@ GLOBAL_LIST_EMPTY_TYPED(custom_squad_radio_freqs, /datum/squad)
LAZYADDASSOCSIMPLE(GLOB.radiochannels, "[radio_channel_name]", freq)
LAZYADDASSOCSIMPLE(GLOB.reverseradiochannels, "[freq]", radio_channel_name)
new_squad.faction = squad_faction
+ var/key_prefix = lowertext_name[1]
+ if(GLOB.department_radio_keys[key_prefix])
+ for(var/letter in splittext(lowertext_name, ""))
+ if(!GLOB.department_radio_keys[letter])
+ key_prefix = letter
+ break
+ //okay... mustve been a very short name, randomly pick things from the alphabet now
+ for(var/letter in shuffle(GLOB.alphabet))
+ if(!GLOB.department_radio_keys[letter])
+ key_prefix = letter
+ break
+ key_prefix = "ERROR"
+ GLOB.department_radio_keys[key_prefix] = radio_channel_name
+ GLOB.channel_tokens[radio_channel_name] = ":[key_prefix]"
+
if(new_squad.faction == FACTION_TERRAGOV)
var/list/terragov_server_freqs = GLOB.telecomms_freq_listening_list[/obj/machinery/telecomms/server/presets/alpha]
var/list/terragov_bus_freqs = GLOB.telecomms_freq_listening_list[/obj/machinery/telecomms/bus/preset_three]
diff --git a/code/datums/keybinding/admin.dm b/code/datums/keybinding/admin.dm
index 64e05d7f453ec..e44901b091bed 100644
--- a/code/datums/keybinding/admin.dm
+++ b/code/datums/keybinding/admin.dm
@@ -44,3 +44,17 @@
return
user.get_togglebuildmode()
return TRUE
+
+/datum/keybinding/admin/view_tags
+ hotkey_keys = list("F9")
+ name = "view_tags"
+ full_name = "View Tags"
+ description = "Open the View-Tags menu"
+ keybind_signal = COMSIG_KB_ADMIN_VIEWTAGS_DOWN
+
+/datum/keybinding/admin/view_tags/down(client/user)
+ . = ..()
+ if(.)
+ return
+ user.holder?.display_tags()
+ return TRUE
diff --git a/code/datums/keybinding/carbon.dm b/code/datums/keybinding/carbon.dm
index a7252c331e3b5..474aebe916595 100644
--- a/code/datums/keybinding/carbon.dm
+++ b/code/datums/keybinding/carbon.dm
@@ -55,7 +55,7 @@
if(.)
return
var/mob/living/carbon/C = user.mob
- C.lay_down()
+ C.toggle_resting()
return TRUE
/datum/keybinding/carbon/select_help_intent
@@ -116,32 +116,3 @@
return
user.mob?.a_intent_change(INTENT_HARM)
return TRUE
-
-/datum/keybinding/carbon/specialclick
- hotkey_keys = list("Ctrl")
- name = "specialclick"
- full_name = "Special Click"
- description = "Hold this hotkey_keys and click to trigger special object interactions."
- keybind_signal = COMSIG_KB_CARBON_SPECIALCLICK_DOWN
-
-
-/datum/keybinding/carbon/specialclick/down(client/user)
- . = ..()
- if(.)
- return
- RegisterSignals(user.mob, list(COMSIG_MOB_CLICKON), PROC_REF(specialclicky))
- RegisterSignals(user.mob, list(COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEUP), TYPE_PROC_REF(/datum/keybinding, intercept_mouse_special))
- return TRUE
-
-
-/datum/keybinding/carbon/specialclick/up(client/user)
- UnregisterSignal(user.mob, list(COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEUP, COMSIG_MOB_CLICKON))
- return TRUE
-
-/datum/keybinding/carbon/specialclick/proc/specialclicky(datum/source, atom/A, params)
- SIGNAL_HANDLER
- var/mob/living/carbon/user = source
- if(!user.client || !(user.client.eye == user || user.client.eye == user.loc))
- UnregisterSignal(user, (COMSIG_MOB_CLICKON))
- return
- A.specialclick(user)
diff --git a/code/datums/keybinding/human.dm b/code/datums/keybinding/human.dm
index e2e7d0bfe02a1..2ec9c4f109bec 100644
--- a/code/datums/keybinding/human.dm
+++ b/code/datums/keybinding/human.dm
@@ -36,7 +36,7 @@
quick_equip_slot = 5
/datum/keybinding/human/unique_action
- hotkey_keys = list("Space")
+ hotkey_keys = list("C")
name = "unique_action"
full_name = "Perform unique action"
keybind_signal = COMSIG_KB_UNIQUEACTION
diff --git a/code/datums/keybinding/item_toggles.dm b/code/datums/keybinding/item_toggles.dm
new file mode 100644
index 0000000000000..0fbbe17c03d29
--- /dev/null
+++ b/code/datums/keybinding/item_toggles.dm
@@ -0,0 +1,17 @@
+/datum/keybinding/item
+ category = CATEGORY_ITEM
+ weight = WEIGHT_MOB
+
+/datum/keybinding/item/jetpack
+ name = "Jetpack"
+ full_name = "Toggle jetpack"
+ description = "Toggles your jetpack on, allowing you to fly a short distance."
+ keybind_signal = COMSIG_ITEM_TOGGLE_JETPACK
+ hotkey_keys = list("G")
+
+/datum/keybinding/item/blinkdrive
+ name = "Blink drive"
+ full_name = "Toggle blink drive"
+ description = "Toggles your blink drive on, allowing you to instantly teleport short distances."
+ keybind_signal = COMSIG_ITEM_TOGGLE_BLINKDRIVE
+ hotkey_keys = list("G")
diff --git a/code/datums/keybinding/mecha.dm b/code/datums/keybinding/mecha.dm
index 566b70d8ca4f7..6f4d765dd1357 100644
--- a/code/datums/keybinding/mecha.dm
+++ b/code/datums/keybinding/mecha.dm
@@ -50,3 +50,16 @@
description = "Bombard an area with rockets"
keybind_signal = COMSIG_MECHABILITY_STRIKE
hotkey_keys = list("F")
+
+/datum/keybinding/mecha/mech_reload_weapons
+ name = "mech_reload_weapons"
+ full_name = "Mech Reload Weapons"
+ description = "Reload any equipped weapons"
+ keybind_signal = COMSIG_MECHABILITY_RELOAD
+ hotkey_keys = list("R")
+/datum/keybinding/mecha/mech_toggle_actuators
+ name = "mech_toggle_actuators"
+ full_name = "Mecha Toggle Actuators"
+ description = "Toggle leg actuator overload for your mecha"
+ keybind_signal = COMSIG_MECHABILITY_TOGGLE_ACTUATORS
+ hotkey_keys = list("X")
diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm
index d5719bfc50267..282b398ef387a 100644
--- a/code/datums/keybinding/mob.dm
+++ b/code/datums/keybinding/mob.dm
@@ -176,35 +176,6 @@
return TRUE
*/
-
-/datum/keybinding/mob/examine
- hotkey_keys = list("Shift")
- name = "examine_kb"
- full_name = "Examine"
- description = "Hold this hotkey_keys and click to examine things."
- keybind_signal = COMSIG_KB_MOB_EXAMINE_DOWN
-
-
-/datum/keybinding/mob/examine/down(client/user)
- . = ..()
- if(.)
- return
- RegisterSignals(user.mob, list(COMSIG_MOB_CLICKON, COMSIG_OBSERVER_CLICKON), PROC_REF(examinate))
- RegisterSignals(user.mob, list(COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEUP), TYPE_PROC_REF(/datum/keybinding, intercept_mouse_special))
- return TRUE
-
-
-/datum/keybinding/mob/examine/up(client/user)
- UnregisterSignal(user.mob, list(COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEUP, COMSIG_MOB_CLICKON, COMSIG_OBSERVER_CLICKON))
- return TRUE
-
-
-/datum/keybinding/mob/examine/proc/examinate(datum/source, atom/A, params)
- SIGNAL_HANDLER
- var/mob/user = source
- user.examinate(A)
- return COMSIG_MOB_CLICK_HANDLED
-
/datum/keybinding/mob/toggle_move_intent
hotkey_keys = list("5")
name = "toggle_move_intent"
@@ -343,3 +314,32 @@
return
user.mob.do_self_harm = !user.mob.do_self_harm
user.mob.balloon_alert(user.mob, "You can [user.mob.do_self_harm ? "now" : "no longer"] hit yourself")
+
+/datum/keybinding/mob/interactive_emote
+ name = "interactive_emote"
+ full_name = "Do interactive emote"
+ description = "Perform an interactive emote with another player."
+ keybind_signal = COMSIG_KB_INTERACTIVE_EMOTE
+
+/datum/keybinding/mob/interactive_emote/down(client/user)
+ . = ..()
+ if(. || !isliving(user.mob) || CHECK_BITFIELD(user.mob.status_flags, INCORPOREAL) || !user.mob.can_interact(user.mob))
+ return
+
+ var/list/adjacent_mobs = cheap_get_living_near(user.mob, 1)
+ adjacent_mobs.Remove(user.mob) //Get rid of self
+ for(var/mob/M AS in adjacent_mobs)
+ if(!M.client)
+ adjacent_mobs.Remove(M) //Get rid of non-players
+
+ if(!length(adjacent_mobs))
+ return
+
+ if(length(adjacent_mobs) == 1)
+ user.mob.interaction_emote(adjacent_mobs[1])
+ return
+
+ var/mob/target = tgui_input_list(user, "Who do you want to interact with?", "Select a target", adjacent_mobs)
+ if(!target || !user.mob.Adjacent(target)) //In case the target moved away while selecting them
+ return
+ user.mob.interaction_emote(target)
diff --git a/code/datums/keybinding/sectoid.dm b/code/datums/keybinding/sectoid.dm
new file mode 100644
index 0000000000000..f3a4195e651ef
--- /dev/null
+++ b/code/datums/keybinding/sectoid.dm
@@ -0,0 +1,52 @@
+/datum/keybinding/sectoid
+ category = CATEGORY_PSIONIC
+ weight = WEIGHT_MOB
+
+/datum/keybinding/sectoid/mindmeld
+ name = "Mindmeld"
+ full_name = "Sectoid: Mindmeld"
+ description = "We merge minds with another of our kind, strengthening us both."
+ keybind_signal = COMSIG_ABILITY_MINDMELD
+ hotkey_keys = list("U")
+
+/datum/keybinding/sectoid/mindfray
+ name = "Mindfray"
+ full_name = "Sectoid: Mindfray"
+ description = "We attack the mind of our foe, greatly weakening them for a time."
+ keybind_signal = COMSIG_ABILITY_MINDFRAY
+ hotkey_keys = list("Q")
+
+/datum/keybinding/sectoid/reknit_form
+ name = "Reknit form"
+ full_name = "Sectoid: Reknit form"
+ description = "Flesh and bone runs like water at our will, healing horrendous damage with the power of our mind."
+ keybind_signal = COMSIG_ABILITY_REKNIT_FORM
+ hotkey_keys = list("F")
+
+/datum/keybinding/sectoid/fuse
+ name = "Fuse"
+ full_name = "Sectoid: Fuse"
+ description = "We reach out with our mind to trigger an explosive device."
+ keybind_signal = COMSIG_ABILITY_FUSE
+ hotkey_keys = list("R")
+
+/datum/keybinding/sectoid/stasis
+ name = "Stasis"
+ full_name = "Sectoid: Stasis"
+ description = "We surround a living thing with a powerful psionic field, temporarily disabling them and protecting them from all harm."
+ keybind_signal = COMSIG_ABILITY_STASIS
+ hotkey_keys = list("H")
+
+/datum/keybinding/sectoid/telekinesis
+ name = "Telekinesis"
+ full_name = "Sectoid: Telekinesis"
+ description = "We manipulate things from a distance."
+ keybind_signal = COMSIG_ABILITY_TELEKINESIS
+ hotkey_keys = list("G")
+
+/datum/keybinding/sectoid/reanimate
+ name = "Reanimate"
+ full_name = "Sectoid: Reanimate"
+ description = "With our psionic strength we turn the dead into our puppet, or revive a fallen ally."
+ keybind_signal = COMSIG_ABILITY_REANIMATE
+ hotkey_keys = list("B")
diff --git a/code/datums/keybinding/weapons.dm b/code/datums/keybinding/weapons.dm
new file mode 100644
index 0000000000000..5a5077bf42e57
--- /dev/null
+++ b/code/datums/keybinding/weapons.dm
@@ -0,0 +1,17 @@
+/datum/keybinding/weapon
+ category = CATEGORY_WEAPON
+ weight = WEIGHT_MOB
+
+/datum/keybinding/weapon/axe_sweep
+ name = "Axe sweep"
+ full_name = "Breaching axe: Axe sweep"
+ description = "A powerful sweeping blow that hits foes in the direction you are facing. Cannot stun."
+ keybind_signal = COMSIG_WEAPONABILITY_AXESWEEP
+ hotkey_keys = list("G")
+
+/datum/keybinding/weapon/sword_lunge
+ name = "Lunging strike"
+ full_name = "Sword: Lunging strike"
+ description = "Dash a short distance to inflict a staggering blow on an opponent. Cannot stun."
+ keybind_signal = COMSIG_WEAPONABILITY_SWORDLUNGE
+ hotkey_keys = list("G")
diff --git a/code/datums/keybinding/xeno.dm b/code/datums/keybinding/xeno.dm
index 249a171555408..9a2418d492bf1 100644
--- a/code/datums/keybinding/xeno.dm
+++ b/code/datums/keybinding/xeno.dm
@@ -47,6 +47,13 @@
keybind_signal = COMSIG_XENOABILITY_SECRETE_RESIN
hotkey_keys = list("R")
+/datum/keybinding/xeno/secrete_special_resin
+ name = "secrete_special_resin"
+ full name = "Secrete Special Resin"
+ description = "Builds whatever special resin you have selected."
+ keybind_signal = COMSIG_XENOABILITY_SECRETE_SPECIAL_RESIN
+ hotkey_keys = list("ShiftR")
+
/datum/keybinding/xeno/recycle
name = "Recycle"
full_name = "Recycle xenomorph"
@@ -103,6 +110,13 @@
keybind_signal = COMSIG_XENOABILITY_XENO_SPIT
hotkey_keys = list("Q")
+/datum/keybinding/xeno/long_range_sight
+ name = "long_range_sight"
+ full_name = "Long Range Sight"
+ description = "Toggles the zoom in."
+ keybind_signal = COMSIG_XENOABILITY_LONG_RANGE_SIGHT
+ hotkey_keys = list("E")
+
/datum/keybinding/xeno/xenohide
name = "xenohide"
full_name = "Hide"
@@ -225,13 +239,6 @@
keybind_signal = COMSIG_XENOABILITY_CREATE_BOMB
hotkey_keys = list("F")
-/datum/keybinding/xeno/root
- name = "root"
- full_name = "Boiler: Root in place"
- description = "Begin rooting in place."
- keybind_signal = COMSIG_XENOABILITY_ROOT
- hotkey_keys = list("C")
-
/datum/keybinding/xeno/bombard
name = "bombard"
full_name = "Boiler: Bombard"
@@ -251,7 +258,7 @@
full_name = "Bull: Headbutt Charge"
description = "A charge that tosses the victim forward."
keybind_signal = COMSIG_XENOABILITY_BULLHEADBUTT
- hotkey_keys = list("E")
+ hotkey_keys = list("F")
/datum/keybinding/xeno/gore_charge
name = "gore_charge"
@@ -481,11 +488,11 @@
keybind_signal = COMSIG_XENOABILITY_TRANSFUSION
hotkey_keys = list("H")
-/datum/keybinding/xeno/rejuvenate
- name = "rejuvenate"
- full_name = "Gorger: Rejuvenate"
- description = "Drains blood continuosly, slows you down and reduces damage taken, while restoring some health over time. Cancel by activating again."
- keybind_signal = COMSIG_XENOABILITY_REJUVENATE
+/datum/keybinding/xeno/oppose
+ name = "oppose"
+ full_name = "Gorger: Oppose"
+ description = "Violently suffuse the nearby ground with stored blood, staggering nearby marines and healing nearby xenomorphs."
+ keybind_signal = COMSIG_XENOABILITY_OPPOSE
hotkey_keys = list("R")
/datum/keybinding/xeno/psychic_link
diff --git a/code/datums/loadout/item_representation/armor_representation.dm b/code/datums/loadout/item_representation/armor_representation.dm
index 5eb07acab1a95..6a0440b01a951 100644
--- a/code/datums/loadout/item_representation/armor_representation.dm
+++ b/code/datums/loadout/item_representation/armor_representation.dm
@@ -173,6 +173,8 @@
if(!.)
return
var/obj/item/armor_module/module = .
+ if(colors && CHECK_BITFIELD(module.attach_features_flags, ATTACH_GREYSCALE_PARENT_COPY))
+ module.set_greyscale_colors(colors)
for(var/datum/item_representation/armor_module/armor_attachement AS in attachments)
armor_attachement.install_on_armor(seller, module, user)
@@ -182,7 +184,7 @@
//if(!item_type)
// return
var/obj/item/armor_module/module_type = item_type
- if(!CHECK_BITFIELD(initial(module_type.flags_attach_features), ATTACH_REMOVABLE))
+ if(!CHECK_BITFIELD(initial(module_type.attach_features_flags), ATTACH_REMOVABLE))
bypass_vendor_check = TRUE
var/obj/item/armor_module/module = instantiate_object(seller, null, user)
if(!module)
diff --git a/code/datums/loadout/loadout.dm b/code/datums/loadout/loadout.dm
index a5954cd48c7dd..89f3570107461 100644
--- a/code/datums/loadout/loadout.dm
+++ b/code/datums/loadout/loadout.dm
@@ -21,40 +21,40 @@
///Check if the item can go to the specified slot
/datum/loadout/proc/can_equip_to_slot(item_type, slot)
var/obj/item/item = item_type
- var/flags_equip_slot = initial(item.flags_equip_slot)
+ var/equip_slot_flags = initial(item.equip_slot_flags)
var/w_class = initial(item.w_class)
switch(slot)
if(slot_wear_mask_str)
- return (flags_equip_slot & ITEM_SLOT_MASK)
+ return (equip_slot_flags & ITEM_SLOT_MASK)
if(slot_back_str)
- return (flags_equip_slot & ITEM_SLOT_BACK)
+ return (equip_slot_flags & ITEM_SLOT_BACK)
if(slot_wear_suit_str)
- return (flags_equip_slot & ITEM_SLOT_OCLOTHING)
+ return (equip_slot_flags & ITEM_SLOT_OCLOTHING)
if(slot_gloves_str)
- return (flags_equip_slot & ITEM_SLOT_GLOVES)
+ return (equip_slot_flags & ITEM_SLOT_GLOVES)
if(slot_shoes_str)
- return (flags_equip_slot & ITEM_SLOT_FEET)
+ return (equip_slot_flags & ITEM_SLOT_FEET)
if(slot_belt_str)
- if(!(flags_equip_slot & ITEM_SLOT_BELT))
+ if(!(equip_slot_flags & ITEM_SLOT_BELT))
return FALSE
if(!item_list[SLOT_W_UNIFORM])
return FALSE
return TRUE
if(slot_glasses_str)
- return (flags_equip_slot & ITEM_SLOT_EYES)
+ return (equip_slot_flags & ITEM_SLOT_EYES)
if(slot_head_str)
- return (flags_equip_slot & ITEM_SLOT_HEAD)
+ return (equip_slot_flags & ITEM_SLOT_HEAD)
if(slot_w_uniform_str)
- return (flags_equip_slot & ITEM_SLOT_ICLOTHING)
+ return (equip_slot_flags & ITEM_SLOT_ICLOTHING)
if(slot_l_store_str)
if(!item_list[SLOT_W_UNIFORM])
return FALSE
- if(w_class <= 2 || (flags_equip_slot & ITEM_SLOT_POCKET))
+ if(w_class <= 2 || (equip_slot_flags & ITEM_SLOT_POCKET))
return TRUE
if(slot_r_store_str)
if(!item_list[SLOT_W_UNIFORM])
return FALSE
- if(w_class <= 2 || (flags_equip_slot & ITEM_SLOT_POCKET))
+ if(w_class <= 2 || (equip_slot_flags & ITEM_SLOT_POCKET))
return TRUE
if(slot_s_store_str)
if(!item_list[SLOT_W_UNIFORM])
@@ -66,9 +66,9 @@
return TRUE
return FALSE
if(slot_ear_str)
- return (flags_equip_slot & ITEM_SLOT_EARS)
+ return (equip_slot_flags & ITEM_SLOT_EARS)
if(slot_wear_id_str)
- return (flags_equip_slot & ITEM_SLOT_ID)
+ return (equip_slot_flags & ITEM_SLOT_ID)
if(slot_r_hand_str)
return TRUE
if(slot_l_hand_str)
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
old mode 100644
new mode 100755
index 7c0838e9b4014..8de9dbe882d02
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -24,6 +24,13 @@
range = 8
falloff = 1
+/datum/looping_sound/flickeringambient
+ mid_sounds = list('sound/effects/lightbuzzloop6.ogg' = 1)
+ mid_length = 5 SECONDS
+ volume = 50
+ range = 6
+ falloff = 2
+
/datum/looping_sound/geiger
mid_sounds = list(
list('sound/effects/geiger/low1.ogg'=1, 'sound/effects/geiger/low2.ogg'=1, 'sound/effects/geiger/low3.ogg'=1, 'sound/effects/geiger/low4.ogg'=1),
diff --git a/code/datums/marine_main_ship.dm b/code/datums/marine_main_ship.dm
index 06749955ab862..dff77022f389c 100644
--- a/code/datums/marine_main_ship.dm
+++ b/code/datums/marine_main_ship.dm
@@ -14,11 +14,11 @@ GLOBAL_DATUM_INIT(marine_main_ship, /datum/marine_main_ship, new)
/datum/marine_main_ship/proc/make_maint_all_access()
maint_all_access = TRUE
- priority_announce("The maintenance access requirement has been revoked on all airlocks.", "Attention!", sound = 'sound/misc/notice1.ogg')
+ priority_announce("The maintenance access requirement has been revoked on all airlocks.", "Attention!", "Shipside emergency declared.", sound = 'sound/misc/notice1.ogg', color_override = "grey")
/datum/marine_main_ship/proc/revoke_maint_all_access()
maint_all_access = FALSE
- priority_announce("The maintenance access requirement has been readded on all maintenance airlocks.", "Attention!", sound = 'sound/misc/notice2.ogg')
+ priority_announce("The maintenance access requirement has been readded on all maintenance airlocks.", "Attention!", "Shipside emergency revoked.", sound = 'sound/misc/notice2.ogg', color_override = "grey")
/datum/marine_main_ship/proc/set_security_level(level, announce = TRUE)
switch(level)
@@ -79,7 +79,7 @@ GLOBAL_DATUM_INIT(marine_main_ship, /datum/marine_main_ship, new)
switch(level)
if(SEC_LEVEL_GREEN)
if(announce)
- priority_announce("Attention: Security level lowered to GREEN - all clear.", "Priority Alert", sound = 'sound/AI/code_green.ogg')
+ priority_announce("Attention: Security level lowered to GREEN - all clear.", title = "Security Level Lowered", subtitle = "All Clear", sound = 'sound/AI/code_green.ogg', color_override = "green")
security_level = SEC_LEVEL_GREEN
for(var/obj/machinery/status_display/SD in GLOB.machines)
if(is_mainship_level(SD.z))
@@ -87,10 +87,10 @@ GLOBAL_DATUM_INIT(marine_main_ship, /datum/marine_main_ship, new)
if(SEC_LEVEL_BLUE)
if(security_level < SEC_LEVEL_BLUE)
if(announce)
- priority_announce("Attention: Security level elevated to BLUE - potentially hostile activity on board.", "Priority Alert", sound = 'sound/AI/code_blue_elevated.ogg')
+ priority_announce("Attention: Security level elevated to BLUE - potentially hostile activity on board.", title = "Security Level Elevated", sound = 'sound/AI/code_blue_elevated.ogg')
else
if(announce)
- priority_announce("Attention: Security level lowered to BLUE - potentially hostile activity on board.", "Priority Alert", sound = 'sound/AI/code_blue_lowered.ogg')
+ priority_announce("Attention: Security level lowered to BLUE - potentially hostile activity on board.", title = "Security Level Lowered", sound = 'sound/AI/code_blue_lowered.ogg')
security_level = SEC_LEVEL_BLUE
for(var/obj/machinery/status_display/SD in GLOB.machines)
if(is_mainship_level(SD.z))
@@ -98,10 +98,10 @@ GLOBAL_DATUM_INIT(marine_main_ship, /datum/marine_main_ship, new)
if(SEC_LEVEL_RED)
if(security_level < SEC_LEVEL_RED)
if(announce)
- priority_announce("Attention: Security level elevated to RED - there is an immediate threat to the ship.", "Priority Alert", sound = 'sound/AI/code_red_elevated.ogg')
+ priority_announce("Attention: Security level elevated to RED - there is an immediate threat to the ship.", title = "Security Level Elevated", sound = 'sound/AI/code_red_elevated.ogg', color_override = "red")
else
if(announce)
- priority_announce("Attention: Security level lowered to RED - there is an immediate threat to the ship.", "Priority Alert", sound = 'sound/AI/code_red_lowered.ogg')
+ priority_announce("Attention: Security level lowered to RED - there is an immediate threat to the ship.", title = "Ship Destruction Averted", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/code_red_lowered.ogg', color_override = "red")
/*
var/area/A
for(var/obj/machinery/power/apc/O in machines)
@@ -117,7 +117,7 @@ GLOBAL_DATUM_INIT(marine_main_ship, /datum/marine_main_ship, new)
SD.set_picture("redalert")
if(SEC_LEVEL_DELTA)
if(announce)
- priority_announce("Attention! Delta security level reached! " + CONFIG_GET(string/alert_delta), "Priority Alert")
+ priority_announce("Attention! Delta security level reached! " + CONFIG_GET(string/alert_delta), title = "Ship Destruction Imminent", type = ANNOUNCEMENT_PRIORITY, color_override = "purple")
security_level = SEC_LEVEL_DELTA
for(var/obj/machinery/door/poddoor/shutters/mainship/D in GLOB.machines)
if(D.id == "sd_lockdown")
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 192f03f281a56..de78fee190302 100644
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -246,3 +246,19 @@
id = human_mob.wear_id?.type
l_store = human_mob.l_store?.type
r_store = human_mob.r_store?.type
+
+/datum/outfit/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_TO_OUTFIT_EDITOR, "Outfit Editor")
+
+/datum/outfit/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_TO_OUTFIT_EDITOR])
+ if(!check_rights(NONE))
+ return
+ usr.client.open_outfit_editor(src)
diff --git a/code/datums/personal_statistics.dm b/code/datums/personal_statistics.dm
index 88f9bead146ef..e34ad294eaba7 100644
--- a/code/datums/personal_statistics.dm
+++ b/code/datums/personal_statistics.dm
@@ -38,6 +38,8 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
var/projectile_damage = 0
var/melee_damage = 0
+ var/mechs_destroyed = 0
+
//We are watching
var/friendly_fire_damage = 0
@@ -62,6 +64,7 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
var/times_revived = 0
var/deaths = 0
+ var/shrapnel_removed = 0
//Downtime
var/time_resting = 0
@@ -105,6 +108,26 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
var/war_crimes = 0
var/tactical_unalives = 0 //Someone should add a way to determine if you died to a grenade in your hand and add it to this
+ //campaign specific vars
+ var/mission_projectile_damage = 0
+ var/mission_friendly_fire_damage = 0
+ var/mission_melee_damage = 0
+ var/mission_revives = 0
+ var/mission_times_revived = 0
+ var/mission_structures_built = 0
+ var/mission_objective_destroyed = 0
+ var/mission_blocker_destroyed = 0
+ var/mission_objective_captured = 0
+ var/mission_objective_decaptured = 0
+ var/mission_mechs_destroyed = 0
+ var/mission_shrapnel_removed = 0
+ var/mission_traps_created = 0
+ var/mission_grenades_primed = 0
+
+/datum/personal_statistics/New()
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_MISSION_STARTED, PROC_REF(reset_mission_stats))
+
///Calculated from the chemicals_ingested list, returns a string: "[chemical name], [amount] units"
/datum/personal_statistics/proc/get_most_ingested_chemical()
var/list/winner = list("none", 0)
@@ -153,6 +176,9 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
if(internal_injuries_inflicted)
stats += "Inflicted [internal_injuries_inflicted] internal injur[internal_injuries_inflicted > 1 ? "ies" : "y"] on [internal_injuries_inflicted > 1 ? "others" : "somebody"]."
+ if(mechs_destroyed)
+ stats += "[mechs_destroyed] hostile mechs destroyed."
+
//Medical
stats += ""
if(self_heals)
@@ -166,6 +192,8 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
if(times_revived)
stats += "You were revived [times_revived] time\s."
stats += deaths ? "You died [deaths] time\s." : "You survived the whole round."
+ if(shrapnel_removed)
+ stats += "Removed [shrapnel_removed] piece\s of shrapnel."
//Downtime
var/list/downtime_stats = list()
@@ -264,7 +292,46 @@ GLOBAL_LIST_EMPTY(personal_statistics_list)
//Replace any instances of line breaks after horizontal rules to prevent unneeded empty spaces
return replacetext(jointext(stats, " "), " ", "")
-
+/**
+ * Resets stats recorded for the current mission
+ * Used for Campaign
+ */
+/datum/personal_statistics/proc/reset_mission_stats()
+ SIGNAL_HANDLER
+ mission_projectile_damage = 0
+ mission_friendly_fire_damage = 0
+ mission_revives = 0
+ mission_times_revived = 0
+ mission_structures_built = 0
+ mission_melee_damage = 0
+ mission_objective_destroyed = 0
+ mission_blocker_destroyed = 0
+ mission_objective_captured = 0
+ mission_objective_decaptured = 0
+ mission_mechs_destroyed = 0
+ mission_shrapnel_removed = 0
+ mission_traps_created = 0
+ mission_grenades_primed = 0
+
+///Returns the credit bonus based on stats from the current mission
+/datum/personal_statistics/proc/get_mission_reward()
+ var/credit_bonus = 0
+ credit_bonus += mission_projectile_damage * 0.1
+ credit_bonus -= mission_friendly_fire_damage * 0.2
+ credit_bonus += mission_melee_damage * 0.2
+ credit_bonus += mission_revives * 15
+ credit_bonus += mission_times_revived * 5 //purple heart
+ credit_bonus += mission_structures_built * 6
+ credit_bonus += mission_objective_destroyed * 50
+ credit_bonus += mission_blocker_destroyed * 30
+ credit_bonus += mission_objective_captured * 20
+ credit_bonus += mission_objective_decaptured * 20
+ credit_bonus += mission_mechs_destroyed * 20
+ credit_bonus += mission_shrapnel_removed * 3
+ credit_bonus += mission_traps_created * 4
+ credit_bonus += mission_grenades_primed * 2
+
+ return max(floor(credit_bonus), 0)
/* Not sure what folder to put a file of just record keeping procs, so just leaving them here
The alternative is scattering them everywhere under their respective objects which is a bit messy */
@@ -276,6 +343,9 @@ The alternative is scattering them everywhere under their respective objects whi
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
personal_statistics.melee_hits++
personal_statistics.melee_damage += damage
+ personal_statistics.mission_melee_damage += damage
+ if(faction == user.faction)
+ personal_statistics.mission_friendly_fire_damage += damage
return TRUE
/mob/living/carbon/human/record_melee_damage(mob/living/user, damage, delimbed)
@@ -310,17 +380,17 @@ The alternative is scattering them everywhere under their respective objects whi
return ..()
///Tally to personal_statistics that a successful shot was made and record the damage dealt
-/mob/living/proc/record_projectile_damage(mob/shooter, damage)
- //Check if a ckey exists; the check for victim aliveness is handled before the proc call
- if(!shooter.ckey)
+/mob/living/proc/record_projectile_damage(damage, mob/living/victim)
+ if(!ckey)
return FALSE
- var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[shooter.ckey]
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[ckey]
personal_statistics.projectiles_hit++
personal_statistics.projectile_damage += damage
- if(faction && isliving(shooter)) //See if any friendly fire was made
- var/mob/living/L = shooter
- if(faction == L.faction)
- personal_statistics.friendly_fire_damage += damage //FF multiplier already included by the way
+ personal_statistics.mission_projectile_damage += damage
+
+ if(faction == victim.faction) //See if any friendly fire was made
+ personal_statistics.friendly_fire_damage += damage //FF multiplier already included by the way
+ personal_statistics.mission_friendly_fire_damage += damage
return TRUE
///Record what reagents and how much of them were transferred to a mob into their ckey's /datum/personal_statistics
@@ -422,7 +492,8 @@ The alternative is scattering them everywhere under their respective objects whi
if(!ckey)
return FALSE
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[ckey]
- personal_statistics.recycle_points_denied += trash.get_export_value()
+ var/list/exported_value = trash.get_export_value()
+ personal_statistics.recycle_points_denied += exported_value[1]
return TRUE
///Separate record keeping proc to reduce copy pasta
@@ -524,6 +595,7 @@ The alternative is scattering them everywhere under their respective objects whi
return FALSE
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[ckey]
personal_statistics.traps_created++
+ personal_statistics.mission_traps_created++
return TRUE
///Tally up bullets caught/reflected
@@ -542,6 +614,7 @@ The alternative is scattering them everywhere under their respective objects whi
return FALSE
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[ckey]
personal_statistics.structures_built++
+ personal_statistics.mission_structures_built++
return TRUE
/mob/proc/record_war_crime()
diff --git a/code/datums/quick_load_beginners.dm b/code/datums/quick_load_beginners.dm
new file mode 100644
index 0000000000000..c2554da595670
--- /dev/null
+++ b/code/datums/quick_load_beginners.dm
@@ -0,0 +1,673 @@
+//Any loadout that is intended for the new player loadout vendor
+///When making new loadouts, remember to also add the typepath to the list under init_beginner_loadouts() or else it won't show up in the vendor
+
+
+/datum/outfit/quick/beginner
+ name = "Beginner loadout base"
+ desc = "The base loadout for beginners. You shouldn't be able to see this"
+ jobtype = "Squad Marine"
+
+ w_uniform = /obj/item/clothing/under/marine
+ shoes = /obj/item/clothing/shoes/marine/full
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten
+ gloves = /obj/item/clothing/gloves/marine/black
+ mask = /obj/item/clothing/mask/bandanna
+ head = /obj/item/clothing/head/modular/m10x
+ r_store = /obj/item/storage/pouch/medkit/firstaid
+ l_store = /obj/item/storage/holster/flarepouch/full
+ back = /obj/item/storage/backpack/marine/satchel
+ belt = /obj/item/storage/belt/marine
+ ears = /obj/item/radio/headset/mainship/marine
+
+/datum/outfit/quick/beginner/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/food/snacks/protein_pack, SLOT_IN_HEAD)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/food/snacks/protein_pack, SLOT_IN_HEAD)
+
+/datum/outfit/quick/beginner/marine/rifleman
+ name = "Rifleman"
+ desc = "A typical rifleman for the marines. \
+ Wields the AR-12, a versatile all-rounder assault rifle with a powerful underbarrel grenade launcher attached. \
+ Also carries the strong P-23 sidearm and a variety of flares, medical equipment, and more for every situation."
+
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/hodgrenades
+ head = /obj/item/clothing/head/modular/m10x/hod
+ w_uniform = /obj/item/clothing/under/marine/holster
+ suit_store = /obj/item/weapon/gun/rifle/standard_assaultrifle/medic
+ l_hand = /obj/item/paper/tutorial/beginner_rifleman
+
+/datum/outfit/quick/beginner/marine/rifleman/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_assaultrifle, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/standard_heavypistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/standard_heavypistol/beginner(human), SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+
+/datum/outfit/quick/beginner/marine/machinegunner
+ name = "Machinegunner"
+ desc = "The king of suppressive fire. Uses the MG-60, a fully automatic 200 round machine gun with a bipod attached. \
+ Excels at denying large areas to the enemy and eliminating those who refuse to leave."
+
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/heavy/tyr_onegeneral
+ head = /obj/item/clothing/head/modular/m10x/tyr
+ w_uniform = /obj/item/clothing/under/marine/black_vest
+ back = /obj/item/storage/backpack/marine/standard
+ belt = /obj/item/storage/belt/sparepouch
+ suit_store = /obj/item/weapon/gun/rifle/standard_gpmg/beginner
+ mask = /obj/item/clothing/mask/rebreather
+ l_hand = /obj/item/paper/tutorial/beginner_machinegunner
+
+/datum/outfit/quick/beginner/marine/machinegunner/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_gpmg, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/plasma_pistol, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/plasma_pistol, SLOT_IN_SUIT)
+
+
+/datum/outfit/quick/beginner/marine/marksman
+ name = "Marksman"
+ desc = "Quality over quantity. Equipped with the DMR-37, an accurate long-range designated marksman rifle with a scope attached. \
+ While subpar in close quarters, the precision of the DMR is unmatched, exceeding at taking out threats from afar."
+
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/lightmedical
+ head = /obj/item/clothing/head/modular/style/boonie
+ w_uniform = /obj/item/clothing/under/marine/holster
+ belt = /obj/item/belt_harness/marine
+ l_store = /obj/item/storage/pouch/magazine/large
+ r_store = /obj/item/storage/pouch/magazine/large
+ suit_store = /obj/item/weapon/gun/rifle/standard_dmr/beginner
+ mask = /obj/item/clothing/mask/breath
+ l_hand = /obj/item/paper/tutorial/beginner_marksman
+
+/datum/outfit/quick/beginner/marine/marksman/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_dmr, SLOT_IN_R_POUCH)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/vp70, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/vp70/beginner(human), SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/bicaridine, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/kelotane, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tricordrazine, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tramadol, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dylovene, SLOT_IN_SUIT)
+
+/datum/outfit/quick/beginner/marine/shotgunner
+ name = "Shotgunner"
+ desc = "Up close and personal. Wields the SH-39, a semi-automatic shotgun loaded with slugs. \
+ An absolute monster at short to mid range, the shotgun will do heavy damage to any target hit, as well as stunning them briefly, staggering them, and knocking them back."
+
+ w_uniform = /obj/item/clothing/under/marine/holster
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/lightgeneral
+ suit_store = /obj/item/weapon/gun/shotgun/combat/standardmarine/beginner
+ belt = /obj/item/storage/belt/shotgun
+ head = /obj/item/clothing/head/modular/m10x/freyr
+ gloves = /obj/item/clothing/gloves/marine/fingerless
+ mask = /obj/item/clothing/mask/gas/tactical/coif
+ l_hand = /obj/item/paper/tutorial/beginner_shotgunner
+
+/datum/outfit/quick/beginner/marine/shotgunner/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/inaprovaline, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/plasma_pistol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/plasma_pistol/beginner(human), SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_SUIT)
+
+/datum/outfit/quick/beginner/marine/shocktrooper
+ name = "Shocktrooper"
+ desc = "The bleeding edge of the corps. \
+ Equipped with the experimental battery-fed laser rifle, featuring four different modes that can be freely swapped between, with an underbarrel flamethrower for area denial and clearing mazes."
+
+ suit_store = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle/medic
+ glasses = /obj/item/clothing/glasses/sunglasses/fake/big
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/lightgeneral
+ head = /obj/item/clothing/head/modular/style/cap
+ mask = /obj/item/clothing/mask/gas/modular/skimask
+ r_store = /obj/item/cell/lasgun/volkite/powerpack/marine
+ w_uniform = /obj/item/clothing/under/marine/corpman_vest
+ shoes = /obj/item/clothing/shoes/marine
+ l_hand = /obj/item/paper/tutorial/beginner_shocktrooper
+
+/datum/outfit/quick/beginner/marine/shocktrooper/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BOOT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/dylovene, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/flamer_tank/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/inaprovaline, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/volkite/powerpack/marine, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/bicaridine, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/kelotane, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tricordrazine, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tramadol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+
+/datum/outfit/quick/beginner/marine/hazmat
+ name = "Hazmat"
+ desc = "Designed for danger. \
+ Wields the AR-11, a powerful yet innacurate assault rifle with high magazine size and an equipped tactical sensor that detects enemies through smoke and walls. \
+ Wears Mimir combat armor, rendering the user immune to the dangerous toxic gas possessed by many xenomorphs."
+
+ head = /obj/item/clothing/head/modular/m10x/mimir
+ suit_store = /obj/item/weapon/gun/rifle/tx11/freelancertwo
+ back = /obj/item/storage/backpack/marine/standard
+ w_uniform = /obj/item/clothing/under/marine/black_vest
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/mimir
+ mask = /obj/item/clothing/mask/rebreather/scarf
+ belt = /obj/item/belt_harness/marine
+ l_hand = /obj/item/paper/tutorial/beginner_hazmat
+
+/datum/outfit/quick/beginner/marine/hazmat/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx11, SLOT_IN_SUIT)
+
+/datum/outfit/quick/beginner/marine/cqc
+ name = "CQC"
+ desc = "Swift and lethal. \
+ Equipped with the AR-18, a lightweight carbine with a rapid-fire burst mode. Designed for maximum mobility, soldiers are able to rush in, assault the enemy, and retreat before they can respond."
+
+ suit_store = /obj/item/weapon/gun/rifle/standard_carbine/beginner
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/lightgeneral
+ w_uniform = /obj/item/clothing/under/marine/black_vest
+ head = /obj/item/clothing/head/modular/style/beret
+ glasses = /obj/item/clothing/glasses/mgoggles
+ l_hand = /obj/item/paper/tutorial/beginner_cqc
+
+/datum/outfit/quick/beginner/marine/cqc/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/standard_carbine, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+
+/datum/outfit/quick/beginner/marine/chad //Ya gotta be if you pick this loadout
+ name = "Grenadier"
+ desc = "Explosive area denial. \
+ Uses the GL-70, a six shot semi-automatic grenade launcher, loaded with HEDP high explosive grenades. \
+ Boasts unmatched power, though heavy caution is advised to avoid harming friendlies."
+
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/heavy/grenadier
+ suit_store = /obj/item/weapon/gun/grenade_launcher/multinade_launcher/beginner
+ l_store = /obj/item/storage/pouch/grenade
+ r_store = /obj/item/storage/pouch/grenade
+ belt = /obj/item/storage/belt/grenade
+ mask = /obj/item/clothing/mask/gas
+ w_uniform = /obj/item/clothing/under/marine/corpman_vest
+ head = /obj/item/clothing/head/modular/m10x/hod
+ shoes = /obj/item/clothing/shoes/marine
+ l_hand = /obj/item/paper/tutorial/beginner_chad
+
+/datum/outfit/quick/beginner/marine/chad/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_R_POUCH)
+
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/inaprovaline, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/bicaridine, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/kelotane, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tricordrazine, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/tramadol, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/shotgun/double/derringer, SLOT_IN_BOOT) //So you can kill yourself when you run out of grenades
+
+/datum/outfit/quick/beginner/engineer
+ jobtype = "Squad Engineer"
+
+ w_uniform = /obj/item/clothing/under/marine/brown_vest
+ shoes = /obj/item/clothing/shoes/marine
+ gloves = /obj/item/clothing/gloves/marine/insulated
+ l_store = /obj/item/storage/pouch/tools
+
+/datum/outfit/quick/beginner/engineer/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BOOT)
+
+ human.equip_to_slot_or_del(new /obj/item/tool/screwdriver, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/tool/wirecutters, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/tool/wrench, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/tool/crowbar, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/hugetank, SLOT_IN_L_POUCH)
+
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade/chem_grenade/razorburn_small, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/tool/handheld_charger/hicapcell, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+
+/datum/outfit/quick/beginner/engineer/builder
+ name = "Engineer Standard"
+ desc = "Born to build. Equipped with a metric ton of metal, you can be certain that a lack of barricades is not a possibility with you around."
+
+ suit_store = /obj/item/weapon/gun/rifle/standard_lmg/beginner
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/heavy/mimirengi
+ mask = /obj/item/clothing/mask/gas/tactical
+ head = /obj/item/clothing/head/modular/m10x/mimir
+ back = /obj/item/storage/backpack/marine/radiopack
+ belt = /obj/item/belt_harness/marine
+ glasses = /obj/item/clothing/glasses/welding/superior
+ l_hand = /obj/item/paper/tutorial/builder
+
+/datum/outfit/quick/beginner/engineer/builder/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/small_stack, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/stack/sandbags_empty/full, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_lmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_lmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_lmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_lmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_lmg, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+
+/datum/outfit/quick/beginner/engineer/burnitall
+ name = "Flamethrower"
+ desc = "For those who truly love to watch the world burn. Equipped with a laser carbine and a flamethrower, you can be certain that none of your enemies will be left un-burnt."
+
+ suit_store = /obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/beginner
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/engineer
+ mask = /obj/item/clothing/mask/gas/tactical/coif
+ head = /obj/item/clothing/head/modular/m10x/superiorwelding
+ back = /obj/item/storage/holster/backholster/flamer
+ glasses = /obj/item/clothing/glasses/meson
+ l_hand = /obj/item/paper/tutorial/flamer
+
+/datum/outfit/quick/beginner/engineer/burnitall/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/medium_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/circuitboard/apc, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/tool/multitool, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+ human.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_BELT)
+
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer/beginner(human), SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/explosive_mines/large, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/shovel/etool, SLOT_IN_BACKPACK)
+
+/datum/outfit/quick/beginner/engineer/pcenjoyer
+ name = "Plasma Cutter"
+ desc = "For the open-air enjoyers. Equipped with a plasma cutter, you will be able to cut down all types of walls and obstacles that dare exist within your vicinity."
+
+ suit_store = /obj/item/tool/pickaxe/plasmacutter
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/engineer
+ mask = /obj/item/clothing/mask/gas
+ head = /obj/item/clothing/head/modular/m10x/superiorwelding
+ back = /obj/item/storage/backpack/marine/engineerpack
+ belt = /obj/item/belt_harness/marine
+ glasses = /obj/item/clothing/glasses/meson
+ l_hand = /obj/item/paper/tutorial/plasmacutter
+
+/datum/outfit/quick/beginner/engineer/pcenjoyer/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/explosive/plastique, SLOT_IN_HEAD)
+
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/small_stack, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/smg/standard_machinepistol/compact(human), SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/smg/standard_machinepistol, SLOT_IN_BACKPACK)
+
+/datum/outfit/quick/beginner/corpsman
+ jobtype = "Squad Corpsman"
+
+ shoes = /obj/item/clothing/shoes/marine
+ w_uniform = /obj/item/clothing/under/marine/corpsman/corpman_vest
+ glasses = /obj/item/clothing/glasses/hud/health
+ r_hand = /obj/item/medevac_beacon
+
+/datum/outfit/quick/beginner/corpsman/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BOOT)
+
+/datum/outfit/quick/beginner/corpsman/lifesaver
+ name = "Standard Lifesaver"
+ desc = "Miracle in progress. \
+ Wields the bolt action Leicaster Repeater, and is equipped with a large variety of medicine for keeping the entire corps topped up and in the fight."
+
+ suit_store = /obj/item/weapon/gun/shotgun/pump/lever/repeater/beginner
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/mimirinjector
+ gloves = /obj/item/clothing/gloves/defibrillator
+ mask = /obj/item/clothing/mask/gas
+ head = /obj/item/clothing/head/modular/m10x/mimir
+ r_store = /obj/item/storage/pouch/medkit/medic
+ l_store = /obj/item/storage/pouch/shotgun
+ back = /obj/item/storage/backpack/marine/corpsman
+ belt = /obj/item/storage/belt/lifesaver/beginner
+ l_hand = /obj/item/paper/tutorial/lifesaver
+
+/datum/outfit/quick/beginner/corpsman/lifesaver/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/roller, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/bodybag/cryobag, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/oxycodone, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/nanoblood, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/roller/medevac, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/tweezers, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/dexalinplus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/quickclotplus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/peridaxon_plus, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/p4570, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/repeater, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/repeater, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/repeater, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/repeater, SLOT_IN_L_POUCH)
+
+/datum/outfit/quick/beginner/corpsman/hypobelt
+ name = "Standard Hypobelt"
+ desc = "Putting the combat in combat medic. \
+ Wields the pump action SH-35 shotgun, and is equipped with a belt full of hyposprays for rapidly treating patients in bad condition."
+
+ suit_store = /obj/item/weapon/gun/shotgun/pump/t35/beginner
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/light/lightmedical
+ gloves = /obj/item/healthanalyzer/gloves
+ mask = /obj/item/clothing/mask/gas/modular/coofmask
+ head = /obj/item/clothing/head/modular/m10x/antenna
+ r_store = /obj/item/storage/pouch/medkit/medic
+ l_store = /obj/item/storage/pouch/shotgun
+ back = /obj/item/storage/backpack/marine/corpsman
+ belt = /obj/item/storage/belt/hypospraybelt/beginner
+ l_hand = /obj/item/paper/tutorial/hypobelt
+
+/datum/outfit/quick/beginner/corpsman/hypobelt/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/splint, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/roller, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/bodybag/cryobag, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/advanced/oxycodone, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/roller/medevac, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/tweezers, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_L_POUCH)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_L_POUCH)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/tool/extinguisher/mini, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/defibrillator, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/food/snacks/protein_pack, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/slug, SLOT_IN_BACKPACK)
+
+/datum/outfit/quick/beginner/smartgunner
+ jobtype = "Squad Smartgunner"
+
+ w_uniform = /obj/item/clothing/under/marine/black_vest
+ shoes = /obj/item/clothing/shoes/marine
+ wear_suit = /obj/item/clothing/suit/modular/xenonauten/lightgeneral
+ mask = /obj/item/clothing/mask/gas
+ head = /obj/item/clothing/head/modular/m10x/antenna
+ belt = /obj/item/belt_harness/marine
+ glasses = /obj/item/clothing/glasses/night/m56_goggles
+
+/datum/outfit/quick/beginner/smartgunner/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/storage/box/MRE, SLOT_IN_BOOT)
+
+/datum/outfit/quick/beginner/smartgunner/sg29
+ name = "Standard Smartmachinegun"
+ desc = "Tactical support fire. \
+ Uses the SG-29, a specialist light machine gun that will shoot through your allies, \
+ equipped with a tactical sensor to detect enemies through smoke, walls, and darkness."
+
+ suit_store = /obj/item/weapon/gun/rifle/standard_smartmachinegun/pmc
+ l_hand = /obj/item/paper/tutorial/smartmachinegunner
+
+/datum/outfit/quick/beginner/smartgunner/sg29/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/tool/extinguisher, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+
+ human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/plasma_pistol, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/explosive/grenade/smokebomb/cloak, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/autoinjector/inaprovaline, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_BACKPACK)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/standard_smartmachinegun, SLOT_IN_BACKPACK)
+
+/datum/outfit/quick/beginner/smartgunner/sg85
+ name = "Standard Smartminigun"
+ desc = "Lead wall! Wields the SG-85, a specialist minigun that holds one thousand rounds and can shoot through your allies, \
+ equipped with a tactical sensor to detect enemies through smoke, walls, and darkness."
+
+ suit_store = /obj/item/weapon/gun/minigun/smart_minigun/motion_detector
+ back = /obj/item/ammo_magazine/minigun_powerpack/smartgun
+ l_hand = /obj/item/paper/tutorial/smartminigunner
+
+/datum/outfit/quick/beginner/smartgunner/sg85/post_equip(mob/living/carbon/human/human, visualsOnly)
+ . = ..()
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/smart_minigun, SLOT_IN_SUIT)
+ human.equip_to_slot_or_del(new /obj/item/ammo_magazine/packet/smart_minigun, SLOT_IN_SUIT)
+
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/storage/box/m94, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/gauze, SLOT_IN_ACCESSORY)
+ human.equip_to_slot_or_del(new /obj/item/stack/medical/heal_pack/ointment, SLOT_IN_ACCESSORY)
+
diff --git a/code/datums/quick_load_outfits.dm b/code/datums/quick_load_outfits.dm
index c2e5626782bca..3963455b05762 100644
--- a/code/datums/quick_load_outfits.dm
+++ b/code/datums/quick_load_outfits.dm
@@ -388,7 +388,6 @@
name = "SH-35 Scout"
desc = "For getting too close for comfort. Equipped with a SH-35 shotgun with buckshot and flechette rounds, a MP-19 sidearm, a good amount of grenades and light armor with a cutting edge 'svallin' shield module. Provides for excellent mobility and devestating close range firepower, but will falter against sustained firepower."
- belt = /obj/item/storage/belt/shotgun
wear_suit = /obj/item/clothing/suit/modular/xenonauten/light/shield
suit_store = /obj/item/weapon/gun/shotgun/pump/t35/standard
belt = /obj/item/storage/belt/shotgun/mixed
@@ -760,10 +759,6 @@
H.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx15_flechette, SLOT_IN_R_POUCH)
H.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/tx15_slug, SLOT_IN_R_POUCH)
- H.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_R_POUCH)
- H.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_R_POUCH)
- H.equip_to_slot_or_del(new /obj/item/cell/lasgun/lasrifle, SLOT_IN_R_POUCH)
-
/datum/outfit/quick/tgmc/corpsman/laser_medic
name = "Laser Rifle Corpsman"
desc = "Keeping everone else in the fight. Armed with an laser rifle with miniflamer, an impressive array of tools for healing your team, and a 'Mimir' biological protection module to allow you to continue operating in hazardous environments. With medivacs out of the question, you are the only thing standing between your buddies and an early grave."
diff --git a/code/datums/round_statistics.dm b/code/datums/round_statistics.dm
index 02bb1ff416c33..53a41816ee04d 100644
--- a/code/datums/round_statistics.dm
+++ b/code/datums/round_statistics.dm
@@ -61,6 +61,7 @@ GLOBAL_DATUM_INIT(round_statistics, /datum/round_statistics, new)
var/mortar_shells_fired = 0
var/howitzer_shells_fired = 0
var/rocket_shells_fired = 0
+ var/obs_fired = 0
var/queen_screech = 0
var/now_pregnant = 0
var/sentinel_drain_stings = 0
diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm
index 4468122b11479..3fbbc3e31695a 100644
--- a/code/datums/shuttles.dm
+++ b/code/datums/shuttles.dm
@@ -143,18 +143,13 @@
display_name = "Tadpole NK-Haul Model"
/datum/map_template/shuttle/minidropship/mobile_bar
- suffix = "_mobile_bar"
+ suffix = "_mobile_bar"
description = "A Tadpole modified to provide drinks and disservices. God dammit it's him again, I thought we got rid of him."
display_name = "Tadpole Mobile-Bar Model"
admin_enable = FALSE
-/datum/map_template/shuttle/minidropship/combat_tad
- suffix = "_combat_tad"
- description = "A Tadpole model modified to have three weapon hardpoints instead of just one, the majority of the other standard features had to be scrapped to fit all three of them on."
- display_name = "Tadpole Combat Model"
-
/datum/map_template/shuttle/minidropship/umbilical
- suffix = "_umbilical"
+ suffix = "_umbilical"
description = "A high-point orbital shuttle with a tactical umbilical airlock for insertion of ground troops."
display_name = "Tadpole Umbilical Model"
diff --git a/code/datums/skills.dm b/code/datums/skills.dm
index be7d9ad26c1a2..25c6a0df117f3 100644
--- a/code/datums/skills.dm
+++ b/code/datums/skills.dm
@@ -257,8 +257,8 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
firearms = SKILL_FIREARMS_DEFAULT
medical = SKILL_MEDICAL_EXPERT
surgery = SKILL_SURGERY_EXPERT
- construction = SKILL_CONSTRUCTION_MASTER
- engineer = SKILL_ENGINEER_MASTER
+ construction = SKILL_CONSTRUCTION_EXPERT
+ engineer = SKILL_ENGINEER_EXPERT
powerloader = SKILL_POWERLOADER_MASTER
police = SKILL_POLICE_FLASH
@@ -285,8 +285,8 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/civilian/survivor/atmos
name = "Survivor Atmos Tech"
- engineer = SKILL_ENGINEER_MASTER
- construction = SKILL_CONSTRUCTION_MASTER
+ engineer = SKILL_ENGINEER_EXPERT
+ construction = SKILL_CONSTRUCTION_EXPERT
/datum/skills/civilian/survivor/marshal
name = "Survivor Marshal"
@@ -314,6 +314,12 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
construction = SKILL_CONSTRUCTION_METAL
engineer = SKILL_ENGINEER_METAL
+/datum/skills/combat_medic/special_forces
+ name = "Special Operations Medic"
+ construction = SKILL_CONSTRUCTION_METAL
+ engineer = SKILL_ENGINEER_METAL
+ smgs = SKILL_SMGS_TRAINED
+
/datum/skills/doctor
name = "Doctor"
cqc = SKILL_CQC_WEAK
@@ -342,8 +348,8 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/ai
name = "AI"
- engineer = SKILL_ENGINEER_MASTER
- construction = SKILL_CONSTRUCTION_MASTER
+ engineer = SKILL_ENGINEER_EXPERT
+ construction = SKILL_CONSTRUCTION_EXPERT
firearms = SKILL_FIREARMS_UNTRAINED
medical = SKILL_MEDICAL_EXPERT
leadership = SKILL_LEAD_MASTER
@@ -354,8 +360,8 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/synthetic
name = SYNTHETIC
- engineer = SKILL_ENGINEER_MASTER
- construction = SKILL_CONSTRUCTION_MASTER
+ engineer = SKILL_ENGINEER_EXPERT
+ construction = SKILL_CONSTRUCTION_EXPERT
firearms = SKILL_FIREARMS_UNTRAINED
medical = SKILL_MEDICAL_EXPERT
cqc = SKILL_CQC_MASTER
@@ -368,10 +374,10 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/early_synthetic
name = "Early Synthetic"
- engineer = SKILL_ENGINEER_INHUMAN
- construction = SKILL_CONSTRUCTION_INHUMAN
+ engineer = SKILL_ENGINEER_MASTER
+ construction = SKILL_CONSTRUCTION_MASTER
firearms = SKILL_FIREARMS_UNTRAINED
- medical = SKILL_SURGERY_PROFESSIONAL
+ medical = SKILL_MEDICAL_COMPETENT
cqc = SKILL_CQC_MASTER
surgery = SKILL_SURGERY_PROFESSIONAL
pilot = SKILL_PILOT_TRAINED
@@ -404,12 +410,40 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
powerloader = SKILL_POWERLOADER_TRAINED
cqc = SKILL_CQC_TRAINED
+/datum/skills/veteran
+ name = "TGMC Retired Veteran"
+ engineer = SKILL_ENGINEER_ENGI //to fix CIC apc.
+ construction = SKILL_CONSTRUCTION_PLASTEEL
+ leadership = SKILL_LEAD_MASTER
+ medical = SKILL_MEDICAL_PRACTICED
+ surgery = SKILL_SURGERY_AMATEUR
+ police = SKILL_POLICE_MP
+ powerloader = SKILL_POWERLOADER_TRAINED
+ cqc = SKILL_CQC_TRAINED
+ firearms = SKILL_FIREARMS_TRAINED
+ rifles = SKILL_RIFLES_TRAINED
+
+/datum/skills/veteran_captain
+ name = "TGMC Retired Veteran Expedition Leader"
+ leadership = SKILL_LEAD_MASTER
+ police = SKILL_POLICE_MP
+ medical = SKILL_MEDICAL_COMPETENT
+ surgery = SKILL_SURGERY_AMATEUR
+ engineer = SKILL_ENGINEER_ENGI
+ construction = SKILL_CONSTRUCTION_ADVANCED
+ powerloader = SKILL_POWERLOADER_MASTER
+ firearms = SKILL_FIREARMS_TRAINED
+ rifles = SKILL_RIFLES_TRAINED
+ smartgun = SKILL_SMART_TRAINED
+
/datum/skills/so
name = STAFF_OFFICER
+ engineer = SKILL_ENGINEER_ENGI
construction = SKILL_CONSTRUCTION_PLASTEEL
leadership = SKILL_LEAD_EXPERT
medical = SKILL_MEDICAL_PRACTICED
surgery = SKILL_SURGERY_AMATEUR
+ powerloader = SKILL_POWERLOADER_TRAINED
police = SKILL_POLICE_MP
/datum/skills/pilot
@@ -418,18 +452,39 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
powerloader = SKILL_POWERLOADER_PRO
leadership = SKILL_LEAD_TRAINED
+/datum/skills/transportofficer
+ name = TRANSPORT_OFFICER
+ construction = SKILL_CONSTRUCTION_ADVANCED
+ powerloader = SKILL_POWERLOADER_PRO
+ engineer = SKILL_ENGINEER_ENGI
+ leadership = SKILL_LEAD_TRAINED
+
/datum/skills/mech_pilot
name = MECH_PILOT
engineer = SKILL_ENGINEER_METAL
construction = SKILL_CONSTRUCTION_METAL
powerloader = SKILL_POWERLOADER_PRO
- large_vehicle = SKILL_LARGE_VEHICLE_TRAINED
+ large_vehicle = SKILL_LARGE_VEHICLE_VETERAN
+
+/datum/skills/assault_crewman
+ name = ASSAULT_CREWMAN
+ engineer = SKILL_ENGINEER_METAL
+ construction = SKILL_CONSTRUCTION_METAL
+ powerloader = SKILL_POWERLOADER_PRO
+ large_vehicle = SKILL_LARGE_VEHICLE_VETERAN
+
+/datum/skills/transport_crewman
+ name = TRANSPORT_CREWMAN
+ engineer = SKILL_ENGINEER_METAL
+ construction = SKILL_CONSTRUCTION_METAL
+ powerloader = SKILL_POWERLOADER_PRO
+ large_vehicle = SKILL_LARGE_VEHICLE_EXPERIENCED
/datum/skills/ce
name = CHIEF_SHIP_ENGINEER
engineer = SKILL_ENGINEER_MASTER
construction = SKILL_CONSTRUCTION_MASTER
- leadership = SKILL_LEAD_EXPERT
+ leadership = SKILL_LEAD_TRAINED
police = SKILL_POLICE_MP
powerloader = SKILL_POWERLOADER_MASTER
@@ -442,8 +497,8 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/st
name = SHIP_TECH
- engineer = SKILL_ENGINEER_MASTER
- construction = SKILL_CONSTRUCTION_MASTER
+ engineer = SKILL_ENGINEER_EXPERT
+ construction = SKILL_CONSTRUCTION_EXPERT
powerloader = SKILL_POWERLOADER_MASTER
/datum/skills/pmc
@@ -462,10 +517,11 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
engineer = SKILL_ENGINEER_ENGI
/datum/skills/special_forces_standard
- name = "Special Force Standard"
+ name = "Special Response Force Standard"
construction = SKILL_CONSTRUCTION_METAL
engineer = SKILL_ENGINEER_METAL
police = SKILL_POLICE_MP
+ smgs = SKILL_SMGS_TRAINED
/datum/skills/sl
name = SQUAD_LEADER
@@ -505,6 +561,7 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
/datum/skills/sl/pmc/special_forces
name = "Special Force Leader"
police = SKILL_POLICE_MP
+ smgs = SKILL_SMGS_TRAINED
/datum/skills/sl/icc
name = "ICC Leader"
@@ -624,7 +681,7 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader
heavy_weapons = SKILL_HEAVY_WEAPONS_TRAINED
police = SKILL_POLICE_MP
powerloader = SKILL_POWERLOADER_MASTER
- large_vehicle = SKILL_LARGE_VEHICLE_TRAINED
+ large_vehicle = SKILL_LARGE_VEHICLE_VETERAN
/* Deathsquad */
/datum/skills/deathsquad
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index c4587bf9e5847..a6e44d48f83e3 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -144,24 +144,24 @@
return ..()
/datum/status_effect/incapacitating/sleeping/tick()
- if(owner.maxHealth)
- var/health_ratio = owner.health / owner.maxHealth
- var/healing = BASE_HEAL_RATE //set for a base of 0.25 healed per 2-second interval asleep in a bed with covers.
- if((locate(/obj/structure/bed) in owner.loc))
- healing += (2 * BASE_HEAL_RATE)
- else if((locate(/obj/structure/table) in owner.loc))
- healing += BASE_HEAL_RATE
- for(var/obj/item/bedsheet/bedsheet in range(owner.loc,0))
- if(bedsheet.loc != owner.loc) //bedsheets in your backpack/neck don't give you comfort
- continue
- healing += BASE_HEAL_RATE
- break //Only count the first bedsheet
- if(health_ratio > -0.5)
- owner.adjustBruteLoss(healing)
- owner.adjustFireLoss(healing)
- owner.adjustToxLoss(healing * 0.5, TRUE, TRUE)
- owner.adjustStaminaLoss(healing * 100)
- owner.adjustCloneLoss(healing * health_ratio * 0.8)
+ if(!owner.maxHealth)
+ return
+ var/health_ratio = owner.health / owner.maxHealth
+ var/healing = BASE_HEAL_RATE //set for a base of 0.25 healed per 2-second interval asleep in a bed with covers.
+ if((locate(/obj/structure/bed) in owner.loc))
+ healing += (2 * BASE_HEAL_RATE)
+ else if((locate(/obj/structure/table) in owner.loc))
+ healing += BASE_HEAL_RATE
+ if(locate(/obj/item/bedsheet) in owner.loc)
+ healing += BASE_HEAL_RATE
+ if((locate(/obj/item/toy/plush) in owner.loc)) // plushie bonus in bed with a blanket
+ healing += 0.75 * BASE_HEAL_RATE // plushie bonus in bed with a blanket
+ if(health_ratio > -0.5)
+ owner.adjustBruteLoss(healing)
+ owner.adjustFireLoss(healing)
+ owner.adjustToxLoss(healing * 0.5, TRUE, TRUE)
+ owner.adjustStaminaLoss(healing * 100)
+ owner.adjustCloneLoss(healing * health_ratio * 0.8)
if(human_owner?.drunkenness)
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
if(prob(20))
@@ -426,6 +426,7 @@
return ..()
/datum/status_effect/spacefreeze
+ alert_type = /atom/movable/screen/alert/status_effect/spacefreeze
id = "spacefreeze"
/datum/status_effect/spacefreeze/on_creation(mob/living/new_owner)
@@ -820,3 +821,8 @@
scale = generator(GEN_VECTOR, list(0.6, 0.6), list(1, 1), NORMAL_RAND)
friction = -0.05
color = "#818181"
+
+/atom/movable/screen/alert/status_effect/spacefreeze
+ name = "Freezing"
+ desc = "Space is very very cold, who would've thought?"
+ icon_state = "cold3"
diff --git a/code/datums/status_effects/sectoid.dm b/code/datums/status_effects/sectoid.dm
new file mode 100644
index 0000000000000..40351afc84835
--- /dev/null
+++ b/code/datums/status_effects/sectoid.dm
@@ -0,0 +1,137 @@
+/datum/status_effect/mindmeld
+ id = "mindmeld"
+ duration = -1
+ tick_interval = 2 SECONDS
+ alert_type = null
+ /// Used to track who is the owner of this buff.
+ var/mob/living/carbon/link_target
+ /// Used to track who is giving this buff to the owner.
+ var/mob/living/carbon/link_partner
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+ /// If the target xeno was within range.
+ var/was_within_range = TRUE
+ ///Range the linkees must be to each other to benefit
+ var/max_range = 6
+ ///Projectile accuracy buff
+ var/accuracy_mod = 0
+ ///Max health buff
+ var/health_mod = 0
+ ///Movement speed buff
+ var/speed_mod = 0
+ ///% chance to ignore stuns
+ var/stun_resistance = 0
+
+/datum/status_effect/mindmeld/on_creation(mob/living/new_owner, mob/living/carbon/partner, new_max_range, new_accuracy_mod, new_health_mod, new_speed_mod, new_stun_resistance)
+ link_target = new_owner
+ link_partner = partner
+ ADD_TRAIT(link_target, TRAIT_MINDMELDED, TRAIT_STATUS_EFFECT(id))
+ max_range = new_max_range
+ accuracy_mod = new_accuracy_mod
+ health_mod = new_health_mod
+ speed_mod = new_speed_mod
+ if(new_stun_resistance)
+ stun_resistance = new_stun_resistance
+ RegisterSignals(link_target, list(
+ COMSIG_LIVING_STATUS_STUN,
+ COMSIG_LIVING_STATUS_KNOCKDOWN,
+ COMSIG_LIVING_STATUS_PARALYZE,
+ COMSIG_LIVING_STATUS_UNCONSCIOUS,
+ COMSIG_LIVING_STATUS_CONFUSED,
+ COMSIG_LIVING_STATUS_STAGGER,
+ ), PROC_REF(handle_stun))
+ INVOKE_ASYNC(link_target, TYPE_PROC_REF(/mob, emote), "roar2")
+ toggle_buff(TRUE)
+ return ..()
+
+/datum/status_effect/mindmeld/on_remove()
+ link_target.balloon_alert(link_target, "mindmeld inactive")
+ REMOVE_TRAIT(link_target, TRAIT_MINDMELDED, TRAIT_STATUS_EFFECT(id))
+ link_target.UnregisterSignal(link_target, list(
+ COMSIG_LIVING_STATUS_STUN,
+ COMSIG_LIVING_STATUS_KNOCKDOWN,
+ COMSIG_LIVING_STATUS_PARALYZE,
+ COMSIG_LIVING_STATUS_UNCONSCIOUS,
+ COMSIG_LIVING_STATUS_CONFUSED,
+ COMSIG_LIVING_STATUS_STAGGER,
+ ))
+ check_range()
+ return ..()
+
+/datum/status_effect/mindmeld/tick()
+ check_range()
+
+///Checks if mob is in buff range and toggles as required
+/datum/status_effect/mindmeld/proc/check_range()
+ var/within_range = get_dist(link_target, link_partner) <= max_range
+ if(within_range != was_within_range)
+ was_within_range = within_range
+ toggle_buff(was_within_range)
+
+/// Toggles the buff on or off.
+/datum/status_effect/mindmeld/proc/toggle_buff(toggle)
+ if(!toggle)
+ link_target.adjust_mob_accuracy(-accuracy_mod)
+ link_target.maxHealth -= health_mod
+ link_target.remove_movespeed_modifier(MOVESPEED_ID_MINDMELD)
+ toggle_particles(FALSE)
+ return
+ link_target.adjust_mob_accuracy(accuracy_mod)
+ link_target.maxHealth += health_mod
+ link_target.add_movespeed_modifier(MOVESPEED_ID_MINDMELD, TRUE, 0, NONE, FALSE, speed_mod)
+ toggle_particles(TRUE)
+
+/// Toggles particles on or off, adjusting their positioning to fit the buff's owner.
+/datum/status_effect/mindmeld/proc/toggle_particles(toggle)
+ if(toggle)
+ link_target.add_filter("[id]", 3, outline_filter(1, LIGHT_COLOR_BLUE))
+ else
+ link_target.remove_filter("[id]")
+
+/// Removes the status effect on death.
+/datum/status_effect/mindmeld/proc/handle_stun(datum/source, amount, ignore_canstun)
+ SIGNAL_HANDLER
+ if(amount >= 3)
+ return
+ if(prob(stun_resistance))
+ return COMPONENT_NO_STUN
+
+// ***************************************
+// *********** Reknit form
+// ***************************************
+/datum/status_effect/reknit_form
+ id = "reknit_form"
+ tick_interval = 0.5 SECONDS
+ alert_type = /atom/movable/screen/alert/status_effect/reknit_form
+
+/datum/status_effect/reknit_form/on_creation(mob/living/new_owner, set_duration)
+ owner = new_owner
+ duration = set_duration
+ owner.add_filter("[id]", 0, outline_filter(2, LIGHT_COLOR_EMISSIVE_GREEN))
+ return ..()
+
+/datum/status_effect/reknit_form/on_remove()
+ . = ..()
+ owner.remove_filter("[id]")
+
+/datum/status_effect/reknit_form/tick()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/human_owner = owner
+ human_owner.reagent_shock_modifier -= PAIN_REDUCTION_VERY_HEAVY //oof ow ouch
+ for(var/datum/limb/limb_to_fix AS in human_owner.limbs)
+ if(limb_to_fix.limb_status & (LIMB_BROKEN | LIMB_SPLINTED | LIMB_STABILIZED))
+ if((prob(50) || limb_to_fix.brute_dam > limb_to_fix.min_broken_damage))
+ continue
+ limb_to_fix.remove_limb_flags(LIMB_BROKEN | LIMB_SPLINTED | LIMB_STABILIZED)
+ limb_to_fix.add_limb_flags(LIMB_REPAIRED)
+ break
+
+ owner.adjustCloneLoss(-3)
+ owner.adjustOxyLoss(-5)
+ owner.heal_overall_damage(5, 5)
+ owner.adjustToxLoss(-3)
+
+/atom/movable/screen/alert/status_effect/reknit_form
+ name = "Reknit form"
+ desc = "Your health is being restored."
+ icon_state = "xeno_rejuvenate"
diff --git a/code/datums/status_effects/xeno_buffs.dm b/code/datums/status_effects/xeno_buffs.dm
index cfa6d290f998d..c701129c79dda 100644
--- a/code/datums/status_effects/xeno_buffs.dm
+++ b/code/datums/status_effects/xeno_buffs.dm
@@ -331,64 +331,8 @@
enhancement_action.end_ability()
// ***************************************
-// *********** Rejuvenate
+// *********** Psychic Link
// ***************************************
-/atom/movable/screen/alert/status_effect/xeno_rejuvenate
- name = "Rejuvenation"
- desc = "Your health is being restored."
- icon_state = "xeno_rejuvenate"
-
-/datum/status_effect/xeno_rejuvenate
- id = "xeno_rejuvenate"
- tick_interval = 2 SECONDS
- alert_type = /atom/movable/screen/alert/status_effect/xeno_rejuvenate
- ///Amount of damage taken before reduction kicks in
- var/tick_damage_limit
- ///Amount of damage taken this tick
- var/tick_damage
-
-/datum/status_effect/xeno_rejuvenate/on_creation(mob/living/new_owner, set_duration, tick_damage_limit)
- owner = new_owner
- duration = set_duration
- src.tick_damage_limit = tick_damage_limit
- RegisterSignals(owner, list(COMSIG_XENOMORPH_BRUTE_DAMAGE, COMSIG_XENOMORPH_BURN_DAMAGE), PROC_REF(handle_damage_taken))
- owner.add_movespeed_modifier(MOVESPEED_ID_GORGER_REJUVENATE, TRUE, 0, NONE, TRUE, GORGER_REJUVENATE_SLOWDOWN)
- owner.add_filter("[id]m", 0, outline_filter(2, "#455d5762"))
- return ..()
-
-/datum/status_effect/xeno_rejuvenate/on_remove()
- . = ..()
- UnregisterSignal(owner, list(COMSIG_XENOMORPH_BRUTE_DAMAGE, COMSIG_XENOMORPH_BURN_DAMAGE))
- owner.remove_movespeed_modifier(MOVESPEED_ID_GORGER_REJUVENATE)
- owner.remove_filter("[id]m")
-
-/datum/status_effect/xeno_rejuvenate/tick()
- var/mob/living/carbon/xenomorph/owner_xeno = owner
- if(owner_xeno.plasma_stored < GORGER_REJUVENATE_COST)
- to_chat(owner_xeno, span_notice("Not enough substance to sustain ourselves..."))
- owner_xeno.remove_status_effect(STATUS_EFFECT_XENO_REJUVENATE)
- return
-
- owner_xeno.plasma_stored -= GORGER_REJUVENATE_COST
- new /obj/effect/temp_visual/telekinesis(get_turf(owner_xeno))
- to_chat(owner_xeno, span_notice("We feel our wounds close up."))
-
- var/amount = owner_xeno.maxHealth * GORGER_REJUVENATE_HEAL
- HEAL_XENO_DAMAGE(owner_xeno, amount, FALSE)
- tick_damage = 0
-
-///Handles damage received when the status effect is active
-/datum/status_effect/xeno_rejuvenate/proc/handle_damage_taken(datum/source, amount, list/amount_mod)
- SIGNAL_HANDLER
- if(amount <= 0)
- return
-
- tick_damage += amount
- if(tick_damage < tick_damage_limit)
- return
-
- amount_mod += min(amount * 0.75, 40)
-
#define PSYCHIC_LINK_COLOR "#2a888360"
#define CALC_DAMAGE_REDUCTION(amount, amount_mod) \
if(amount <= 0) { \
@@ -398,9 +342,6 @@
amount = min(amount * redirect_mod, remaining_health); \
amount_mod += amount
-// ***************************************
-// *********** Psychic Link
-// ***************************************
/datum/status_effect/xeno_psychic_link
id = "xeno_psychic_link"
tick_interval = 2 SECONDS
diff --git a/code/datums/weakrefs.dm b/code/datums/weakrefs.dm
index 9827cd556a3fe..3c1e90f3d20b2 100644
--- a/code/datums/weakrefs.dm
+++ b/code/datums/weakrefs.dm
@@ -1,3 +1,5 @@
+/// Creates a weakref to the given input.
+/// See /datum/weakref's documentation for more information.
/proc/WEAKREF(datum/input)
if(istype(input) && !QDELETED(input))
if(istype(input, /datum/weakref))
@@ -7,9 +9,49 @@
input.weak_reference = new /datum/weakref(input)
return input.weak_reference
-/datum/proc/create_weakref() //Forced creation for admin proccalls
+/datum/proc/create_weakref() //Forced creation for admin proccalls
return WEAKREF(src)
+/**
+ * A weakref holds a non-owning reference to a datum.
+ * The datum can be referenced again using `resolve()`.
+ *
+ * To figure out why this is important, you must understand how deletion in
+ * BYOND works.
+ *
+ * Imagine a datum as a TV in a living room. When one person enters to watch
+ * TV, they turn it on. Others can come into the room and watch the TV.
+ * When the last person leaves the room, they turn off the TV because it's
+ * no longer being used.
+ *
+ * A datum being deleted tells everyone who's watching the TV to stop.
+ * If everyone leaves properly (AKA cleaning up their references), then the
+ * last person will turn off the TV, and everything is well.
+ * However, if someone is resistant (holds a hard reference after deletion),
+ * then someone has to walk in, drag them away, and turn off the TV forecefully.
+ * This process is very slow, and it's known as hard deletion.
+ *
+ * This is where weak references come in. Weak references don't count as someone
+ * watching the TV. Thus, when what it's referencing is destroyed, it will
+ * hopefully clean up properly, and limit hard deletions.
+ *
+ * A common use case for weak references is holding onto what created itself.
+ * For example, if a machine wanted to know what its last user was, it might
+ * create a `var/mob/living/last_user`. However, this is a strong reference to
+ * the mob, and thus will force a hard deletion when that mob is deleted.
+ * It is often better in this case to instead create a weakref to the user,
+ * meaning this type definition becomes `var/datum/weakref/last_user`.
+ *
+ * A good rule of thumb is that you should hold strong references to things
+ * that you *own*. For example, a dog holding a chew toy would be the owner
+ * of that chew toy, and thus a `var/obj/item/chew_toy` reference is fine
+ * (as long as it is cleaned up properly).
+ * However, a chew toy does not own its dog, so a `var/mob/living/dog/owner`
+ * might be inferior to a weakref.
+ * This is also a good rule of thumb to avoid circular references, such as the
+ * chew toy example. A circular reference that doesn't clean itself up properly
+ * will always hard delete.
+ */
/datum/weakref
var/reference
@@ -25,7 +67,46 @@
target?.weak_reference = null
return ..()
+/**
+ * Retrieves the datum that this weakref is referencing.
+ *
+ * This will return `null` if the datum was deleted. This MUST be respected.
+ */
/datum/weakref/proc/resolve()
var/datum/D = locate(reference)
return (!QDELETED(D) && D.weak_reference == src) ? D : null
+/**
+ * SERIOUSLY READ THE AUTODOC COMMENT FOR THIS PROC BEFORE EVEN THINKING ABOUT USING IT
+ *
+ * Like resolve, but doesn't care if the datum is being qdeleted but hasn't been deleted yet.
+ *
+ * The return value of this proc leaves hanging references if the datum is being qdeleted but hasn't been deleted yet.
+ *
+ * Do not do anything that would create a lasting reference to the return value, such as giving it a tag, putting it on the map,
+ * adding it to an atom's contents or vis_contents, giving it a key (if it's a mob), attaching it to an atom (if it's an image),
+ * or assigning it to a datum or list referenced somewhere other than a temporary value.
+ *
+ * Unless you're resolving a weakref to a datum in a COMSIG_QDELETING signal handler registered on that very same datum,
+ * just use resolve instead.
+ */
+/datum/weakref/proc/hard_resolve()
+ var/datum/D = locate(reference)
+ return (D?.weak_reference == src) ? D : null
+
+/datum/weakref/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION(VV_HK_WEAKREF_RESOLVE, "Go to reference")
+
+/datum/weakref/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_WEAKREF_RESOLVE])
+ if(!check_rights(NONE))
+ return
+ var/datum/R = resolve()
+ if(R)
+ usr.client.debug_variables(R)
diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm
new file mode 100644
index 0000000000000..2e66443154b9b
--- /dev/null
+++ b/code/game/alternate_appearance.dm
@@ -0,0 +1,134 @@
+GLOBAL_LIST_EMPTY(active_alternate_appearances)
+
+/atom/proc/remove_alt_appearance(key)
+ if(alternate_appearances)
+ for(var/K in alternate_appearances)
+ var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K]
+ if(AA.appearance_key == key)
+ AA.remove_from_hud(src)
+ break
+
+/atom/proc/add_alt_appearance(type, key, ...)
+ if(!type || !key)
+ return
+ if(alternate_appearances && alternate_appearances[key])
+ return
+ if(!ispath(type, /datum/atom_hud/alternate_appearance))
+ CRASH("Invalid type passed in: [type]")
+ var/list/arguments = args.Copy(2)
+ return new type(arglist(arguments))
+
+/datum/atom_hud/alternate_appearance
+ var/appearance_key
+ var/transfer_overlays = FALSE
+
+/datum/atom_hud/alternate_appearance/New(key)
+ ..()
+ GLOB.active_alternate_appearances += src
+ appearance_key = key
+
+ for(var/mob AS in GLOB.player_list)
+ if(mobShouldSee(mob))
+ add_hud_to(mob)
+
+/datum/atom_hud/alternate_appearance/Destroy()
+ GLOB.active_alternate_appearances -= src
+ return ..()
+
+/datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M)
+ if(mobShouldSee(M))
+ add_hud_to(M)
+
+/datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M)
+ return FALSE
+
+/datum/atom_hud/alternate_appearance/add_to_hud(atom/A, image/I)
+ . = ..()
+ if(.)
+ LAZYINITLIST(A.alternate_appearances)
+ A.alternate_appearances[appearance_key] = src
+
+/datum/atom_hud/alternate_appearance/remove_from_hud(atom/A)
+ . = ..()
+ if(.)
+ LAZYREMOVE(A.alternate_appearances, appearance_key)
+
+/datum/atom_hud/alternate_appearance/proc/copy_overlays(atom/other, cut_old)
+ return
+
+//an alternate appearance that attaches a single image to a single atom
+/datum/atom_hud/alternate_appearance/basic
+ var/atom/target
+ var/image/image
+ var/add_ghost_version = FALSE
+ var/ghost_appearance
+
+/datum/atom_hud/alternate_appearance/basic/New(key, image/I, options = AA_TARGET_SEE_APPEARANCE)
+ ..()
+ transfer_overlays = options & AA_MATCH_TARGET_OVERLAYS
+ image = I
+ target = I.loc
+ if(transfer_overlays)
+ I.copy_overlays(target)
+
+ hud_icons = list(appearance_key)
+ add_to_hud(target, I)
+ if((options & AA_TARGET_SEE_APPEARANCE) && ismob(target))
+ add_hud_to(target)
+ if(add_ghost_version)
+ var/image/ghost_image = image(icon = I.icon , icon_state = I.icon_state, loc = I.loc)
+ ghost_image.override = FALSE
+ ghost_image.alpha = 128
+ ghost_appearance = new /datum/atom_hud/alternate_appearance/basic/observers(key + "_observer", ghost_image, NONE)
+
+/datum/atom_hud/alternate_appearance/basic/Destroy()
+ . = ..()
+ QDEL_NULL(image)
+ target = null
+ if(ghost_appearance)
+ QDEL_NULL(ghost_appearance)
+
+/datum/atom_hud/alternate_appearance/basic/add_to_hud(atom/A)
+ LAZYINITLIST(A.hud_list)
+ A.hud_list[appearance_key] = image
+ . = ..()
+
+/datum/atom_hud/alternate_appearance/basic/remove_from_hud(atom/A)
+ . = ..()
+ A.hud_list -= appearance_key
+ if(. && !QDELETED(src))
+ qdel(src)
+
+/datum/atom_hud/alternate_appearance/basic/copy_overlays(atom/other, cut_old)
+ image.copy_overlays(other, cut_old)
+
+/datum/atom_hud/alternate_appearance/basic/everyone
+ add_ghost_version = TRUE
+
+/datum/atom_hud/alternate_appearance/basic/everyone/mobShouldSee(mob/M)
+ return !isdead(M)
+
+/datum/atom_hud/alternate_appearance/basic/silicons
+
+/datum/atom_hud/alternate_appearance/basic/silicons/mobShouldSee(mob/M)
+ if(issilicon(M))
+ return TRUE
+ return FALSE
+
+/datum/atom_hud/alternate_appearance/basic/observers
+ add_ghost_version = FALSE //just in case, to prevent infinite loops
+
+/datum/atom_hud/alternate_appearance/basic/observers/mobShouldSee(mob/M)
+ return isobserver(M)
+
+/datum/atom_hud/alternate_appearance/basic/one_person
+ var/mob/seer
+
+/datum/atom_hud/alternate_appearance/basic/one_person/mobShouldSee(mob/M)
+ if(M == seer)
+ return TRUE
+ return FALSE
+
+/datum/atom_hud/alternate_appearance/basic/one_person/New(key, image/I, mob/living/M)
+ ..(key, I, FALSE)
+ seer = M
diff --git a/code/game/area/area.dm b/code/game/area/area.dm
index 78637fd5e7b49..abccdde33f3d9 100644
--- a/code/game/area/area.dm
+++ b/code/game/area/area.dm
@@ -9,7 +9,7 @@
invisibility = INVISIBILITY_LIGHTING
minimap_color = null
- var/flags_alarm_state = NONE
+ var/alarm_state_flags = NONE
var/unique = TRUE
@@ -45,7 +45,7 @@
///Is this area considered inside or outside
var/outside = TRUE
- var/flags_area = NONE
+ var/area_flags = NONE
///Cameras in this area
var/list/cameras
///Keeps a lit of adjacent firelocks, used for alarms/ZAS
@@ -206,8 +206,8 @@
/area/proc/firealert()
if(name == "Space") //no fire alarms in space
return
- if(!(flags_alarm_state & ALARM_WARNING_FIRE))
- flags_alarm_state |= ALARM_WARNING_FIRE
+ if(!(alarm_state_flags & ALARM_WARNING_FIRE))
+ alarm_state_flags |= ALARM_WARNING_FIRE
update_icon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/obj/machinery/door/firedoor/D in all_fire_doors)
@@ -222,8 +222,8 @@
/area/proc/firereset()
- if(flags_alarm_state & ALARM_WARNING_FIRE)
- flags_alarm_state &= ~ALARM_WARNING_FIRE
+ if(alarm_state_flags & ALARM_WARNING_FIRE)
+ alarm_state_flags &= ~ALARM_WARNING_FIRE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
update_icon()
@@ -238,16 +238,23 @@
a.cancelAlarm("Fire", src, src)
-/area/update_icon()
+/area/update_icon_state()
+ . = ..()
var/I //More important == bottom. Fire normally takes priority over everything.
- if(flags_alarm_state && (!requires_power || power_environ)) //It either doesn't require power or the environment is powered. And there is an alarm.
- if(flags_alarm_state & ALARM_WARNING_READY) I = "alarm_ready" //Area is ready for something.
- if(flags_alarm_state & ALARM_WARNING_EVAC) I = "alarm_evac" //Evacuation happening.
- if(flags_alarm_state & ALARM_WARNING_ATMOS) I = "alarm_atmos" //Atmos breach.
- if(flags_alarm_state & ALARM_WARNING_FIRE) I = "alarm_fire" //Fire happening.
- if(flags_alarm_state & ALARM_WARNING_DOWN) I = "alarm_down" //Area is shut down.
-
- if(icon_state != I) icon_state = I //If the icon state changed, change it. Otherwise do nothing.
+ if(alarm_state_flags && (!requires_power || power_environ)) //It either doesn't require power or the environment is powered. And there is an alarm.
+ if(alarm_state_flags & ALARM_WARNING_READY)
+ I = "alarm_ready" //Area is ready for something.
+ if(alarm_state_flags & ALARM_WARNING_EVAC)
+ I = "alarm_evac" //Evacuation happening.
+ if(alarm_state_flags & ALARM_WARNING_ATMOS)
+ I = "alarm_atmos" //Atmos breach.
+ if(alarm_state_flags & ALARM_WARNING_FIRE)
+ I = "alarm_fire" //Fire happening.
+ if(alarm_state_flags & ALARM_WARNING_DOWN)
+ I = "alarm_down" //Area is shut down.
+
+ if(icon_state != I)
+ icon_state = I //If the icon state changed, change it. Otherwise do nothing.
/area/proc/powered(chan)
diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm
index 9feee726edcbe..18983064390b1 100644
--- a/code/game/area/areas/shuttles.dm
+++ b/code/game/area/areas/shuttles.dm
@@ -27,7 +27,7 @@
/area/shuttle/dropship/Initialize(mapload, ...)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/area/shuttle/dropship/alamo
name = "Dropship Alamo"
@@ -47,7 +47,7 @@
/area/shuttle/minidropship/Initialize(mapload, ...)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/area/shuttle/ert
name = "Emergency Response Team"
@@ -183,7 +183,7 @@
/area/shuttle/canterbury/Initialize(mapload, ...)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/area/shuttle/canterbury/cic
name = "Combat Information Center"
diff --git a/code/game/area/bigred.dm b/code/game/area/bigred.dm
index 0041d05b6f69b..7334736aa3ed9 100644
--- a/code/game/area/bigred.dm
+++ b/code/game/area/bigred.dm
@@ -248,12 +248,15 @@
outside = FALSE
/area/bigredv2/outside/engineering
- name = "Engineering Complex"
+ name = "West Engineering Complex"
icon_state = "engine"
ceiling = CEILING_METAL
minimap_color = MINIMAP_AREA_ENGI
outside = FALSE
+/area/bigredv2/outside/engineering/east
+ name = "East Engineering Complex"
+
/area/bigredv2/outside/storage
name = "Storage"
icon_state = "storage"
diff --git a/code/game/area/campaign_maps/jungle_outpost.dm b/code/game/area/campaign_maps/jungle_outpost.dm
index f70ef395e3e12..1d29e76ca7af3 100644
--- a/code/game/area/campaign_maps/jungle_outpost.dm
+++ b/code/game/area/campaign_maps/jungle_outpost.dm
@@ -71,6 +71,10 @@
outside = FALSE
minimap_color = MINIMAP_AREA_COLONY
+/area/campaign/jungle_outpost/outpost/bar
+ name = "\improper Bar"
+ icon_state = "bar"
+
/area/campaign/jungle_outpost/outpost/medbay
name = "\improper Medbay"
icon_state = "medbay"
diff --git a/code/game/area/campaign_maps/som_base.dm b/code/game/area/campaign_maps/som_base.dm
index 535eb62f6692d..2afe7a03fb9cb 100644
--- a/code/game/area/campaign_maps/som_base.dm
+++ b/code/game/area/campaign_maps/som_base.dm
@@ -2,7 +2,7 @@
/area/rocinante_base
name = "rocinante Polar Base"
icon_state = "dark"
- flags_area = ALWAYS_RADIO
+ area_flags = ALWAYS_RADIO
/area/rocinante_base/ground
name = "Ground"
diff --git a/code/game/area/campaign_maps/som_raiding_base.dm b/code/game/area/campaign_maps/som_raiding_base.dm
new file mode 100644
index 0000000000000..206dbb0e5c3ce
--- /dev/null
+++ b/code/game/area/campaign_maps/som_raiding_base.dm
@@ -0,0 +1,223 @@
+
+/area/campaign/som_raiding
+ icon_state = "lv-626"
+ area_flags = ALWAYS_RADIO
+ ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg')
+
+/area/campaign/som_raiding/ground
+ name = "Ground"
+ icon_state = "green"
+ always_unpowered = TRUE
+ ambience = list('sound/ambience/jungle_amb1.ogg')
+
+//Jungle
+/area/campaign/som_raiding/ground/jungle
+ name = "Central Jungle"
+ icon_state = "central"
+ minimap_color = MINIMAP_AREA_JUNGLE
+
+/area/campaign/som_raiding/ground/jungle/south_west
+ name = "Southwestern Jungle"
+ icon_state = "southwest"
+
+/area/campaign/som_raiding/ground/jungle/south_east
+ name = "Southeastern Jungle"
+ icon_state = "southeast"
+
+/area/campaign/som_raiding/ground/jungle/north_west
+ name = "Northwestern Jungle"
+ icon_state = "northwest"
+
+/area/campaign/som_raiding/ground/jungle/north_east
+ name = "Northeastern Jungle"
+ icon_state = "northeast"
+
+/area/campaign/som_raiding/ground/jungle/west
+ name = "Western Jungle"
+ icon_state = "west"
+
+/area/campaign/som_raiding/ground/jungle/south
+ name = "Southern Jungle"
+ icon_state = "south"
+
+/area/campaign/som_raiding/ground/jungle/east
+ name = "Eastern Jungle"
+ icon_state = "east"
+
+/area/campaign/som_raiding/ground/jungle/north
+ name = "Northern Jungle"
+ icon_state = "north"
+
+//river
+/area/campaign/som_raiding/ground/river
+ name = "\improper Southern River"
+ icon_state = "blueold"
+
+/area/campaign/som_raiding/ground/river/north
+ name = "\improper Northern River"
+
+/area/campaign/som_raiding/ground/river/west
+ name = "\improper Western River"
+
+/area/campaign/som_raiding/ground/river/east
+ name = "\improper Eastern River"
+
+/area/campaign/som_raiding/ground/river/lake
+ name = "\improper Southern Lake"
+
+//outpost
+/area/campaign/som_raiding/cave
+ name = "\improper Mountain"
+ icon_state = "cave"
+ ceiling = CEILING_UNDERGROUND
+ outside = FALSE
+ minimap_color = MINIMAP_AREA_CAVES
+
+/area/campaign/som_raiding/cave/tunnel
+ name = "\improper Old tunnels"
+ icon_state = "explored"
+
+//outpost
+/area/campaign/som_raiding/outpost
+ name = "\improper Outpost"
+ icon_state = "green"
+ ceiling = CEILING_UNDERGROUND_METAL
+ outside = FALSE
+ minimap_color = MINIMAP_AREA_COLONY
+
+/area/campaign/som_raiding/outpost/firing_range
+ name = "\improper Firing range"
+
+/area/campaign/som_raiding/outpost/construction
+ name = "\improper Construction site"
+
+/area/campaign/som_raiding/outpost/central_corridor
+ name = "\improper Central corridor"
+
+/area/campaign/som_raiding/outpost/maintenance
+ name = "\improper Southwest maintenance"
+ minimap_color = MINIMAP_AREA_CAVES
+ icon_state = "maint_security_starboard"
+
+/area/campaign/som_raiding/outpost/maintenance/engie
+ name = "\improper Engineering maintenance"
+ icon_state = "maint_engine"
+
+/area/campaign/som_raiding/outpost/maintenance/operation
+ name = "\improper Operations maintenance"
+ icon_state = "apmaint"
+
+/area/campaign/som_raiding/outpost/maintenance/cic
+ name = "\improper CIC maintenance"
+ icon_state = "fpmaint"
+
+/area/campaign/som_raiding/outpost/maintenance/req
+ name = "\improper Requisitions maintenance"
+ icon_state = "maint_cargo"
+
+/area/campaign/som_raiding/outpost/maintenance/med
+ name = "\improper medbay maintenance"
+ icon_state = "maint_medbay"
+
+/area/campaign/som_raiding/outpost/medbay
+ name = "\improper Medbay"
+ icon_state = "medbay"
+ minimap_color = MINIMAP_AREA_MEDBAY
+
+/area/campaign/som_raiding/outpost/security
+ name = "\improper Armoury"
+ icon_state = "security"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/campaign/som_raiding/outpost/security/south_post
+ name = "\improper South security checkpoint"
+
+/area/campaign/som_raiding/outpost/security/southeast_post
+ name = "\improper Southeast security checkpoint"
+
+/area/campaign/som_raiding/outpost/security/west_post
+ name = "\improper West security checkpoint"
+
+/area/campaign/som_raiding/outpost/security/north_post
+ name = "\improper North security checkpoint"
+
+/area/campaign/som_raiding/outpost/security/cargo_post
+ name = "\improper Caro security checkpoint"
+
+/area/campaign/som_raiding/outpost/command
+ name = "\improper Operations"
+ icon_state = "bridge"
+ minimap_color = MINIMAP_AREA_COMMAND
+
+/area/campaign/som_raiding/outpost/command/captain
+ name = "\improper Executive Office"
+ icon_state = "captain"
+
+/area/campaign/som_raiding/outpost/command/telecom
+ name = "\improper Telecommunications"
+ icon_state = "tcomms"
+
+/area/campaign/som_raiding/outpost/command/cic
+ name = "\improper Combat Information Centre"
+
+/area/campaign/som_raiding/outpost/command/north
+ name = "\improper North offices"
+
+/area/campaign/som_raiding/outpost/command/living
+ name = "\improper Officer's quarters"
+
+/area/campaign/som_raiding/outpost/engineering
+ name = "\improper Engineering"
+ icon_state = "engine_smes"
+ minimap_color = MINIMAP_AREA_ENGI
+
+/area/campaign/som_raiding/outpost/living
+ name = "\improper Barracks"
+ icon_state = "Sleep"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/campaign/som_raiding/outpost/living/briefing
+ name = "\improper Briefing room"
+ icon_state = "conference"
+
+/area/campaign/som_raiding/outpost/living/bathroom
+ name = "\improper Bathrooms"
+ icon_state = "restrooms"
+
+/area/campaign/som_raiding/outpost/living/canteen
+ name = "\improper Canteen"
+ icon_state = "cafeteria"
+
+/area/campaign/som_raiding/outpost/living/kitchen
+ name = "\improper Kitchen"
+ icon_state = "kitchen"
+
+/area/campaign/som_raiding/outpost/req
+ name = "\improper Main cargo bay"
+ icon_state = "quart"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/campaign/som_raiding/outpost/req/north
+ name = "\improper North cargo bay"
+
+/area/campaign/som_raiding/outpost/req/aux
+ name = "\improper North auxiliary storage"
+ icon_state = "quart"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/campaign/som_raiding/outpost/req/secure
+ name = "\improper Secure storage"
+ icon_state = "quart"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/campaign/som_raiding/outpost/req/qm
+ name = "\improper Quartermaster's Office"
+ icon_state = "quartoffice"
+
+/area/campaign/som_raiding/outpost/tunnel
+ name = "\improper South tunnel"
+ icon_state = "explored"
+ ceiling = CEILING_UNDERGROUND
+
+/area/campaign/som_raiding/outpost/tunnel/west
+ name = "\improper West tunnel"
diff --git a/code/game/area/daedalusprison.dm b/code/game/area/daedalusprison.dm
new file mode 100644
index 0000000000000..ba9fb7c836859
--- /dev/null
+++ b/code/game/area/daedalusprison.dm
@@ -0,0 +1,414 @@
+// Daedalus Prison Areas
+
+//Caves
+/area/daedalusprison/caves
+ name = "Caves"
+ icon_state = "cave"
+ ambience = list('sound/ambience/ambimine.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambisin4.ogg')
+ ceiling = CEILING_DEEP_UNDERGROUND
+ outside = FALSE
+ minimap_color = MINIMAP_AREA_CAVES
+ always_unpowered = TRUE
+
+/area/daedalusprison/caves/rock
+ name = "Enclosed Area"
+ icon_state = "transparent"
+
+/area/daedalusprison/caves/northwest
+ name = "Northwestern Caves"
+ icon_state = "northwest2"
+
+/area/daedalusprison/caves/northwest/garbledradio
+ ceiling = CEILING_UNDERGROUND
+
+/area/daedalusprison/caves/north
+ name = "Northern Caves"
+ icon_state = "north2"
+
+/area/daedalusprison/caves/north/garbledradio
+ ceiling = CEILING_UNDERGROUND
+
+/area/daedalusprison/caves/nukestorage
+ name = "Nuclear Storage"
+ icon_state = "nuke_storage"
+ ceiling = CEILING_DEEP_UNDERGROUND_METAL
+ minimap_color = MINIMAP_AREA_ENGI_CAVE
+ always_unpowered = FALSE
+
+/area/daedalusprison/caves/research
+ name = "Biologcal Research Facility"
+ icon_state = "research"
+ ceiling = CEILING_DEEP_UNDERGROUND_METAL
+ minimap_color = MINIMAP_AREA_RESEARCH_CAVE
+ always_unpowered = FALSE
+
+/area/daedalusprison/caves/northeast
+ name = "Northeastern Caves"
+ icon_state = "northeast2"
+
+/area/daedalusprison/caves/northeast/garbledradio
+ ceiling = CEILING_UNDERGROUND
+
+/area/daedalusprison/caves/southwest
+ name = "Southwestern Caves"
+ icon_state = "southwest2"
+
+/area/daedalusprison/caves/southwest/garbledradio
+ ceiling = CEILING_UNDERGROUND
+
+/area/daedalusprison/caves/south
+ name = "Southern Tunnel"
+ icon_state = "south2"
+ ceiling = CEILING_UNDERGROUND
+
+/area/daedalusprison/caves/east
+ name = "Eastern Tunnel"
+ icon_state = "east2"
+
+//Outside Area
+/area/daedalusprison/outside
+ name = "Colony Grounds"
+ icon_state = "cliff_blocked"
+ ceiling = CEILING_NONE
+ outside = TRUE
+ minimap_color = MINIMAP_AREA_COLONY
+ always_unpowered = TRUE
+ temperature = ICE_COLONY_TEMPERATURE
+
+/area/daedalusprison/outside/southeast
+ name = "Southeastern Colony"
+ icon_state = "southeast"
+
+/area/daedalusprison/outside/south
+ name = "Southern Colony"
+ icon_state = "south"
+
+/area/daedalusprison/outside/southwest
+ name = "Southwestern Colony"
+ icon_state = "southeast"
+
+/area/daedalusprison/outside/east
+ name = "Eastern Grounds"
+ icon_state = "east"
+
+/area/daedalusprison/outside/northeast
+ name = "Northeastern Grounds"
+ icon_state = "northeast"
+
+/area/daedalusprison/outside/north
+ name = "Northern Grounds"
+ icon_state = "north"
+
+//Inside area parent, not used.
+/area/daedalusprison/inside
+ name = "Inside"
+ icon_state = "red"
+ ceiling = CEILING_METAL
+ outside = FALSE
+
+/area/daedalusprison/inside/engineering
+ name = "Engineering"
+ icon_state = "engine"
+ minimap_color = MINIMAP_AREA_ENGI
+
+/area/daedalusprison/inside/colonydorms
+ name = "Colony Dorms"
+ icon_state = "Sleep"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/bar
+ name = "Colony Bar"
+ icon_state = "bar"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/cargo
+ name = "Colony Cargo"
+ icon_state = "primarystorage"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/daedalusprison/inside/colonyauxstorage
+ name = "Colony Auxillary Storage"
+ icon_state = "storage"
+ always_unpowered = TRUE
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/daedalusprison/inside/bunker
+ name = "Landing Zone Bunker"
+ icon_state = "shuttlered"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/bunker/west
+ name = "Western Bunker"
+
+/area/daedalusprison/inside/bunker/center
+ name = "Central Bunker"
+
+/area/daedalusprison/inside/bunker/east
+ name = "Eastern Bunker"
+
+/area/daedalusprison/inside/prisonshower
+ name = "Prison Showers"
+ icon_state = "decontamination"
+ minimap_color = MINIMAP_AREA_CELL_MED
+
+/area/daedalusprison/inside/habitationnorth
+ name = "Prison North Habitation"
+ icon_state = "cells_med_n"
+ minimap_color = MINIMAP_AREA_CELL_MED
+
+/area/daedalusprison/inside/habitationsouth
+ name = "Prison South Habitation"
+ icon_state = "cells_med_s"
+ minimap_color = MINIMAP_AREA_CELL_MED
+
+/area/daedalusprison/inside/studyroom
+ name = "Prison Study Room"
+ icon_state = "library"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/mining
+ name = "Prison Mineral Processing"
+ icon_state = "mining"
+ ceiling = CEILING_OBSTRUCTED
+ minimap_color = MINIMAP_AREA_CELL_MED
+
+/area/daedalusprison/inside/westernbooth
+ name = "Prison Western Security Booth"
+ icon_state = "brig"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/westcomputerlab
+ name = "Prison Western Computer Lab"
+ icon_state = "server"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/substation
+ name = "Prison Substation"
+ icon_state = "substation"
+ minimap_color = MINIMAP_AREA_ENGI
+
+/area/daedalusprison/inside/prisongarden
+ name = "Prison Garden"
+ icon_state = "garden"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/centralhalls
+ name = "Prison Central Halls"
+ icon_state = "hallC1"
+
+/area/daedalusprison/inside/laundromat
+ name = "Prison Laundromat"
+ icon_state = "LP"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/laundromat/collapsedroof
+ outside = TRUE
+ ceiling = CEILING_NONE
+ always_unpowered = TRUE
+
+/area/daedalusprison/inside/mechanicshop
+ name = "Prison Mechanical Shop"
+ icon_state = "engine"
+ minimap_color = MINIMAP_AREA_ENGI
+
+/area/daedalusprison/inside/staffrestroom
+ name = "Prison Staff Restroom"
+ icon_state = "toilet"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/auxstorage
+ name = "Prison Auxillary Storage"
+ icon_state = "storage"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/daedalusprison/inside/staffbreakroom
+ name = "Prison Staff Breakroom"
+ icon_state = "Holodeck"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/northclass
+ name = "Prison Northern Classroom"
+ icon_state = "law"
+ minimap_color = MINIMAP_AREA_RESEARCH
+
+/area/daedalusprison/inside/southclass
+ name = "Prison Southern Classroom"
+ icon_state = "law"
+ minimap_color = MINIMAP_AREA_RESEARCH
+
+/area/daedalusprison/inside/centralbooth
+ name = "Prison Central Security Booth"
+ icon_state = "brig"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/recreation
+ name = "Prison Recreation"
+ icon_state = "showroom"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/janitorial
+ name = "Prison Janitorial Room"
+ icon_state = "janitor"
+ minimap_color = MINIMAP_AREA_RESEARCH
+
+/area/daedalusprison/inside/freezer
+ name = "Prison Freezer"
+ icon_state = "kitchen"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/kitchen
+ name = "Prison Kitchen"
+ icon_state = "kitchen"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/cafeteria
+ name = "Prison Cafeteria"
+ icon_state = "cafeteria"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/sportstorage
+ name = "Prison Sports Storage"
+ icon_state = "auxstorage"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/daedalusprison/inside/northmeetingroom
+ name = "Prison Meeting Room"
+ icon_state = "conference"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/library
+ name = "Prison Library"
+ icon_state = "library"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/execution
+ name = "Prison Execution"
+ icon_state = "sec_backroom"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/basketball
+ name = "Prison Basketball Court"
+ icon_state = "anog"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/lobby
+ name = "Prison Lobby"
+ icon_state = "red"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/corporateoffice
+ name = "Liason Office"
+ icon_state = "blueold"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/southmeetingroom
+ name = "Corporate Meeting Room"
+ icon_state = "party"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/garage
+ name = "Prison Garage"
+ icon_state = "garage"
+ minimap_color = MINIMAP_AREA_REQ
+
+/area/daedalusprison/inside/easternhalls
+ name = "Prison Eastern Hallways"
+ icon_state = "hallS"
+
+/area/daedalusprison/inside/gym
+ name = "Prison Gym"
+ icon_state = "bluenew"
+ minimap_color = MINIMAP_AREA_ESCAPE
+
+/area/daedalusprison/inside/chapel
+ name = "Prison Chapel"
+ icon_state = "chapel"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/security
+ name = "Security"
+ icon_state = "brig"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/security/easternbooth
+ name = "Prison Eastern Security Booth"
+
+/area/daedalusprison/inside/security/secbreakroom
+ name = "Prison Security Break Room"
+
+/area/daedalusprison/inside/security/cameras
+ name = "Prison Camera Center"
+
+/area/daedalusprison/inside/security/warden
+ name = "Prison Warden Office"
+
+/area/daedalusprison/inside/security/office
+ name = "Prison Security Office"
+
+/area/daedalusprison/inside/security/interrogation
+ name = "Prison Interrogation"
+ icon_state = "interrogation"
+
+/area/daedalusprison/inside/security/medsec
+ name = "Prison Medbay Security"
+ ceiling = CEILING_OBSTRUCTED
+
+/area/daedalusprison/inside/medical
+ name = "Prison Infirmary"
+ icon_state = "medbay"
+ minimap_color = MINIMAP_AREA_MEDBAY
+ ceiling = CEILING_OBSTRUCTED
+
+/area/daedalusprison/inside/medical/chemistry
+ name = "Prison Chemistry"
+
+/area/daedalusprison/inside/medical/treatment
+ name = "Prison Infirmary Treatment"
+
+/area/daedalusprison/inside/barracks
+ name = "Prison Security Barracks"
+ icon_state = "armory"
+ minimap_color = MINIMAP_AREA_SEC_CAVE
+
+/area/daedalusprison/inside/garden
+ name = "Hydroponics Garden"
+ icon_state = "garden"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/hydroponics
+ name = "Hydroponics"
+ icon_state = "hydro"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/hydroponicstesting
+ name = "Hydroponics Testing"
+ icon_state = "hydro_north"
+ minimap_color = MINIMAP_AREA_LIVING
+
+/area/daedalusprison/inside/seccheckpoint
+ name = "Security Checkpoint"
+ icon_state = "brig"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/secoffices
+ name = "Security Checkpoint Offices"
+ icon_state = "brig"
+ minimap_color = MINIMAP_AREA_SEC
+
+/area/daedalusprison/inside/pmcdropship
+ name = "Crashed PMC Dropship"
+ icon_state = "shuttle"
+ minimap_color = MINIMAP_AREA_COLONY
+ always_unpowered = TRUE
+
+/area/daedalusprison/inside/landingzoneone
+ name = "Landing Zone One"
+ icon_state = "landingzone1"
+ area_flags = NO_DROPPOD
+ minimap_color = MINIMAP_AREA_LZ
+
+/area/daedalusprison/inside/telecomms
+ name = "Telecomms"
+ icon_state = "tcomsatcham"
+ area_flags = NO_DROPPOD
+ requires_power = FALSE
diff --git a/code/game/area/desertdam.dm b/code/game/area/desertdam.dm
index 29b33c187f82c..26de7e7b3ee19 100644
--- a/code/game/area/desertdam.dm
+++ b/code/game/area/desertdam.dm
@@ -1004,13 +1004,13 @@
name = "LZ1 'Admin'"
icon_state = "tcomsatcham"
requires_power = 0
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
/area/desert_dam/landing/console2
name = "LZ2 'Supply'"
icon_state = "tcomsatcham"
requires_power = 0
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
//Transit Shuttle
/area/shuttle/tri_trans1/alpha
diff --git a/code/game/area/general.dm b/code/game/area/general.dm
index 51f7079f48816..ba712738435ab 100644
--- a/code/game/area/general.dm
+++ b/code/game/area/general.dm
@@ -10,7 +10,7 @@
ambience = list('sound/ambience/ambispace.ogg')
temperature = TCMB
pressure = 0
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
///What type of debuff do we apply when someone enters this area?
var/debuff_type = /datum/status_effect/spacefreeze
@@ -42,7 +42,7 @@
/area/shuttle //DO NOT TURN THE dynamic_lighting STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
requires_power = FALSE
outside = FALSE
- flags_area = OB_CAS_IMMUNE
+ area_flags = OB_CAS_IMMUNE
minimap_color = MINIMAP_AREA_LZ
/area/shuttle/arrival
@@ -1201,7 +1201,7 @@
requires_power = 0
name = "Abandoned Test Room"
icon_state = "storage"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
//DJSTATION
diff --git a/code/game/area/lawankaoutpost.dm b/code/game/area/lawankaoutpost.dm
index 4284779ac0317..e547c2ad08d24 100644
--- a/code/game/area/lawankaoutpost.dm
+++ b/code/game/area/lawankaoutpost.dm
@@ -210,11 +210,11 @@
/area/lawankaoutpost/colony/landingzoneone
name = "Landing Zone One"
icon_state = "landingzone1"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
/area/lawankaoutpost/colony/landingzonetwo
name = "Landing Zone Two"
icon_state = "landingzone2"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
diff --git a/code/game/area/lv624.dm b/code/game/area/lv624.dm
index b7519f1bce350..1d51f20e1870c 100644
--- a/code/game/area/lv624.dm
+++ b/code/game/area/lv624.dm
@@ -477,17 +477,17 @@
/area/lv624/lazarus/console
name = "\improper Shuttle Console"
icon_state = "tcomsatcham"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
requires_power = FALSE
/area/lv624/lazarus/spaceport
name = "\improper Eastern Space Port"
icon_state = "landingzone1"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
/area/lv624/lazarus/spaceport2
name = "\improper Western Space Port"
icon_state = "landingzone2"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
diff --git a/code/game/area/magmoor_digsite.dm b/code/game/area/magmoor_digsite.dm
index ea23beff76252..aa128e504788a 100644
--- a/code/game/area/magmoor_digsite.dm
+++ b/code/game/area/magmoor_digsite.dm
@@ -22,7 +22,7 @@
/area/magmoor/volcano
name = "Magmoor Central Fissure"
ceiling = CEILING_DEEP_UNDERGROUND
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
always_unpowered = TRUE
//Caves
diff --git a/code/game/area/mainship.dm b/code/game/area/mainship.dm
index 5c9cc6b3af9cb..7ea34503b97b9 100644
--- a/code/game/area/mainship.dm
+++ b/code/game/area/mainship.dm
@@ -157,6 +157,11 @@
icon_state = "livingspace"
minimap_color = MINIMAP_AREA_COMMAND
+/area/mainship/living/mechpilotquarters
+ name = "Mech Pilot Quarters"
+ icon_state = "blueold"
+ minimap_color = MINIMAP_AREA_COMMAND
+
/area/mainship/hallways/exoarmor
name = "Vehicle Armor Storage"
icon_state = "exoarmor"
diff --git a/code/game/area/orion_outpost.dm b/code/game/area/orion_outpost.dm
index 76830cb9f7e99..b13109feb1feb 100644
--- a/code/game/area/orion_outpost.dm
+++ b/code/game/area/orion_outpost.dm
@@ -30,7 +30,7 @@
/area/orion_outpost/surface/landing_pad
name = "Landing Pad 1"
icon_state = "landing_pad"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
ceiling = CEILING_METAL
outside = FALSE
minimap_color = MINIMAP_AREA_LZ
@@ -46,7 +46,7 @@
/area/orion_outpost/surface/landing_pad_2
name = "Landing Pad 2"
icon_state = "landing_pad"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
ceiling = CEILING_METAL
outside = FALSE
minimap_color = MINIMAP_AREA_LZ
diff --git a/code/game/area/patricks_rest.dm b/code/game/area/patricks_rest.dm
index 6e3942ab9f534..f0d3c28c581b0 100644
--- a/code/game/area/patricks_rest.dm
+++ b/code/game/area/patricks_rest.dm
@@ -30,7 +30,7 @@
/area/patricks_rest/surface/landing_pad
name = "Landing Pad 1"
icon_state = "landing_pad"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
ceiling = CEILING_METAL
outside = FALSE
minimap_color = MINIMAP_AREA_LZ
@@ -45,7 +45,7 @@
/area/patricks_rest/surface/landing_pad_2
name = "Landing Pad 2"
icon_state = "landing_pad"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
ceiling = CEILING_METAL
outside = FALSE
minimap_color = MINIMAP_AREA_LZ
diff --git a/code/game/area/slumbridge.dm b/code/game/area/slumbridge.dm
index f0b9884935b49..c3d75e0723ebe 100644
--- a/code/game/area/slumbridge.dm
+++ b/code/game/area/slumbridge.dm
@@ -331,17 +331,17 @@
/area/slumbridge/landingzoneone
name = "Landing Zone One"
icon_state = "landingzone1"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
/area/slumbridge/landingzonetwo
name = "Landing Zone Two"
icon_state = "landingzone2"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
minimap_color = MINIMAP_AREA_LZ
/area/slumbridge/console
name = "\improper Shuttle Console"
icon_state = "tcomsatcham"
- flags_area = NO_DROPPOD
+ area_flags = NO_DROPPOD
requires_power = FALSE
diff --git a/code/game/area/sulaco.dm b/code/game/area/sulaco.dm
index fbe0db09b7690..904520db7757b 100644
--- a/code/game/area/sulaco.dm
+++ b/code/game/area/sulaco.dm
@@ -338,7 +338,7 @@
/area/shuttle/drop1/lz1
name = "Alamo Landing Zone"
icon_state = "away1"
- flags_area = NONE
+ area_flags = NONE
/area/shuttle/drop2/Enter(atom/movable/arrived, direction)
if(istype(arrived, /obj/structure/barricade))
@@ -376,7 +376,7 @@
/area/shuttle/drop2/lz2
name = "Normandy Landing Zone"
icon_state = "away2"
- flags_area = NONE
+ area_flags = NONE
diff --git a/code/game/atoms.dm b/code/game/atoms/_atom.dm
similarity index 83%
rename from code/game/atoms.dm
rename to code/game/atoms/_atom.dm
index e5aa3e93f3ee2..49666d6277de7 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms/_atom.dm
@@ -4,7 +4,7 @@
appearance_flags = TILE_BOUND
var/level = 2
- var/flags_atom = NONE
+ var/atom_flags = NONE
var/datum/reagents/reagents = null
var/list/fingerprints
@@ -39,9 +39,6 @@
///How much does this atom block the explosion's shock wave.
var/explosion_block = 0
- ///overlays managed by update_overlays() to prevent removing overlays that weren't added by the same proc
- var/list/managed_overlays
-
var/datum/component/orbiter/orbiters
var/datum/proximity_monitor/proximity_monitor
@@ -122,6 +119,11 @@
///Cooldown for telling someone they're buckled
COOLDOWN_DECLARE(buckle_message_cooldown)
+ ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays.
+ var/list/managed_vis_overlays
+ ///The list of alternate appearances for this atom
+ var/list/alternate_appearances
+
/*
We actually care what this returns, since it can return different directives.
Not specifically here, but in other variations of this. As a general safety,
@@ -142,6 +144,11 @@ directive is properly returned.
if(isturf(loc))
loc.fingerprints = fingerprints
+ if(alternate_appearances)
+ for(var/K in alternate_appearances)
+ var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K]
+ AA.remove_from_hud(src)
+
return ..()
//===========================================================================
@@ -228,6 +235,7 @@ directive is properly returned.
/atom/proc/emp_act(severity)
+ SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
return
@@ -356,32 +364,6 @@ directive is properly returned.
SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .)
-
-/// Updates the icon of the atom
-/atom/proc/update_icon()
- var/signalOut = SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON)
-
- if(!(signalOut & COMSIG_ATOM_NO_UPDATE_ICON_STATE))
- update_icon_state()
-
- if(!(signalOut & COMSIG_ATOM_NO_UPDATE_OVERLAYS))
- var/list/new_overlays = update_overlays()
- if(managed_overlays)
- cut_overlay(managed_overlays)
- managed_overlays = null
- if(length(new_overlays))
- managed_overlays = new_overlays
- add_overlay(new_overlays)
-
-/// Updates the icon state of the atom
-/atom/proc/update_icon_state()
-
-/// Updates the overlays of the atom
-/atom/proc/update_overlays()
- SHOULD_CALL_PARENT(TRUE)
- . = list()
- SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .)
-
/// Checks if the colors given are different and if so causes a greyscale icon update
/// The colors argument can be either a list or the full color string
/atom/proc/set_greyscale_colors(list/colors, update=TRUE)
@@ -434,7 +416,7 @@ directive is properly returned.
*/
/* RUTGMC DELETION
/atom/proc/ex_act(severity, epicenter_dist, impact_range)
- if(!(flags_atom & PREVENT_CONTENTS_EXPLOSION))
+ if(!(atom_flags & PREVENT_CONTENTS_EXPLOSION))
contents_explosion(severity, epicenter_dist, impact_range)
SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, epicenter_dist, impact_range)
*/
@@ -442,12 +424,21 @@ directive is properly returned.
/atom/proc/fire_act()
return
+///Effects of lava. Return true where we want the lava to keep processing
+/atom/proc/lava_act()
+ if(resistance_flags & INDESTRUCTIBLE)
+ return FALSE
+ fire_act()
+ return TRUE
/atom/proc/hitby(atom/movable/AM, speed = 5)
if(density)
AM.stop_throw()
return TRUE
+///Psionic interaction with this atom
+/atom/proc/psi_act(psi_power, mob/living/user)
+ return
/atom/proc/GenerateTag()
return
@@ -647,9 +638,9 @@ directive is properly returned.
/atom/proc/Initialize(mapload, ...)
SHOULD_CALL_PARENT(TRUE)
SHOULD_NOT_SLEEP(TRUE)
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("Warning: [src]([type]) initialized multiple times!")
- flags_atom |= INITIALIZED
+ atom_flags |= INITIALIZED
update_greyscale()
@@ -695,17 +686,138 @@ directive is properly returned.
SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir)
dir = newdir
-
/atom/vv_get_dropdown()
. = ..()
- . += "---"
- var/turf/curturf = get_turf(src)
- if(curturf)
- .["Jump to"] = "?_src_=holder;[HrefToken()];observecoordjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
- .["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]"
- .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]"
- .["Modify Filters"] = "?_src_=vars;[HrefToken()];filteredit=[REF(src)]"
- .["Modify Greyscale Colors"] = "?_src_=vars;[HrefToken()];modify_greyscale=[REF(src)]"
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_ATOM_JUMP_TO, "Jump To")
+ VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform")
+ VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add reagent")
+ VV_DROPDOWN_OPTION(VV_HK_MODIFY_FILTERS, "Modify Filters")
+ VV_DROPDOWN_OPTION(VV_HK_MODIFY_GREYSCALE_COLORS, "Modify Greyscale Colors")
+ VV_DROPDOWN_OPTION(VV_HK_EDIT_COLOR_MATRIX, "Edit Color as Matrix")
+ VV_DROPDOWN_OPTION(VV_HK_TEST_MATRIXES, "Test Matrices")
+
+/atom/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_ATOM_JUMP_TO])
+ if(!check_rights(NONE))
+ return
+ var/x = text2num(href_list["X"])
+ var/y = text2num(href_list["Y"])
+ var/z = text2num(href_list["Z"])
+ var/client/C = usr.client
+
+ if(x == 0 && y == 0 && z == 0)
+ return
+
+ var/message
+ if(!isobserver(usr))
+ usr.client.holder.admin_ghost()
+ message = TRUE
+
+ var/mob/dead/observer/O = C.mob
+ var/turf/T = locate(x, y, z)
+ O.forceMove(T)
+
+ if(message)
+ log_admin("[key_name(O)] jumped to coordinates [AREACOORD(T)].")
+ message_admins("[ADMIN_TPMONTY(O)] jumped to coordinates [ADMIN_VERBOSEJMP(T)].")
+
+ if(href_list[VV_HK_MODIFY_TRANSFORM])
+ if(!check_rights(R_DEBUG))
+ return
+ if(!istype(src))
+ return
+ var/result = input(usr, "Choose the transformation to apply", "Modify Transform") as null|anything in list("Scale","Translate","Rotate")
+ var/matrix/M = src.transform
+ switch(result)
+ if("Scale")
+ var/x = input(usr, "Choose x mod", "Modify Transform") as null|num
+ var/y = input(usr, "Choose y mod", "Modify Transform") as null|num
+ if(x == 0 || y == 0)
+ if(alert("You've entered 0 as one of the values, are you sure?", "Modify Transform", "Yes", "No") != "Yes")
+ return
+ if(!isnull(x) && !isnull(y))
+ src.transform = M.Scale(x,y)
+ if("Translate")
+ var/x = input(usr, "Choose x mod", "Modify Transform") as null|num
+ var/y = input(usr, "Choose y mod", "Modify Transform") as null|num
+ if(x == 0 && y == 0)
+ return
+ if(!isnull(x) && !isnull(y))
+ src.transform = M.Translate(x,y)
+ if("Rotate")
+ var/angle = input(usr, "Choose angle to rotate", "Modify Transform") as null|num
+ if(angle == 0)
+ if(alert("You've entered 0 as one of the values, are you sure?", "Warning", "Yes", "No") != "Yes")
+ return
+ if(!isnull(angle))
+ src.transform = M.Turn(angle)
+ log_admin("[key_name(usr)] has used [result] transformation on [src].")
+ message_admins("[ADMIN_TPMONTY(usr)] has used [result] transformation on [src].")
+
+ if(href_list[VV_HK_ADD_REAGENT])
+ if(!check_rights(R_VAREDIT))
+ return
+ if(!reagents)
+ var/amount = input(usr, "Specify the reagent size of [src]", "Set Reagent Size", 50) as num
+ if(amount)
+ create_reagents(amount)
+ if(reagents)
+ var/chosen_id
+ var/list/reagent_options = sortList(GLOB.chemical_reagents_list)
+ switch(alert(usr, "Choose a method.", "Add Reagents", "Enter ID", "Choose ID"))
+ if("Enter ID")
+ var/valid_id
+ while(!valid_id)
+ chosen_id = stripped_input(usr, "Enter the ID of the reagent you want to add.")
+ if(!chosen_id) //Get me out of here!
+ break
+ for(var/ID in reagent_options)
+ if(ID == chosen_id)
+ valid_id = TRUE
+ if(!valid_id)
+ to_chat(usr, span_warning("A reagent with that ID doesn't exist!"))
+ if("Choose ID")
+ chosen_id = input(usr, "Choose a reagent to add.", "Add Reagent") as null|anything in reagent_options
+ if(chosen_id)
+ var/amount = input(usr, "Choose the amount to add.", "Add Reagent", reagents.maximum_volume) as num
+ if(amount)
+ reagents.add_reagent(chosen_id, amount)
+ log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src].")
+ message_admins("[ADMIN_TPMONTY(usr)] has added [amount] units of [chosen_id] to [src].")
+
+ if(href_list[VV_HK_MODIFY_FILTERS])
+ if(!check_rights(R_VAREDIT))
+ return
+ var/client/C = usr.client
+ C?.open_filter_editor(src)
+
+ if(href_list[VV_HK_MODIFY_GREYSCALE_COLORS])
+ if(!check_rights(R_DEBUG))
+ return
+ var/datum/greyscale_modify_menu/menu = new(usr)
+ menu.ui_interact(usr)
+
+ if(href_list[VV_HK_EDIT_COLOR_MATRIX])
+ if(!check_rights(R_VAREDIT))
+ return
+ usr.client?.open_color_matrix_editor(src)
+
+ if(href_list[VV_HK_TEST_MATRIXES])
+ if(!check_rights(R_VAREDIT))
+ return
+ usr.client?.open_matrix_tester(src)
+
+/atom/vv_get_header()
+ . = ..()
+ var/refid = REF(src)
+ . += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "[src]")]"
+ . += " <<[dir2text(dir) || dir]>>"
/atom/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, arrived, old_loc, old_locs)
@@ -881,17 +993,17 @@ directive is properly returned.
return TRUE
-
-// For special click interactions (take first item out of container, quick-climb, etc.)
-/atom/proc/specialclick(mob/living/carbon/user)
- return
-
/atom/proc/prepare_huds()
hud_list = new
for(var/hud in hud_possible) //Providing huds.
- var/image/new_hud = image('icons/mob/hud.dmi', src, "")
- new_hud.appearance_flags = KEEP_APART
- hud_list[hud] = new_hud
+ var/hint = hud_possible[hud]
+ switch(hint)
+ if(HUD_LIST_LIST)
+ hud_list[hud] = list()
+ else
+ var/image/I = image('icons/mob/hud.dmi', src, "")
+ I.appearance_flags = RESET_COLOR|RESET_TRANSFORM|KEEP_APART
+ hud_list[hud] = I
/**
* If this object has lights, turn it on/off.
@@ -980,3 +1092,7 @@ directive is properly returned.
///Returns the hard armor for the given atom. If human and a limb is specified, gets the armor for that specific limb.
/atom/proc/get_hard_armor(armor_type, proj_def_zone)
return
+
+///Interaction for using a grab on an atom
+/atom/proc/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ return
diff --git a/code/game/atoms/atom_appearance.dm b/code/game/atoms/atom_appearance.dm
new file mode 100644
index 0000000000000..76a8268a932a1
--- /dev/null
+++ b/code/game/atoms/atom_appearance.dm
@@ -0,0 +1,112 @@
+/atom
+ ///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc. Single items are stored on their own, not in a list.
+ var/list/managed_overlays
+
+/**
+ * Updates the appearence of the icon
+ *
+ * Mostly delegates to update_name, update_desc, and update_icon
+ *
+ * Arguments:
+ * - updates: A set of bitflags dictating what should be updated. Defaults to [ALL]
+ */
+/atom/proc/update_appearance(updates=ALL)
+ SHOULD_NOT_SLEEP(TRUE)
+ SHOULD_CALL_PARENT(TRUE)
+
+ . = NONE
+ updates &= ~SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_APPEARANCE, updates)
+ if(updates & UPDATE_NAME)
+ . |= update_name(updates)
+ if(updates & UPDATE_DESC)
+ . |= update_desc(updates)
+ if(updates & UPDATE_ICON)
+ . |= update_icon(updates)
+
+/// Updates the name of the atom
+/atom/proc/update_name(updates=ALL)
+ SHOULD_CALL_PARENT(TRUE)
+ return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_NAME, updates)
+
+/// Updates the description of the atom
+/atom/proc/update_desc(updates=ALL)
+ SHOULD_CALL_PARENT(TRUE)
+ return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_DESC, updates)
+
+/// Updates the icon of the atom
+/atom/proc/update_icon(updates=ALL)
+ SHOULD_CALL_PARENT(TRUE)
+
+ . = NONE
+ updates &= ~SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON, updates)
+ if(updates & UPDATE_ICON_STATE)
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON_STATE)
+ update_icon_state()
+ . |= UPDATE_ICON_STATE
+
+ if(updates & UPDATE_OVERLAYS)
+ if(LAZYLEN(managed_vis_overlays))
+ SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
+
+ var/list/new_overlays = update_overlays(updates)
+ var/nulls = 0
+ for(var/i in 1 to length(new_overlays))
+ var/atom/maybe_not_an_atom = new_overlays[i]
+ if(isnull(maybe_not_an_atom))
+ nulls++
+ continue
+ if(istext(maybe_not_an_atom) || isicon(maybe_not_an_atom))
+ continue
+ new_overlays[i] = maybe_not_an_atom.appearance
+ if(nulls)
+ for(var/i in 1 to nulls)
+ new_overlays -= null
+
+ var/identical = FALSE
+ var/new_length = length(new_overlays)
+ if(!managed_overlays && !new_length)
+ identical = TRUE
+ else if(!islist(managed_overlays))
+ if(new_length == 1 && managed_overlays == new_overlays[1])
+ identical = TRUE
+ else if(length(managed_overlays) == new_length)
+ identical = TRUE
+ for(var/i in 1 to length(managed_overlays))
+ if(managed_overlays[i] != new_overlays[i])
+ identical = FALSE
+ break
+
+ if(!identical)
+ var/full_control = FALSE
+ if(managed_overlays)
+ full_control = length(overlays) == (islist(managed_overlays) ? length(managed_overlays) : 1)
+ if(full_control)
+ overlays = null
+ else
+ cut_overlay(managed_overlays)
+
+ switch(length(new_overlays))
+ if(0)
+ if(full_control)
+ POST_OVERLAY_CHANGE(src)
+ managed_overlays = null
+ if(1)
+ add_overlay(new_overlays)
+ managed_overlays = new_overlays[1]
+ else
+ add_overlay(new_overlays)
+ managed_overlays = new_overlays
+
+ . |= UPDATE_OVERLAYS
+
+ . |= SEND_SIGNAL(src, COMSIG_ATOM_UPDATED_ICON, updates, .)
+
+/// Updates the icon state of the atom
+/atom/proc/update_icon_state()
+
+
+/// Updates the overlays of the atom
+/atom/proc/update_overlays()
+ SHOULD_CALL_PARENT(TRUE)
+ . = list()
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms/atom_movable.dm
old mode 100755
new mode 100644
similarity index 89%
rename from code/game/atoms_movable.dm
rename to code/game/atoms/atom_movable.dm
index 0c4d920b43cdd..c95ee7c19f95f
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms/atom_movable.dm
@@ -231,7 +231,7 @@ RU TGMC EDIT */
var/can_pass_diagonally = NONE
if (direction & (direction - 1)) //Check if the first part of the diagonal move is possible
moving_diagonally = TRUE
- if(!(flags_atom & DIRLOCK))
+ if(!(atom_flags & DIRLOCK))
setDir(direction) //We first set the direction to prevent going through dir sensible object
if((direction & NORTH) && loc.Exit(src, NORTH) && get_step(loc, NORTH).Enter(src))
can_pass_diagonally = NORTH
@@ -247,13 +247,13 @@ RU TGMC EDIT */
moving_diagonally = FALSE
if(!get_step(loc, can_pass_diagonally)?.Exit(src, direction & ~can_pass_diagonally))
return Move(get_step(loc, can_pass_diagonally), can_pass_diagonally)
- if(!(flags_atom & DIRLOCK)) //We want to set the direction to be the one of the "second" diagonal move, aka not can_pass_diagonally
+ if(!(atom_flags & DIRLOCK)) //We want to set the direction to be the one of the "second" diagonal move, aka not can_pass_diagonally
setDir(direction &~ can_pass_diagonally)
else
if(!loc.Exit(src, direction))
return
- if(!(flags_atom & DIRLOCK))
+ if(!(atom_flags & DIRLOCK))
setDir(direction)
var/enter_return_value = newloc.Enter(src)
@@ -368,12 +368,12 @@ RU TGMC EDIT */
/atom/movable/proc/Moved(atom/old_loc, movement_dir, forced = FALSE, list/old_locs)
- SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, movement_dir, forced, old_locs)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, movement_dir, forced, locs)
if(client_mobs_in_contents)
update_parallax_contents()
if(pulledby)
- SEND_SIGNAL(src, COMSIG_MOVABLE_PULL_MOVED, old_loc, movement_dir, forced, old_locs)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_PULL_MOVED, old_loc, movement_dir, forced, locs)
//Cycle through the light sources on this atom and tell them to update.
for(var/datum/dynamic_light_source/light AS in hybrid_light_sources)
light.source_atom.update_light()
@@ -491,7 +491,7 @@ RU TGMC EDIT */
return
if(!isturf(loc))
return
- var/dir_to_proj = get_dir(hit_atom, old_throw_source)
+ var/dir_to_proj = angle_to_cardinal_dir(Get_Angle(hit_atom, old_throw_source))
if(ISDIAGONALDIR(dir_to_proj))
var/list/cardinals = list(turn(dir_to_proj, 45), turn(dir_to_proj, -45))
for(var/direction in cardinals)
@@ -500,8 +500,8 @@ RU TGMC EDIT */
cardinals -= direction
dir_to_proj = pick(cardinals)
- var/perpendicular_angle = Get_Angle(hit_atom, get_step(hit_atom, dir_to_proj))
- var/new_angle = (perpendicular_angle + (perpendicular_angle - Get_Angle(old_throw_source, src) - 180) + rand(-10, 10))
+ var/perpendicular_angle = Get_Angle(hit_atom, get_step(hit_atom, ISDIAGONALDIR(dir_to_proj) ? get_dir(hit_atom, old_throw_source) - dir_to_proj : dir_to_proj))
+ var/new_angle = (perpendicular_angle + (perpendicular_angle - Get_Angle(old_throw_source, (loc == old_throw_source ? hit_atom : src)) - 180) + rand(-10, 10))
if(new_angle < -360)
new_angle += 720 //north is 0 instead of 360
@@ -542,10 +542,10 @@ RU TGMC EDIT */
if(flying)
set_flying(TRUE, FLY_LAYER)
- var/originally_dir_locked = flags_atom & DIRLOCK
+ var/originally_dir_locked = atom_flags & DIRLOCK
if(!originally_dir_locked)
setDir(get_dir(src, target))
- flags_atom |= DIRLOCK
+ atom_flags |= DIRLOCK
throw_source = get_turf(src) //store the origin turf
@@ -574,7 +574,8 @@ RU TGMC EDIT */
var/atom/step = get_step(src, dy)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
- Move(step)
+ if(!Move(step))
+ throwing = FALSE
error += dist_x
dist_since_sleep++
if(dist_since_sleep >= speed)
@@ -584,7 +585,8 @@ RU TGMC EDIT */
var/atom/step = get_step(src, dx)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
- Move(step)
+ if(!Move(step))
+ throwing = FALSE
error -= dist_y
dist_since_sleep++
if(dist_since_sleep >= speed)
@@ -598,7 +600,8 @@ RU TGMC EDIT */
var/atom/step = get_step(src, dx)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
- Move(step)
+ if(!Move(step))
+ throwing = FALSE
error += dist_y
dist_since_sleep++
if(dist_since_sleep >= speed)
@@ -608,7 +611,8 @@ RU TGMC EDIT */
var/atom/step = get_step(src, dy)
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
break
- Move(step)
+ if(!Move(step))
+ throwing = FALSE
error -= dist_x
dist_since_sleep++
if(dist_since_sleep >= speed)
@@ -617,16 +621,16 @@ RU TGMC EDIT */
//done throwing, either because it hit something or it finished moving
if(!originally_dir_locked)
- flags_atom &= ~DIRLOCK
+ atom_flags &= ~DIRLOCK
if(isobj(src) && throwing)
throw_impact(get_turf(src), speed)
- if(loc)
- stop_throw(flying, original_layer)
- SEND_SIGNAL(loc, COMSIG_TURF_THROW_ENDED_HERE, src)
- SEND_SIGNAL(src, COMSIG_MOVABLE_POST_THROW)
+ stop_throw(flying, original_layer)
-/// Annul all throw var to ensure a clean exit out of throw state
+///Clean up all throw vars
/atom/movable/proc/stop_throw(flying = FALSE, original_layer)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_POST_THROW)
+ if(loc)
+ SEND_SIGNAL(loc, COMSIG_TURF_THROW_ENDED_HERE, src)
set_throwing(FALSE)
if(flying)
set_flying(FALSE, original_layer)
@@ -731,17 +735,135 @@ RU TGMC EDIT */
// And animate the attack!
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
-
/atom/movable/vv_get_dropdown()
. = ..()
- . += "---"
- .["Follow"] = "?_src_=holder;[HrefToken()];observefollow=[REF(src)]"
- .["Get"] = "?_src_=vars;[HrefToken()];getatom=[REF(src)]"
- .["Send"] = "?_src_=vars;[HrefToken()];sendatom=[REF(src)]"
- .["Delete All Instances"] = "?_src_=vars;[HrefToken()];delall=[REF(src)]"
- .["Update Icon"] = "?_src_=vars;[HrefToken()];updateicon=[REF(src)]"
- .["Edit Particles"] = "?_src_=vars;[HrefToken()];modify_particles=[REF(src)]"
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_FOLLOW, "Follow")
+ VV_DROPDOWN_OPTION(VV_HK_GET, "Get")
+ VV_DROPDOWN_OPTION(VV_HK_SEND, "Send")
+ VV_DROPDOWN_OPTION(VV_HK_DELETE_ALL_INSTANCES, "Delete All Instances")
+ VV_DROPDOWN_OPTION(VV_HK_UPDATE_ICONS, "Update Icon")
+ VV_DROPDOWN_OPTION(VV_HK_EDIT_PARTICLES, "Edit Particles")
+
+/atom/movable/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_FOLLOW])
+ if(!check_rights(NONE))
+ return
+ var/client/C = usr.client
+ if(isnewplayer(C.mob) || isnewplayer(src))
+ return
+ var/message
+ if(!isobserver(C.mob))
+ usr.client.holder.admin_ghost()
+ message = TRUE
+ var/mob/dead/observer/O = C.mob
+ O.ManualFollow(src)
+ if(message)
+ log_admin("[key_name(O)] jumped to follow [key_name(src)].")
+ message_admins("[ADMIN_TPMONTY(O)] jumped to follow [ADMIN_TPMONTY(src)].")
+
+ if(href_list[VV_HK_GET])
+ if(!check_rights(R_DEBUG))
+ return
+ if(!istype(src))
+ return
+ var/turf/T = get_turf(usr)
+ if(!istype(T))
+ return
+ forceMove(T)
+ log_admin("[key_name(usr)] has sent atom [src] to themselves.")
+ message_admins("[ADMIN_TPMONTY(usr)] has sent atom [src] to themselves.")
+ if(href_list[VV_HK_SEND])
+ if(!check_rights(R_DEBUG))
+ return
+ if(!istype(src))
+ return
+ var/atom/target
+ switch(input("Where do you want to send it to?", "Send Mob") as null|anything in list("Area", "Mob", "Key", "Coords"))
+ if("Area")
+ var/area/AR = input("Pick an area.", "Pick an area") as null|anything in GLOB.sorted_areas
+ if(!AR || !src)
+ return
+ target = pick(get_area_turfs(AR))
+ if("Mob")
+ var/mob/N = input("Pick a mob.", "Pick a mob") as null|anything in sortList(GLOB.mob_list)
+ if(!N || !src)
+ return
+ target = get_turf(N)
+ if("Key")
+ var/client/C = input("Pick a key.", "Pick a key") as null|anything in sortKey(GLOB.clients)
+ if(!C || !src)
+ return
+ target = get_turf(C.mob)
+ if("Coords")
+ var/X = input("Select coordinate X", "Coordinate X") as null|num
+ var/Y = input("Select coordinate Y", "Coordinate Y") as null|num
+ var/Z = input("Select coordinate Z", "Coordinate Z") as null|num
+ if(isnull(X) || isnull(Y) || isnull(Z) || !src)
+ return
+ target = locate(X, Y, Z)
+ if(!target)
+ return
+ forceMove(target)
+ log_admin("[key_name(usr)] has sent atom [src] to [AREACOORD(target)].")
+ message_admins("[ADMIN_TPMONTY(usr)] has sent atom [src] to [ADMIN_VERBOSEJMP(target)].")
+
+ if(href_list[VV_HK_DELETE_ALL_INSTANCES])
+ if(!check_rights(R_DEBUG|R_SERVER))
+ return
+ var/obj/O = src
+ if(!isobj(O))
+ return
+ var/action_type = alert("Strict type ([O.type]) or type and all subtypes?", "Type", "Strict type", "Type and subtypes", "Cancel")
+ if(action_type == "Cancel" || !action_type)
+ return
+ if(alert("Are you really sure you want to delete all objects of type [O.type]?", "Warning", "Yes", "No") != "Yes")
+ return
+ if(alert("Second confirmation required. Delete?", "Warning", "Yes", "No") != "Yes")
+ return
+ var/O_type = O.type
+ var/i = 0
+ var/strict
+ switch(action_type)
+ if("Strict type")
+ strict = TRUE
+ for(var/obj/Obj in world)
+ if(Obj.type == O_type)
+ i++
+ qdel(Obj)
+ CHECK_TICK
+ if(!i)
+ to_chat(usr, "No objects of this type exist")
+ return
+ if("Type and subtypes")
+ for(var/obj/Obj in world)
+ if(istype(Obj,O_type))
+ i++
+ qdel(Obj)
+ CHECK_TICK
+ if(!i)
+ to_chat(usr, "No objects of this type exist")
+ return
+ log_admin("[key_name(usr)] deleted all objects of type[strict ? "" : " and subtypes"] of [O_type] ([i] objects deleted).")
+ message_admins("[ADMIN_TPMONTY(usr)] deleted all objects of type[strict ? "" : " and subtypes"] of [O_type] ([i] objects deleted).")
+
+ if(href_list[VV_HK_UPDATE_ICONS])
+ if(!check_rights(R_DEBUG))
+ return
+ update_icon()
+ log_admin("[key_name(usr)] updated the icon of [src].")
+
+ if(href_list[VV_HK_EDIT_PARTICLES])
+ if(!check_rights(R_VAREDIT))
+ return
+ var/client/C = usr.client
+ C?.open_particle_editor(src)
/atom/movable/proc/get_language_holder(shadow = TRUE)
if(language_holder)
@@ -1086,10 +1208,7 @@ RU TGMC EDIT */
grab_state = newstate
///Toggles AM between throwing states
-/atom/movable/proc/set_throwing(new_throwing, flying)
- if(new_throwing == throwing)
- return
- . = throwing
+/atom/movable/proc/set_throwing(new_throwing)
throwing = new_throwing
if(throwing)
pass_flags |= PASS_THROW
diff --git a/code/game/blood.dm b/code/game/blood.dm
index 70c4ffd411fe8..4b61630d9e35e 100644
--- a/code/game/blood.dm
+++ b/code/game/blood.dm
@@ -27,7 +27,7 @@
/obj/add_blood(b_color)
- if(flags_atom & NOBLOODY)
+ if(atom_flags & NOBLOODY)
return FALSE
if(b_color)
blood_color = b_color
@@ -145,24 +145,24 @@
var/washears = TRUE
var/washglasses = TRUE
if(wear_suit)
- washgloves = !(wear_suit.flags_inv_hide & HIDEGLOVES)
- washshoes = !(wear_suit.flags_inv_hide & HIDESHOES)
+ washgloves = !(wear_suit.inv_hide_flags & HIDEGLOVES)
+ washshoes = !(wear_suit.inv_hide_flags & HIDESHOES)
if(wear_suit.clean_blood())
update_inv_wear_suit()
else if(w_uniform)
if(w_uniform.clean_blood())
update_inv_w_uniform()
if(head)
- washmask = !(head.flags_inv_hide & HIDEMASK)
- washglasses = !(head.flags_inv_hide & HIDEEYES)
- washears = !(head.flags_inv_hide & HIDEEARS)
+ washmask = !(head.inv_hide_flags & HIDEMASK)
+ washglasses = !(head.inv_hide_flags & HIDEEYES)
+ washears = !(head.inv_hide_flags & HIDEEARS)
if(head.clean_blood())
update_inv_head()
if(wear_mask)
if(washears)
- washears = !(wear_mask.flags_inv_hide & HIDEEARS)
+ washears = !(wear_mask.inv_hide_flags & HIDEEARS)
if(washglasses)
- washglasses = !(wear_mask.flags_inv_hide & HIDEEYES)
+ washglasses = !(wear_mask.inv_hide_flags & HIDEEYES)
if(washmask && wear_mask.clean_blood())
update_inv_wear_mask()
if(gloves && washgloves)
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 6927da95a7ed9..723ea4be388e0 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -108,6 +108,14 @@
/mob/living/carbon/xenomorph/med_hud_set_health()
+ if(hud_used?.healths)
+ var/bucket
+ if(stat == DEAD)
+ bucket = "critical"
+ else
+ bucket = get_bucket(XENO_HUD_ICON_BUCKETS, maxHealth, health, get_crit_threshold(), list("full", "critical"))
+ hud_used.healths.icon_state = "health[bucket]"
+
var/image/holder = hud_list[HEALTH_HUD_XENO]
if(!holder)
return
@@ -176,7 +184,6 @@
/mob/living/carbon/xenomorph/med_hud_set_status()
- hud_set_plasma()
hud_set_pheromone()
@@ -262,14 +269,19 @@
simple_status_hud.icon_state = ""
if(stat != DEAD)
status_hud.icon_state = "hudsynth"
+ else if(HAS_TRAIT(src, TRAIT_UNDEFIBBABLE))
+ status_hud.icon_state = "hudsynthdnr"
+ return TRUE
else
- if(!client)
- var/mob/dead/observer/G = get_ghost(FALSE, TRUE)
+ if(!mind)
+ var/mob/dead/observer/G = get_ghost(TRUE)
if(!G)
status_hud.icon_state = "hudsynthdnr"
else
status_hud.icon_state = "hudsynthdead"
- return
+ else
+ status_hud.icon_state = "hudsynthdead"
+ return TRUE
infection_hud.icon_state = "hudsynth" //Xenos can feel synths are not human.
return TRUE
@@ -306,8 +318,8 @@
hud_list[HEART_STATUS_HUD].icon_state = "still_heart"
status_hud.icon_state = "huddead"
return TRUE
- if(!client)
- var/mob/dead/observer/ghost = get_ghost()
+ if(!mind)
+ var/mob/dead/observer/ghost = get_ghost(TRUE)
if(!ghost?.can_reenter_corpse)
status_hud.icon_state = "huddead"
return TRUE
@@ -401,7 +413,6 @@
return TRUE
*/
-
//infection status that appears on humans and monkeys, viewed by xenos only.
/datum/atom_hud/xeno_infection
hud_icons = list(XENO_EMBRYO_HUD)
@@ -466,8 +477,16 @@
/mob/living/carbon/xenomorph/proc/hud_set_plasma()
- if(!xeno_caste) // usually happens because hud ticks before New() finishes.
+ if(!xeno_caste) //this is cringe that we need this but currently its called before caste is set on init
return
+ if(hud_used?.alien_plasma_display)
+ var/bucket
+ if(stat == DEAD)
+ bucket = "empty"
+ else
+ bucket = get_bucket(XENO_HUD_ICON_BUCKETS, xeno_caste.plasma_max, plasma_stored, 0, list("full", "empty"))
+ hud_used.alien_plasma_display.icon_state = "power_display_[bucket]"
+
var/image/holder = hud_list[PLASMA_HUD]
if(!holder)
return
@@ -518,7 +537,7 @@
if(hive?.living_xeno_queen)
if(hive.living_xeno_queen.observed_xeno == src)
holder.icon_state = "queen_overwatch"
- if(queen_chosen_lead)
+ if(xeno_flags & XENO_LEADER)
var/image/I = image('modular_RUtgmc/icons/mob/hud.dmi',src, "hudxenoleader") //RUTGMC EDIT .dmi
holder.overlays += I
hud_list[QUEEN_OVERWATCH_HUD] = holder
diff --git a/code/game/objects/effects/acid_hole.dm b/code/game/objects/effects/acid_hole.dm
index 8689ce2f83248..4c14af8cfd327 100644
--- a/code/game/objects/effects/acid_hole.dm
+++ b/code/game/objects/effects/acid_hole.dm
@@ -50,7 +50,7 @@
use_wall_hole(user)
-/obj/effect/acid_hole/specialclick(mob/living/carbon/user)
+/obj/effect/acid_hole/CtrlClick(mob/living/carbon/user)
if(!isxeno(user))
return
if(!user.CanReach(src))
@@ -125,6 +125,8 @@
//Throwing Shiet
/obj/effect/acid_hole/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
var/mob_dir = get_dir(user, src)
var/crawl_dir = dir & mob_dir
diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm
index 9067443aeaf8d..7faaa75f4d8c1 100644
--- a/code/game/objects/effects/countdown.dm
+++ b/code/game/objects/effects/countdown.dm
@@ -86,5 +86,52 @@
/obj/effect/countdown/campaign_objective/get_value()
if(QDELETED(attached_to))
return
- var/obj/structure/campaign_objective/capture_objective/objective = attached_to
+ var/obj/structure/campaign_objective/objective = attached_to
return objective.get_time_left()
+
+/obj/effect/countdown/action_cooldown
+ name = "cooldown"
+ color = "#d1d1d1"
+ invisibility = SEE_INVISIBLE_LIVING
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ layer = ABOVE_HUD_LAYER
+ plane = HUD_PLANE
+ pixel_x = 5
+ pixel_y = 8
+ appearance_flags = KEEP_APART|RESET_COLOR
+ ///The action this countdown is associated with
+ var/datum/action/ability/attached_action
+
+/obj/effect/countdown/action_cooldown/Destroy()
+ attached_action = null
+ return ..()
+
+/obj/effect/countdown/action_cooldown/attach(atom/A)
+ var/atom/movable/screen/action_button/button = A
+ if(!istype(button))
+ qdel(src)
+ return
+ attached_to = button
+ button.vis_contents += src
+ attached_action = button.source_action
+
+/obj/effect/countdown/action_cooldown/start()
+ if(!started)
+ START_PROCESSING(SSfastprocess, src)
+ started = TRUE
+
+/obj/effect/countdown/action_cooldown/process()
+ if(QDELETED(attached_to))
+ qdel(src)
+ return
+ var/new_val = round(attached_action.cooldown_remaining(), 0.1)
+ if(new_val == displayed_text)
+ return
+ if(new_val >= 10) //avoid cropping, and deciseconds don't really matter if you're 10+ seconds away
+ new_val = floor(new_val)
+ displayed_text = new_val
+
+ if(displayed_text)
+ maptext = "[displayed_text]"
+ else
+ maptext = null
diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm
index b5af9a359fdf3..4fe964eb2a049 100644
--- a/code/game/objects/effects/decals/Cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/Cleanable/aliens.dm
@@ -16,9 +16,6 @@
basecolor = "#dffc00"
amount = 0
-/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
- color = "#FFFFFF"
-
/obj/effect/decal/cleanable/blood/gibs/xeno/up
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1")
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index e9a20b8767350..322fc0fecf9ea 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -46,9 +46,8 @@
deltimer(drying_timer)
return ..()
-
-/obj/effect/decal/cleanable/blood/update_icon()
- if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
+/obj/effect/decal/cleanable/blood/update_icon_state()
+ . = ..()
color = basecolor
/obj/effect/decal/cleanable/blood/proc/on_cross(datum/source, mob/living/carbon/human/perp, oldloc, oldlocs)
@@ -74,9 +73,6 @@
else if (hasfeet)//Or feet
perp.feet_blood_color = basecolor
perp.track_blood = max(amount,perp.track_blood)
- else if (perp.buckled && istype(perp.buckled, /obj/structure/bed/chair/wheelchair))
- var/obj/structure/bed/chair/wheelchair/W = perp.buckled
- W.bloodiness = 4
perp.update_inv_shoes(1)
amount--
@@ -171,20 +167,22 @@
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
var/fleshcolor = "#FFC896"
-/obj/effect/decal/cleanable/blood/gibs/update_icon()
-
- var/image/giblets = new(base_icon, "[icon_state]_flesh", dir)
- if(!fleshcolor || fleshcolor == "rainbow")
+/obj/effect/decal/cleanable/blood/gibs/update_icon_state()
+ . = ..()
+ if(!fleshcolor)
fleshcolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
- giblets.color = fleshcolor
-
var/icon/blood = new(base_icon,"[icon_state]",dir)
- if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
- blood.Blend(basecolor,ICON_MULTIPLY)
+ if(basecolor == "rainbow")
+ basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
+ blood.Blend(basecolor, ICON_MULTIPLY)
icon = blood
- overlays.Cut()
- overlays += giblets
+
+/obj/effect/decal/cleanable/blood/gibs/update_overlays()
+ . = ..()
+ var/image/giblets = new(base_icon, "[icon_state]_flesh", dir)
+ giblets.color = fleshcolor
+ . += giblets
/obj/effect/decal/cleanable/blood/gibs/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm
index d2a1b539f7870..1f8fa7aafd19e 100644
--- a/code/game/objects/effects/decals/Cleanable/robots.dm
+++ b/code/game/objects/effects/decals/Cleanable/robots.dm
@@ -6,9 +6,6 @@
basecolor="#030303"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
-/obj/effect/decal/cleanable/blood/gibs/robot/update_icon()
- color = "#FFFFFF"
-
/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like
return
diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm
index 624fbcf6a50c6..5f71d971b94b7 100644
--- a/code/game/objects/effects/decals/Cleanable/tracks.dm
+++ b/code/game/objects/effects/decals/Cleanable/tracks.dm
@@ -116,9 +116,8 @@
if(updated)
update_icon()
-/obj/effect/decal/cleanable/blood/tracks/update_icon()
- overlays.Cut()
- color = "#FFFFFF"
+/obj/effect/decal/cleanable/blood/tracks/update_overlays()
+ . = ..()
var/truedir=0
// Update ONLY the overlays that have changed.
@@ -131,14 +130,14 @@
truedir=truedir>>4
if(track.overlay)
- track.overlay=null
+ track.overlay=null //todo, not handling track overlays properly. fuck this shitcode.
var/image/I = image(icon, icon_state=state, dir=num2dir(truedir))
I.color = track.basecolor
track.fresh=0
track.overlay=I
stack[stack_idx]=track
- overlays += I
+ . += I
updatedtracks=0 // Clear our memory of updated tracks.
/obj/effect/decal/cleanable/blood/tracks/footprints
diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm
index 7e83d8f29c85a..65f9d965f07f1 100644
--- a/code/game/objects/effects/decals/contraband.dm
+++ b/code/game/objects/effects/decals/contraband.dm
@@ -36,6 +36,7 @@
/obj/structure/sign/poster/Initialize(mapload)
. = ..()
+ icon = 'icons/obj/contraband.dmi'
switch(dir)
if(NORTH)
pixel_y = 30
@@ -62,6 +63,8 @@
/obj/structure/sign/poster/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswirecutter(I))
playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
if(ruined)
diff --git a/code/game/objects/effects/effect.dm b/code/game/objects/effects/effect.dm
index b650a43e53d70..092224cb4ed06 100644
--- a/code/game/objects/effects/effect.dm
+++ b/code/game/objects/effects/effect.dm
@@ -5,3 +5,6 @@
/obj/effect/add_debris_element() //they're not hittable, and prevents recursions
return
+
+/obj/effect/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ return
diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm
index 8e20164c335b5..8b153fb590a7e 100644
--- a/code/game/objects/effects/effect_system/smoke.dm
+++ b/code/game/objects/effects/effect_system/smoke.dm
@@ -13,13 +13,19 @@
pass_flags = PASS_AIR
resistance_flags = UNACIDABLE|PLASMACUTTER_IMMUNE|PROJECTILE_IMMUNE|CRUSHER_IMMUNE
var/amount = 3
+ ///Duration in 2 second ticks
var/lifetime = 5
///time in decisecond for a smoke to spread one tile.
var/expansion_speed = 1
+ ///Special effect traits
var/smoke_traits = NONE
- var/strength = 1 // Effects scale with the emitter's bomb_strength upgrades.
- var/bio_protection = 1 // how unefficient its effects are against protected target from 0 to 1.
- var/datum/effect_system/smoke_spread/cloud // for associated chemical smokes.
+ ///Smoke effect strength mult
+ var/strength = 1
+ ///Effect strength mult against bio protection
+ var/bio_protection = 1
+ ///for associated chemical smoke
+ var/datum/effect_system/smoke_spread/cloud
+ ///Fraction used for chem touch effects
var/fraction = 0.2
///Delay in ticks before this smoke can affect a given mob again, applied in living's effect_smoke
var/minimum_effect_delay = 1 SECONDS
@@ -189,8 +195,11 @@
/////////////////////////////////////////////
/datum/effect_system/smoke_spread
+ ///Smoke range
var/range = 3
+ ///Type of smoke
var/smoke_type = /obj/effect/particle_effect/smoke
+ ///Smoke duration in 2 sec ticks
var/lifetime
var/list/smokes
var/list/smoked_mobs
@@ -276,6 +285,23 @@
color = "#791697"
smoke_traits = SMOKE_PLASMALOSS
+/obj/effect/particle_effect/smoke/plasmaloss/effect_smoke(obj/effect/particle_effect/smoke/S)
+ . = ..()
+ if(!.)
+ return
+ if(S.smoke_traits & SMOKE_PURGER)
+ lifetime -= 4
+
+//////////////////////////////////////
+// ANTIGAS SMOKE
+////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/antigas
+ alpha = 65
+ opacity = FALSE
+ color = "#1b1b1b"
+ smoke_traits = SMOKE_PURGER
+
//////////////////////////////////////
// FLASHBANG SMOKE
////////////////////////////////////
@@ -295,6 +321,13 @@
strength = 1.5
smoke_traits = SMOKE_SATRAPINE|SMOKE_GASP|SMOKE_COUGH
+/obj/effect/particle_effect/smoke/satrapine/effect_smoke(obj/effect/particle_effect/smoke/S)
+ . = ..()
+ if(!.)
+ return
+ if(S.smoke_traits & SMOKE_PURGER)
+ lifetime -= 4
+
/////////////////////////////////////////
// BOILER SMOKES
/////////////////////////////////////////
@@ -311,40 +344,50 @@
return
if(S.smoke_traits & SMOKE_PLASMALOSS)
lifetime -= 2
+ if(S.smoke_traits & SMOKE_PURGER)
+ lifetime -= 4
//Xeno acid smoke.
/obj/effect/particle_effect/smoke/xeno/burn
lifetime = 6
+ alpha = 120
+ opacity = FALSE
color = "#86B028" //Mostly green?
- smoke_traits = SMOKE_XENO|SMOKE_XENO_ACID|SMOKE_GASP|SMOKE_COUGH|SMOKE_HUGGER_PACIFY
+ smoke_traits = SMOKE_XENO|SMOKE_XENO_ACID|SMOKE_GASP|SMOKE_COUGH
+
+//Used for smokebomb nades.
+/obj/effect/particle_effect/smoke/xeno/burn/opaque
+ alpha = 255
+ opacity = TRUE
//Xeno light acid smoke.for acid huggers
/obj/effect/particle_effect/smoke/xeno/burn/light
lifetime = 4 //Lasts for less time
- alpha = 60
- opacity = FALSE
- smoke_traits = SMOKE_XENO|SMOKE_XENO_ACID|SMOKE_GASP|SMOKE_COUGH
//Xeno neurotox smoke.
/obj/effect/particle_effect/smoke/xeno/neuro
+ alpha = 120
+ opacity = FALSE
color = "#ffbf58" //Mustard orange?
- smoke_traits = SMOKE_XENO|SMOKE_XENO_NEURO|SMOKE_GASP|SMOKE_COUGH|SMOKE_EXTINGUISH|SMOKE_HUGGER_PACIFY
+ smoke_traits = SMOKE_XENO|SMOKE_XENO_NEURO|SMOKE_GASP|SMOKE_COUGH|SMOKE_EXTINGUISH
///Xeno neurotox smoke for Defilers; doesn't extinguish
/obj/effect/particle_effect/smoke/xeno/neuro/medium
+ alpha = 255
+ opacity = TRUE
color = "#ffbf58" //Mustard orange?
smoke_traits = SMOKE_XENO|SMOKE_XENO_NEURO|SMOKE_GASP|SMOKE_COUGH|SMOKE_HUGGER_PACIFY
///Xeno neurotox smoke for neurospit; doesn't extinguish or blind
/obj/effect/particle_effect/smoke/xeno/neuro/light
- alpha = 60
- opacity = FALSE
smoke_traits = SMOKE_XENO|SMOKE_XENO_NEURO|SMOKE_GASP|SMOKE_COUGH|SMOKE_NEURO_LIGHT //Light neuro smoke doesn't extinguish
/obj/effect/particle_effect/smoke/xeno/toxic
lifetime = 2
+ alpha = 60
+ opacity = FALSE
color = "#00B22C"
- smoke_traits = SMOKE_XENO|SMOKE_XENO_TOXIC|SMOKE_GASP|SMOKE_COUGH|SMOKE_EXTINGUISH|SMOKE_HUGGER_PACIFY
+ smoke_traits = SMOKE_XENO|SMOKE_XENO_TOXIC|SMOKE_GASP|SMOKE_COUGH|SMOKE_EXTINGUISH
/obj/effect/particle_effect/smoke/xeno/hemodile
color = "#0287A1"
@@ -389,6 +432,9 @@
/datum/effect_system/smoke_spread/satrapine
smoke_type = /obj/effect/particle_effect/smoke/satrapine
+/datum/effect_system/smoke_spread/antigas
+ smoke_type = /obj/effect/particle_effect/smoke/antigas
+
/datum/effect_system/smoke_spread/xeno
smoke_type = /obj/effect/particle_effect/smoke/xeno
var/strength = 1
@@ -404,6 +450,9 @@
/datum/effect_system/smoke_spread/xeno/acid
smoke_type = /obj/effect/particle_effect/smoke/xeno/burn
+/datum/effect_system/smoke_spread/xeno/acid/opaque
+ smoke_type = /obj/effect/particle_effect/smoke/xeno/burn/opaque
+
/datum/effect_system/smoke_spread/xeno/acid/light
smoke_type = /obj/effect/particle_effect/smoke/xeno/burn/light
diff --git a/code/game/objects/effects/landmarks/corpsespawner.dm b/code/game/objects/effects/landmarks/corpsespawner.dm
index 245a912239bdf..c14526e6e5b37 100644
--- a/code/game/objects/effects/landmarks/corpsespawner.dm
+++ b/code/game/objects/effects/landmarks/corpsespawner.dm
@@ -34,7 +34,7 @@
var/corpsepocket2 = null
var/corpseback = null
var/corpseid = 0 //Just set to 1 if you want them to have an ID
- var/corpseidjob = null // Needs to be in quotes, such as "Clown" or "Chef." This just determines what the ID reads as, not their access
+ var/corpseidjob = null //Needs to be in quotes, such as "Clown" or "Chef." This just determines what the ID reads as, not their access
var/corpseidaccess = null //This is for access. See access.dm for which jobs give what access. Use CAPTAIN if you want it to be all access.
var/corpseidicon = null //For setting it to be a gold, silver, centcom etc ID
@@ -259,7 +259,7 @@
/obj/effect/landmark/corpsespawner/chef
name = "Chef"
corpseuniform = /obj/item/clothing/under/rank/chef
- corpsesuit = /obj/item/clothing/suit/chef/classic
+ corpsesuit = /obj/item/clothing/suit/storage/chef/classic
corpseshoes = /obj/item/clothing/shoes/black
corpsehelmet = /obj/item/clothing/head/chefhat
corpseback = /obj/item/storage/backpack
diff --git a/code/game/objects/effects/landmarks/excavation_site_spawner.dm b/code/game/objects/effects/landmarks/excavation_site_spawner.dm
index 300a60c4f5539..8fc61db071c8a 100644
--- a/code/game/objects/effects/landmarks/excavation_site_spawner.dm
+++ b/code/game/objects/effects/landmarks/excavation_site_spawner.dm
@@ -52,5 +52,5 @@
rewards_max = 4
map_icon = "excav_xeno"
rewards = list(
- /obj/item/research_resource/xeno/tier_one,
+ /obj/item/research_resource/xeno,
)
diff --git a/code/game/objects/effects/landmarks/itemspawner.dm b/code/game/objects/effects/landmarks/itemspawner.dm
index e555b97efa20f..4aa8ee1782386 100644
--- a/code/game/objects/effects/landmarks/itemspawner.dm
+++ b/code/game/objects/effects/landmarks/itemspawner.dm
@@ -87,7 +87,7 @@
/obj/effect/landmark/itemspawner/waiter
items_to_spawn = list(\
/obj/item/clothing/under/waiter,\
- /obj/item/clothing/suit/apron)
+ /obj/item/clothing/suit/storage/apron)
/obj/effect/landmark/itemspawner/pirate
diff --git a/code/game/objects/effects/landmarks/landmarks.dm b/code/game/objects/effects/landmarks/landmarks.dm
index a9a5ed498c97c..63136df51e9ab 100644
--- a/code/game/objects/effects/landmarks/landmarks.dm
+++ b/code/game/objects/effects/landmarks/landmarks.dm
@@ -171,7 +171,7 @@
/obj/effect/landmark/resin_jelly_pod
name = "xeno jelly pod landmark"
- icon = 'icons/Xeno/resinpod.dmi'
+ icon = 'icons/Xeno/resin_pod.dmi'
icon_state = "resinpod"
/obj/effect/landmark/resin_jelly_pod/Initialize(mapload)
@@ -422,7 +422,7 @@
/obj/item/weapon/gun/minigun,
/obj/item/weapon/gun/grenade_launcher/multinade_launcher,
/obj/item/weapon/gun/energy/lasgun/pulse,
- /obj/item/weapon/gun/tl102/death, // memes
+ /obj/item/weapon/gun/hsg_102/death, // memes
)
/obj/effect/landmark/weapon_spawn/tier6_weapon_spawn
@@ -436,7 +436,7 @@
/obj/effect/landmark/sensor_tower
name = "Sensor tower"
icon = 'icons/obj/structures/sensor.dmi'
- icon_state = "sensor_loyalist"
+ icon_state = "sensor"
/obj/effect/landmark/sensor_tower/Initialize(mapload)
..()
@@ -477,7 +477,7 @@
. = ..()
//adds the exit points to the glob, and the start points link to them in lateinit
GLOB.patrol_point_list += src
- if(!(SSticker?.mode?.flags_round_type & MODE_TWO_HUMAN_FACTIONS))
+ if(!(SSticker?.mode?.round_type_flags & MODE_TWO_HUMAN_FACTIONS))
return
SSminimaps.add_marker(src, GLOB.faction_to_minimap_flag[faction], image('icons/UI_icons/map_blips.dmi', null, minimap_icon))
diff --git a/code/game/objects/effects/landmarks/marine_spawns.dm b/code/game/objects/effects/landmarks/marine_spawns.dm
index 4da10a96c4717..b25d11fe01904 100644
--- a/code/game/objects/effects/landmarks/marine_spawns.dm
+++ b/code/game/objects/effects/landmarks/marine_spawns.dm
@@ -34,6 +34,10 @@
icon_state = "PO"
job = /datum/job/terragov/command/pilot
+/obj/effect/landmark/start/job/transportofficer
+ icon_state = "TO"
+ job = /datum/job/terragov/command/transportofficer
+
/obj/effect/landmark/start/job/chiefshipengineer
icon_state = "CSE"
job = /datum/job/terragov/engineering/chief
@@ -46,6 +50,14 @@
icon_state = "MP"
job = /datum/job/terragov/command/mech_pilot
+/obj/effect/landmark/start/job/assault_crewman
+ icon_state = "AC"
+ job = /datum/job/terragov/command/assault_crewman
+
+/obj/effect/landmark/start/job/transport_crewman
+ icon_state = "TC"
+ job = /datum/job/terragov/command/transport_crewman
+
/obj/effect/landmark/start/job/shiptech
icon_state = "SE"
job = /datum/job/terragov/engineering/tech
diff --git a/code/game/objects/effects/landmarks/mode.dm b/code/game/objects/effects/landmarks/mode.dm
index f6b7831b42e6b..7171ffaa43511 100644
--- a/code/game/objects/effects/landmarks/mode.dm
+++ b/code/game/objects/effects/landmarks/mode.dm
@@ -9,7 +9,7 @@
/obj/effect/landmark/lv624/fog_blocker/Initialize(mapload)
. = ..()
store_location()
- flags_atom |= INITIALIZED
+ atom_flags |= INITIALIZED
return INITIALIZE_HINT_QDEL
/obj/effect/landmark/lv624/fog_blocker/proc/store_location()
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index 0e4845379a5b1..71530bb0f9724 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -93,8 +93,8 @@
return TRUE
-/obj/effect/forcefield/fog/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- return attack_hand(X)
+/obj/effect/forcefield/fog/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ return attack_hand(xeno_attacker)
/obj/effect/forcefield/fog/attack_animal(M)
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 6ebd589ba19f0..cfb06dbc71570 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -105,6 +105,23 @@
/obj/effect/overlay/blinking_laser/napalm
icon_state = "napalm_target"
+/obj/effect/overlay/blinking_laser/monarch
+ icon_state = "monarch_target"
+
+/obj/effect/overlay/blinking_laser/swansong
+ icon_state = "swansong_target"
+
+// Bombs, then bomblets
+
+/obj/effect/overlay/blinking_laser/bomb
+ icon_state = "bomb_target"
+
+/obj/effect/overlay/blinking_laser/bomb_fat
+ icon_state = "fat_bomb_target"
+
+/obj/effect/overlay/blinking_laser/bomblet
+ icon_state = "bomblet_target"
+
//Marine-only visuals. Prediction HUD, etc. Does not show without marine headset
/obj/effect/overlay/blinking_laser/marine
name = "prediction matrix"
@@ -373,3 +390,12 @@
icon_state = "spooky"
pixel_x = 16
pixel_y = 16
+
+/obj/effect/overlay/vis
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ anchored = TRUE
+ vis_flags = VIS_INHERIT_DIR
+ /// When detected to be unused it gets set to world.time, after a while it gets removed
+ var/unused = 0
+ /// Overlays which go unused for 2 minutes get cleaned up
+ var/cache_expiration = 2 MINUTES
diff --git a/code/game/objects/effects/spawners/modularmappingspawner.dm b/code/game/objects/effects/spawners/modularmappingspawner.dm
index 51b6010aa3091..565c56e0f9ba6 100644
--- a/code/game/objects/effects/spawners/modularmappingspawner.dm
+++ b/code/game/objects/effects/spawners/modularmappingspawner.dm
@@ -240,3 +240,29 @@
mapid = "EORG"
spawner_height = 46
spawner_width = 46
+
+/**********Jungle Outpost*******/
+/obj/effect/spawner/modularmap/jungle_outpost/westtower
+ mapid = "jowesttower"
+ spawner_width = 12
+ spawner_height = 14
+
+/obj/effect/spawner/modularmap/jungle_outpost/southcrates
+ mapid = "josouthcrates"
+ spawner_width = 12
+ spawner_height = 14
+
+/obj/effect/spawner/modularmap/jungle_outpost/hydroponics
+ mapid = "johydroponics"
+ spawner_width = 19
+ spawner_height = 18
+
+/obj/effect/spawner/modularmap/jungle_outpost/medbay
+ mapid = "jomedbay"
+ spawner_width = 16
+ spawner_height = 24
+
+/obj/effect/spawner/modularmap/jungle_outpost/engineering
+ mapid = "joengineering"
+ spawner_width = 21
+ spawner_height = 21
diff --git a/code/game/objects/effects/spawners/random/clothing.dm b/code/game/objects/effects/spawners/random/clothing.dm
index 6dec381cb74ab..69564dfbc9835 100644
--- a/code/game/objects/effects/spawners/random/clothing.dm
+++ b/code/game/objects/effects/spawners/random/clothing.dm
@@ -12,7 +12,7 @@
icon_state = "random_clothes"
loot = list(
/obj/item/clothing/suit/bio_suit,
- /obj/item/clothing/suit/bomber,
+ /obj/item/clothing/suit/storage/bomber,
/obj/item/clothing/suit/ianshirt,
/obj/item/clothing/suit/radiation,
/obj/item/clothing/suit/space,
diff --git a/code/game/objects/effects/spawners/random/engineering.dm b/code/game/objects/effects/spawners/random/engineering.dm
index 0c095d960dea5..e77c3daee2d94 100644
--- a/code/game/objects/effects/spawners/random/engineering.dm
+++ b/code/game/objects/effects/spawners/random/engineering.dm
@@ -20,8 +20,7 @@
/obj/effect/spawner/random/engineering/technology_scanner
name = "Random Scanner"
- icon = 'icons/obj/items/items.dmi'
- icon_state = "atmos"
+ icon_state = "random_scanner"
loot = list(
/obj/item/t_scanner = 4,
/obj/item/radio = 2,
@@ -204,8 +203,8 @@
icon_state = "random_glass"
spawn_loot_chance = 90
loot = list(
- /obj/item/stack/sheet/glass = 25,
- /obj/item/stack/sheet/glass/large_stack = 1,
+ /obj/item/stack/sheet/glass/glass = 25,
+ /obj/item/stack/sheet/glass/glass/large_stack = 1,
)
/obj/effect/spawner/random/engineering/insulatedgloves
diff --git a/code/game/objects/effects/spawners/random/food_or_drink.dm b/code/game/objects/effects/spawners/random/food_or_drink.dm
index ce720e684ca68..3df1e31df6612 100644
--- a/code/game/objects/effects/spawners/random/food_or_drink.dm
+++ b/code/game/objects/effects/spawners/random/food_or_drink.dm
@@ -112,7 +112,7 @@
loot = list(
/obj/item/reagent_containers/food/snacks/wrapped/booniebars = 26,
/obj/item/reagent_containers/food/snacks/wrapped/chunk = 26,
- /obj/item/reagent_containers/food/snacks/wrapped/barcardine = 26,
+ /obj/item/reagent_containers/food/snacks/wrapped/barcaridine = 26,
/obj/item/reagent_containers/food/snacks/wrapped/proteinbar = 12,
/obj/item/reagent_containers/food/snacks/candy = 5,
/obj/item/reagent_containers/food/snacks/enrg_bar = 5,
@@ -126,7 +126,7 @@
/obj/item/reagent_containers/food/snacks/wrapped/proteinbar = 10,
/obj/item/reagent_containers/food/snacks/wrapped/booniebars = 5,
/obj/item/reagent_containers/food/snacks/wrapped/chunk = 5,
- /obj/item/reagent_containers/food/snacks/wrapped/barcardine = 5,
+ /obj/item/reagent_containers/food/snacks/wrapped/barcaridine = 5,
)
/obj/effect/spawner/random/food_or_drink/cheesewedge
@@ -257,7 +257,7 @@
/obj/item/reagent_containers/food/snacks/sosjerky,
/obj/item/reagent_containers/food/snacks/donkpocket,
/obj/item/reagent_containers/food/snacks/wrapped/booniebars,
- /obj/item/reagent_containers/food/snacks/wrapped/barcardine,
+ /obj/item/reagent_containers/food/snacks/wrapped/barcaridine,
/obj/item/reagent_containers/food/snacks/wrapped/chunk,
/obj/item/reagent_containers/food/snacks/lollipop,
/obj/item/reagent_containers/food/snacks/pastries/appletart,
diff --git a/code/game/objects/effects/spawners/random/misc_item.dm b/code/game/objects/effects/spawners/random/misc_item.dm
index d92513cf1a4fd..de1151e3ceab2 100644
--- a/code/game/objects/effects/spawners/random/misc_item.dm
+++ b/code/game/objects/effects/spawners/random/misc_item.dm
@@ -259,7 +259,7 @@
/obj/item/trash/tgmc_tray,
/obj/item/trash/boonie,
/obj/item/trash/chunk,
- /obj/item/trash/barcardine,
+ /obj/item/trash/barcaridine,
/obj/item/trash/mre,
/obj/item/trash/berrybar,
)
diff --git a/code/game/objects/effects/temporary_visuals/explosions.dm b/code/game/objects/effects/temporary_visuals/explosions.dm
index 6ca16156905c3..175a2f14c940a 100644
--- a/code/game/objects/effects/temporary_visuals/explosions.dm
+++ b/code/game/objects/effects/temporary_visuals/explosions.dm
@@ -323,3 +323,63 @@
QDEL_NULL(falling_debris)
QDEL_NULL(dirt_kickup)
return ..()
+
+/obj/effect/temp_visual/rappel_dust
+ duration = 25
+ ///smoke wave particle holder
+ var/obj/effect/abstract/particle_holder/smoke_wave
+ ///debris dirt kickup particle holder
+ var/obj/effect/abstract/particle_holder/dirt_kickup
+ ///falling debris particle holder
+ var/obj/effect/abstract/particle_holder/falling_debris
+ ///large dirt kickup particle holder
+ var/obj/effect/abstract/particle_holder/large_kickup
+
+/obj/effect/temp_visual/rappel_dust/Initialize(mapload, radius, small = FALSE, large = FALSE)
+ . = ..()
+ var/turf/turf_type = get_turf(src)
+ if(iswater(turf_type))
+ smoke_wave = new(src, /particles/wave_water)
+ dirt_kickup = new(src, /particles/water_splash)
+ falling_debris = new(src, /particles/water_falling)
+ large_kickup = new(src, /particles/water_splash_large)
+ else
+ if(small)
+ smoke_wave = new(src, /particles/smoke_wave/small)
+ else
+ smoke_wave = new(src, /particles/smoke_wave)
+
+ dirt_kickup = new(src, /particles/dirt_kickup)
+ if(small)
+ falling_debris = new(src, /particles/falling_debris/small)
+ else
+ falling_debris = new(src, /particles/falling_debris)
+
+ if(large)
+ large_kickup = new(src, /particles/dirt_kickup_large/deva)
+ else
+ large_kickup = new(src, /particles/dirt_kickup_large)
+
+ if(large)
+ smoke_wave.particles.velocity = generator(GEN_CIRCLE, 6 * radius, 6 * radius)
+ else if(small)
+ smoke_wave.particles.velocity = generator(GEN_CIRCLE, 3 * radius, 3 * radius)
+ else
+ smoke_wave.particles.velocity = generator(GEN_CIRCLE, 5 * radius, 5 * radius)
+ addtimer(CALLBACK(src, PROC_REF(set_count_short)), 5)
+ addtimer(CALLBACK(src, PROC_REF(set_count_long)), 10)
+
+/obj/effect/temp_visual/rappel_dust/proc/set_count_short()
+ smoke_wave.particles.count = 0
+ large_kickup.particles.count = 0
+ falling_debris.particles.count = 0
+
+/obj/effect/temp_visual/rappel_dust/proc/set_count_long()
+ dirt_kickup.particles.count = 0
+
+/obj/effect/temp_visual/rappel_dust/Destroy()
+ QDEL_NULL(smoke_wave)
+ QDEL_NULL(large_kickup)
+ QDEL_NULL(falling_debris)
+ QDEL_NULL(dirt_kickup)
+ return ..()
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 67db013e29dc1..78d19c0d857d9 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -114,14 +114,21 @@ GLOBAL_LIST_EMPTY(blood_particles)
opacity = FALSE
anchored = FALSE
animate_movement = SLIDE_STEPS
+ randomdir = FALSE
+ vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID
/obj/effect/temp_visual/xenomorph/afterimage/Initialize(mapload, atom/owner)
. = ..()
- appearance = owner.appearance
- setDir(owner.dir)
- alpha = initial(alpha)
- layer = initial(layer)
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ var/mutable_appearance/xeno_afterimage = new()
+ xeno_afterimage.appearance = owner.appearance
+ xeno_afterimage.render_target = null
+ xeno_afterimage.density = initial(density)
+ xeno_afterimage.alpha = initial(alpha)
+ xeno_afterimage.appearance_flags = RESET_COLOR|RESET_ALPHA|PASS_MOUSE
+ xeno_afterimage.setDir(owner.dir)
+ xeno_afterimage.pixel_x = owner.pixel_x
+ xeno_afterimage.pixel_y = owner.pixel_y
+ appearance = xeno_afterimage
animate(src, alpha = 0, time = duration)
/obj/effect/temp_visual/ob_impact
@@ -168,7 +175,7 @@ GLOBAL_LIST_EMPTY(blood_particles)
var/marker_flags = GLOB.faction_to_minimap_flag[faction]
if(marker_flags)
- SSminimaps.add_marker(src, marker_flags, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, icon_state_on, VERY_HIGH_FLOAT_LAYER))
+ SSminimaps.add_marker(src, marker_flags, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, icon_state_on, VERY_HIGH_FLOAT_LAYER)) //RUTGMC EDIT
set_visuals(faction)
/obj/effect/temp_visual/order/attack_order
diff --git a/code/game/objects/effects/temporary_visuals/temporary_visual.dm b/code/game/objects/effects/temporary_visuals/temporary_visual.dm
index b0b1eb4b0cd99..ad1089e5e6f9b 100644
--- a/code/game/objects/effects/temporary_visuals/temporary_visual.dm
+++ b/code/game/objects/effects/temporary_visuals/temporary_visual.dm
@@ -4,9 +4,13 @@
anchored = TRUE
layer = ABOVE_MOB_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ ///How long before the temp_visual gets deleted
var/duration = 1 SECONDS
- var/randomdir = TRUE
+ ///Timer that our duration is stored in
var/timerid
+ ///Gives our effect a random direction on init
+ var/randomdir = TRUE
+
/obj/effect/temp_visual/Initialize(mapload)
diff --git a/code/game/objects/effects/weeds.dm b/code/game/objects/effects/weeds.dm
index 1cea8b0dd0e3f..55fa140a8c8dc 100644
--- a/code/game/objects/effects/weeds.dm
+++ b/code/game/objects/effects/weeds.dm
@@ -190,6 +190,7 @@
icon_state = "weedwall"
/obj/alien/weeds/weedwall/update_icon_state()
+ . = ..()
var/turf/closed/wall/W = loc
if(!istype(W))
icon_state = initial(icon_state)
@@ -208,6 +209,7 @@
var/window_type = /obj/structure/window/framed
/obj/alien/weeds/weedwall/window/update_icon_state()
+ . = ..()
var/obj/structure/window/framed/F = locate() in loc
icon_state = F?.smoothing_junction ? "weedwall-[F.smoothing_junction]" : initial(icon_state)
if(color_variant == STICKY_COLOR)
@@ -221,11 +223,11 @@
return ..()
return window.MouseDrop_T(dropping, user)
-/obj/alien/weeds/weedwall/window/specialclick(mob/living/carbon/user)
+/obj/alien/weeds/weedwall/window/CtrlClick(mob/living/carbon/user)
var/obj/structure/window = locate(window_type) in loc
if(!window)
return ..()
- return window.specialclick(user)
+ return window.CtrlClick(user)
/obj/alien/weeds/weedwall/window/attackby(obj/item/I, mob/user, params) //yes, this blocks attacking the weed itself, but if you destroy the frame you destroy the weed!
var/obj/structure/window = locate(window_type) in loc
@@ -233,11 +235,11 @@
return ..()
return window.attackby(I, user, params)
-/obj/alien/weeds/weedwall/window/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/alien/weeds/weedwall/window/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
var/obj/structure/window = locate(window_type) in loc
if(!window)
return ..()
- return window.attack_alien(X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+ return window.attack_alien(xeno_attacker, damage_amount, damage_type, armor_type, effects, armor_penetration, isrightclick)
/obj/alien/weeds/weedwall/window/frame
window_type = /obj/structure/window_frame
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 3e060d5c959a1..9254e86376784 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -10,8 +10,9 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
light_system = MOVABLE_LIGHT
allow_pass_flags = PASS_LOW_STRUCTURE
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
resistance_flags = PROJECTILE_IMMUNE
+ move_resist = MOVE_FORCE_WEAK
var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
///The iconstate that the items use for blood on blood.dmi when drawn on the mob.
@@ -36,21 +37,21 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
var/hitsound = null
var/w_class = WEIGHT_CLASS_NORMAL
- var/flags_item = NONE //flags for item stuff that isn't clothing/equipping specific.
- var/flags_equip_slot = NONE //This is used to determine on which slots an item can fit.
+ var/item_flags = NONE //flags for item stuff that isn't clothing/equipping specific.
+ var/equip_slot_flags = NONE //This is used to determine on which slots an item can fit.
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
- var/flags_inventory = NONE //This flag is used for various clothing/equipment item stuff
- var/flags_inv_hide = NONE //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
+ var/inventory_flags = NONE //This flag is used for various clothing/equipment item stuff
+ var/inv_hide_flags = NONE //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
var/obj/item/master = null
- var/flags_armor_protection = NONE //see setup.dm for appropriate bit flags
- var/flags_heat_protection = NONE //flags which determine which body parts are protected from heat. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
- var/flags_cold_protection = NONE //flags which determine which body parts are protected from cold. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
+ var/armor_protection_flags = NONE //see setup.dm for appropriate bit flags
+ var/heat_protection_flags = NONE //flags which determine which body parts are protected from heat. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
+ var/cold_protection_flags = NONE //flags which determine which body parts are protected from cold. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
- var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by flags_heat_protection flags
- var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by flags_cold_protection flags
+ var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection_flags flags
+ var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection_flags flags
///list of /datum/action's that this item has.
var/list/actions
@@ -123,7 +124,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
///Worn inhand overlay will be shifted by this along y axis
var/inhand_y_offset = 0
- var/flags_item_map_variant = NONE
+ var/item_map_variant_flags = NONE
//TOOL RELATED VARS
var/tool_behaviour = FALSE
@@ -168,7 +169,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
else if(islist(embedding))
embedding = getEmbeddingBehavior(arglist(embedding))
- if(flags_item_map_variant)
+ if(item_map_variant_flags)
update_item_sprites()
if(current_variant)
@@ -183,12 +184,22 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
master = null
embedding = null
embedded_into = null //Should have been removed by temporarilyRemoveItemFromInventory, but let's play it safe.
- GLOB.cryoed_item_list -= src
+ GLOB.cryoed_item_list_gun -= src
+ GLOB.cryoed_item_list_ammo -= src
+ GLOB.cryoed_item_list_explosive -= src
+ GLOB.cryoed_item_list_melee -= src
+ GLOB.cryoed_item_list_clothing -= src
+ GLOB.cryoed_item_list_food -= src
+ GLOB.cryoed_item_list_drugs -= src
+ GLOB.cryoed_item_list_containers -= src
+ GLOB.cryoed_item_list_other -= src
return ..()
+/obj/item/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ return
/obj/item/proc/update_item_state(mob/user)
- item_state = "[initial(icon_state)][flags_item & WIELDED ? "_w" : ""]"
+ item_state = "[initial(icon_state)][item_flags & WIELDED ? "_w" : ""]"
//user: The mob that is suiciding
@@ -278,6 +289,8 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
// I have cleaned it up a little, but it could probably use more. -Sayu
/obj/item/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/facepaint) && colorable_allowed != NONE)
color_item(I, user)
@@ -337,9 +350,9 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
// apparently called whenever an item is removed from a slot, container, or anything else.
//the call happens after the item's potential loc change.
/obj/item/proc/dropped(mob/user)
- if((flags_item & DELONDROP) && !QDELETED(src))
+ if((item_flags & DELONDROP) && !QDELETED(src))
qdel(src)
- flags_item &= ~IN_INVENTORY
+ item_flags &= ~IN_INVENTORY
SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user)
///Called whenever an item is unequipped to a new loc (IE, not when the item ends up in the hands)
@@ -370,7 +383,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
limb_count++
UPDATEHEALTH(H)
QDEL_NULL(current_acid)
- flags_item |= IN_INVENTORY
+ item_flags |= IN_INVENTORY
return
///Called to return an item to equip using the quick equip hotkey. Base proc returns the item itself, overridden for storage behavior.
@@ -402,8 +415,8 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
SHOULD_CALL_PARENT(TRUE) // no exceptions
SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot)
- var/equipped_to_slot = flags_equip_slot & slotdefine2slotbit(slot)
- if(equipped_to_slot) // flags_equip_slot is a bitfield
+ var/equipped_to_slot = equip_slot_flags & slotdefine2slotbit(slot)
+ if(equipped_to_slot) // equip_slot_flags is a bitfield
SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED_TO_SLOT, user, slot)
else
SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED_NOT_IN_SLOT, user, slot)
@@ -412,17 +425,17 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
if(item_action_slot_check(user, slot)) //some items only give their actions buttons when in a specific slot.
A.give_action(user)
- flags_item |= IN_INVENTORY
+ item_flags |= IN_INVENTORY
if(!equipped_to_slot)
return
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
- if(flags_armor_protection)
+ if(armor_protection_flags)
human_user.add_limb_armor(src)
if(slowdown)
- human_user.add_movespeed_modifier(type, TRUE, 0, (flags_item & IMPEDE_JETPACK) ? SLOWDOWN_IMPEDE_JETPACK : NONE, TRUE, slowdown)
+ human_user.add_movespeed_modifier(type, TRUE, 0, (item_flags & IMPEDE_JETPACK) ? SLOWDOWN_IMPEDE_JETPACK : NONE, TRUE, slowdown)
///Called when an item is removed from an equipment slot. The loc should still be in the unequipper.
@@ -430,7 +443,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_UNEQUIPPED, unequipper, slot)
- var/equipped_from_slot = flags_equip_slot & slotdefine2slotbit(slot)
+ var/equipped_from_slot = equip_slot_flags & slotdefine2slotbit(slot)
for(var/datum/action/A AS in actions)
A.remove_action(unequipper)
@@ -440,7 +453,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
if(ishuman(unequipper))
var/mob/living/carbon/human/human_unequipper = unequipper
- if(flags_armor_protection)
+ if(armor_protection_flags)
human_unequipper.remove_limb_armor(src)
if(slowdown)
human_unequipper.remove_movespeed_modifier(type)
@@ -462,12 +475,12 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
///Used to enable/disable an item's bump attack. Grouped in a proc to make sure the signal or flags aren't missed
/obj/item/proc/toggle_item_bump_attack(mob/user, enable_bump_attack)
SEND_SIGNAL(user, COMSIG_ITEM_TOGGLE_BUMP_ATTACK, enable_bump_attack)
- if(flags_item & CAN_BUMP_ATTACK && enable_bump_attack)
+ if(item_flags & CAN_BUMP_ATTACK && enable_bump_attack)
return
if(enable_bump_attack)
- flags_item |= CAN_BUMP_ATTACK
+ item_flags |= CAN_BUMP_ATTACK
return
- flags_item &= ~CAN_BUMP_ATTACK
+ item_flags &= ~CAN_BUMP_ATTACK
/**
* The mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't.
@@ -504,7 +517,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
if(!is_type_in_list(H.species, species_exception))
return FALSE
- if(issynth(H) && CHECK_BITFIELD(flags_item, SYNTH_RESTRICTED) && !CONFIG_GET(flag/allow_synthetic_gun_use))
+ if(issynth(H) && CHECK_BITFIELD(item_flags, SYNTH_RESTRICTED) && !CONFIG_GET(flag/allow_synthetic_gun_use))
to_chat(H, span_warning("Your programming prevents you from wearing this."))
return FALSE
@@ -653,7 +666,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
return FALSE //Unsupported slot
if(equip_to_slot)
- if(!(flags_equip_slot & slotdefine2slotbit(slot)))
+ if(!(equip_slot_flags & slotdefine2slotbit(slot)))
return FALSE
return TRUE
@@ -692,7 +705,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
/obj/item/proc/update_item_sprites()
switch(SSmapping.configs[GROUND_MAP].armor_style)
if(MAP_ARMOR_STYLE_JUNGLE)
- if(flags_item_map_variant & ITEM_JUNGLE_VARIANT)
+ if(item_map_variant_flags & ITEM_JUNGLE_VARIANT)
if(colorable_allowed & PRESET_COLORS_ALLOWED)
greyscale_colors = ARMOR_PALETTE_BLACK //RUTGMC edit - black instead of default drab
else if(colorable_allowed & ICON_STATE_VARIANTS_ALLOWED)
@@ -701,7 +714,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
icon_state = "m_[icon_state]"
item_state = "m_[item_state]"
if(MAP_ARMOR_STYLE_ICE)
- if(flags_item_map_variant & ITEM_ICE_VARIANT)
+ if(item_map_variant_flags & ITEM_ICE_VARIANT)
if(colorable_allowed & PRESET_COLORS_ALLOWED)
greyscale_colors = ARMOR_PALETTE_SNOW
else if(colorable_allowed & ICON_STATE_VARIANTS_ALLOWED)
@@ -710,7 +723,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
icon_state = "s_[icon_state]"
item_state = "s_[item_state]"
if(MAP_ARMOR_STYLE_PRISON)
- if(flags_item_map_variant & ITEM_PRISON_VARIANT)
+ if(item_map_variant_flags & ITEM_PRISON_VARIANT)
if(colorable_allowed & PRESET_COLORS_ALLOWED)
greyscale_colors = ARMOR_PALETTE_BLACK
else if(colorable_allowed & ICON_STATE_VARIANTS_ALLOWED)
@@ -719,13 +732,13 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
icon_state = "k_[icon_state]"
item_state = "k_[item_state]"
if(MAP_ARMOR_STYLE_DESERT)
- if(flags_item_map_variant & ITEM_DESERT_VARIANT)
+ if(item_map_variant_flags & ITEM_DESERT_VARIANT)
if(colorable_allowed & PRESET_COLORS_ALLOWED)
greyscale_colors = ARMOR_PALETTE_DESERT
else if(colorable_allowed & ICON_STATE_VARIANTS_ALLOWED)
current_variant = DESERT_VARIANT
- if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD] && (flags_item_map_variant & ITEM_ICE_PROTECTION))
+ if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD] && (item_map_variant_flags & ITEM_ICE_PROTECTION))
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
if(!greyscale_colors)
@@ -824,7 +837,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
//The default action is attack_self().
//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob.
/obj/item/proc/ui_action_click(mob/user, datum/action/item_action/action)
- attack_self(user)
+ return attack_self(user)
/obj/item/proc/toggle_item_state(mob/user)
SHOULD_CALL_PARENT(TRUE)
@@ -836,7 +849,7 @@ GLOBAL_DATUM_INIT(welding_sparks_prepdoor, /mutable_appearance, mutable_appearan
set category = "Object"
var/obj/item/I = get_active_held_item()
- if(I && !(I.flags_item & ITEM_ABSTRACT))
+ if(I && !(I.item_flags & ITEM_ABSTRACT))
visible_message("[src] holds up [I]. Take a closer look.")
/*
@@ -996,7 +1009,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
//This proc is here to prevent Xenomorphs from picking up objects (default attack_hand behaviour)
//Note that this is overriden by every proc concerning a child of obj unless inherited
-/obj/item/attack_alien(mob/living/carbon/xenomorph/X, isrightclick = FALSE)
+/obj/item/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
return FALSE
@@ -1011,7 +1024,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
return
user.visible_message(span_danger("[user] sprays water from [src]!"), \
- span_warning("You spray water from [src]."),)
+ span_warning("You spray water from [src]."))
playsound(user.loc, 'sound/effects/extinguish.ogg', 52, 1, 7)
@@ -1238,16 +1251,14 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
return icon_override
//2: species-specific sprite sheets.
- var/icon = LAZYACCESS(sprite_sheets, species_type)
- if(icon && !inhands)
- return icon
+ . = LAZYACCESS(sprite_sheets, species_type)
+ if(. && !inhands)
+ return
//3: slot-specific sprite sheets
- icon = LAZYACCESS(item_icons, slot_name)
- if(ispath(icon, /datum/greyscale_config))
- return SSgreyscale.GetColoredIconByType(icon, greyscale_colors)
- if(icon)
- return icon
+ . = LAZYACCESS(item_icons, slot_name)
+ if(.)
+ return
//5: provided default_icon
if(default_icon)
@@ -1383,9 +1394,9 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
///Handles registering if an item is flagged as deployed or not
/obj/item/proc/toggle_deployment_flag(deployed)
if(deployed)
- ENABLE_BITFIELD(flags_item, IS_DEPLOYED)
+ ENABLE_BITFIELD(item_flags, IS_DEPLOYED)
else
- DISABLE_BITFIELD(flags_item, IS_DEPLOYED)
+ DISABLE_BITFIELD(item_flags, IS_DEPLOYED)
///Called by vendors when vending an item. Allows the item to specify what happens when it is given to the player.
/obj/item/proc/on_vend(mob/user, faction, fill_container = FALSE, auto_equip = FALSE)
diff --git a/code/game/objects/items/ashtray.dm b/code/game/objects/items/ashtray.dm
index 1304a5f2dd228..537932d6c71f9 100644
--- a/code/game/objects/items/ashtray.dm
+++ b/code/game/objects/items/ashtray.dm
@@ -14,6 +14,8 @@
/obj/item/ashtray/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/trash/cigbutt) || istype(I, /obj/item/clothing/mask/cigarette) || istype(I, /obj/item/tool/match))
if(length(contents) >= max_butts)
@@ -43,22 +45,29 @@
AM.forceMove(loc)
return ..()
-
-/obj/item/ashtray/update_icon()
+/obj/item/ashtray/update_desc(updates)
+ . = ..()
if(length(contents) >= max_butts)
- icon_state = icon_full
desc = empty_desc + " It's stuffed full."
return
if(length(contents) >= max_butts / 2)
- icon_state = icon_half
desc = empty_desc + " It's half-filled."
return
- icon_state = icon_empty
desc = empty_desc
+/obj/item/ashtray/update_icon_state()
+ . = ..()
+ if(length(contents) >= max_butts)
+ icon_state = icon_full
+ return
+ if(length(contents) >= max_butts / 2)
+ icon_state = icon_half
+ return
+
+ icon_state = icon_empty
/obj/item/ashtray/plastic
name = "plastic ashtray"
diff --git a/code/game/objects/items/autopsy_scanner.dm b/code/game/objects/items/autopsy_scanner.dm
index f4231813c6e4f..07ba8d87c6908 100644
--- a/code/game/objects/items/autopsy_scanner.dm
+++ b/code/game/objects/items/autopsy_scanner.dm
@@ -2,5 +2,5 @@
name = "autopsy scanner"
desc = "Extracts information on wounds."
icon_state = "autopsy_scanner"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_SMALL
diff --git a/code/game/objects/items/binoculars.dm b/code/game/objects/items/binoculars.dm
index aec8800e7bd1c..55b7033bf6465 100644
--- a/code/game/objects/items/binoculars.dm
+++ b/code/game/objects/items/binoculars.dm
@@ -7,7 +7,7 @@
slot_l_hand_str = 'icons/mob/inhands/equipment/binoculars_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/equipment/binoculars_right.dmi',
)
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 5
w_class = WEIGHT_CLASS_SMALL
throwforce = 5
@@ -225,7 +225,7 @@
to_chat(user, span_notice("INITIATING LASER TARGETING. Stand still."))
if(!do_after(user, max(1.5 SECONDS, target_acquisition_delay - (2.5 SECONDS * user.skills.getRating(SKILL_LEADERSHIP))), NONE, TU, BUSY_ICON_GENERIC) || world.time < laser_cooldown || laser)
return
- if(targ_area.flags_area & OB_CAS_IMMUNE)
+ if(targ_area.area_flags & OB_CAS_IMMUNE)
to_chat(user, span_warning("Our payload won't reach this target!"))
return
switch(mode)
@@ -250,7 +250,7 @@
mortar.recieve_target(TU,user)
return
if(MODE_RAILGUN)
- if(SSticker?.mode?.flags_round_type & MODE_DISALLOW_RAILGUN)
+ if(SSticker?.mode?.round_type_flags & MODE_DISALLOW_RAILGUN)
to_chat(user, span_notice("ERROR. NO LINKED RAILGUN DETECTED. UNABLE TO FIRE."))
return
to_chat(user, span_notice("ACQUIRING TARGET. RAILGUN TRIANGULATING. DON'T MOVE."))
diff --git a/code/game/objects/items/blink_drive.dm b/code/game/objects/items/blink_drive.dm
index 4d5f031511e5e..5592cc1a24dc0 100644
--- a/code/game/objects/items/blink_drive.dm
+++ b/code/game/objects/items/blink_drive.dm
@@ -12,21 +12,25 @@
)
icon_state = "bluespace_pack"
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
obj_flags = CAN_BE_HIT
light_range = 0.1
light_power = 0.1
light_color = LIGHT_COLOR_BLUE
///Number of teleport charges you currently have
var/charges = 3
- ///True if you can use shift click/middle click to use it
- var/selected = FALSE
///The timer for recharging the drive
var/charge_timer
///The mob wearing the blink drive. Needed for item updates.
var/mob/equipped_user
+ ///Controlling action
+ var/datum/action/ability/activable/item_toggle/blink_drive/blink_action
COOLDOWN_DECLARE(blink_stability_cooldown)
+/obj/item/blink_drive/Initialize(mapload)
+ . = ..()
+ blink_action = new(src)
+
/obj/item/blink_drive/update_icon()
. = ..()
equipped_user?.update_inv_back()
@@ -52,68 +56,28 @@
. = ..()
equipped_user = user
if(slot == SLOT_BACK)
- RegisterSignal(user, COMSIG_MOB_CLICK_ALT_RIGHT, PROC_REF(can_use))
- var/datum/action/item_action/toggle/action = new(src)
- action.give_action(user)
+ blink_action.give_action(user)
/obj/item/blink_drive/dropped(mob/user)
. = ..()
- UnregisterSignal(user, list(COMSIG_MOB_CLICK_ALT_RIGHT, COMSIG_MOB_MIDDLE_CLICK))
- UnregisterSignal(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE)
- selected = FALSE
+ blink_action.remove_action(user)
equipped_user = null
- LAZYCLEARLIST(actions)
-/obj/item/blink_drive/ui_action_click(mob/user, datum/action/item_action/action)
- if(selected)
- UnregisterSignal(user, COMSIG_MOB_MIDDLE_CLICK)
- action.set_toggle(FALSE)
- UnregisterSignal(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE)
- else
- RegisterSignal(user, COMSIG_MOB_MIDDLE_CLICK, PROC_REF(can_use))
- action.set_toggle(TRUE)
- SEND_SIGNAL(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE, user)
- RegisterSignal(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE, PROC_REF(unselect))
- selected = !selected
/obj/item/blink_drive/apply_custom(mutable_appearance/standing, inhands, icon_used, state_used)
. = ..()
var/mutable_appearance/emissive_overlay = emissive_appearance(icon_used, "[state_used]_emissive")
standing.overlays.Add(emissive_overlay)
-///Signal handler for making it impossible to use middleclick to use the blink drive
-/obj/item/blink_drive/proc/unselect(datum/source, mob/user)
- SIGNAL_HANDLER
- if(!selected)
- return
- selected = FALSE
- UnregisterSignal(user, COMSIG_MOB_MIDDLE_CLICK)
- UnregisterSignal(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE)
-
- for(var/action in user.actions)
- if(!istype(action, /datum/action/item_action))
- continue
- var/datum/action/item_action/iaction = action
- if(iaction?.holder_item == src)
- iaction.set_toggle(FALSE)
-
-///Check if we can use the blink drive and give feedback to the user
-/obj/item/blink_drive/proc/can_use(datum/source, atom/A)
- SIGNAL_HANDLER
- var/mob/living/carbon/human/human_user = usr
- if(human_user.incapacitated() || human_user.lying_angle)
- return
- if(is_mainship_level(human_user.z))
- human_user.balloon_alert(human_user, "can't use here")
- return
- if(charges <= 0)
- human_user.balloon_alert(human_user, "no charge")
- playsound(src, 'sound/items/blink_empty.ogg', 25, 1)
- return
- INVOKE_ASYNC(src, PROC_REF(teleport), A, human_user)
+/obj/item/blink_drive/ui_action_click(mob/user, datum/action/item_action/action, target)
+ return teleport(target, user)
///Handles the actual teleportation
/obj/item/blink_drive/proc/teleport(atom/A, mob/user)
+ if(charges <= 0)
+ user.balloon_alert(user, "no charge")
+ playsound(src, 'sound/items/blink_empty.ogg', 25, 1)
+ return
var/turf/target_turf = get_turf(A)
if(target_turf == user.loc)
@@ -165,6 +129,7 @@
deltimer(charge_timer)
charge_timer = addtimer(CALLBACK(src, PROC_REF(recharge)), BLINK_DRIVE_CHARGE_TIME * 2, TIMER_STOPPABLE)
update_icon()
+ return TRUE
///Recharges the drive, and sets another timer if not maxed out
/obj/item/blink_drive/proc/recharge()
@@ -219,3 +184,19 @@
traits += "Shared use: If the user has grabbed another mob when activating the drive, the grabbed mob will be teleported with them. "
. += jointext(traits, " ")
+
+/datum/action/ability/activable/item_toggle/blink_drive
+ name = "Use Blink Drive"
+ action_icon_state = "axe_sweep"
+ desc = "Teleport a short distance instantly."
+ use_state_flags = ABILITY_USE_STAGGERED|ABILITY_USE_BUSY
+ keybinding_signals = list(KEYBINDING_NORMAL = COMSIG_ITEM_TOGGLE_BLINKDRIVE)
+
+/datum/action/ability/activable/item_toggle/blink_drive/can_use_ability(silent, override_flags, selecting)
+ var/mob/living/carbon/carbon_owner = owner
+ if(carbon_owner.incapacitated() || carbon_owner.lying_angle)
+ return FALSE
+ if(is_mainship_level(carbon_owner.z))
+ carbon_owner.balloon_alert(carbon_owner, "can't use here")
+ return FALSE
+ return ..()
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index d0b930b3f098d..0b802f8bdf236 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -68,6 +68,8 @@
var/obj/item/bodybag/foldedbag_instance = null
var/obj/structure/bed/roller/roller_buckled //the roller bed this bodybag is attached to.
var/mob/living/bodybag_occupant
+ ///Should the name of the person inside be displayed?
+ var/display_name = TRUE
/obj/structure/closet/bodybag/Initialize(mapload, foldedbag)
@@ -94,7 +96,10 @@
return ..()
-/obj/structure/closet/bodybag/proc/update_name()
+/obj/structure/closet/bodybag/update_name(updates)
+ . = ..()
+ if(!display_name)
+ return
if(opened)
name = bag_name
else
@@ -106,6 +111,8 @@
/obj/structure/closet/bodybag/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen))
var/t = stripped_input(user, "What would you like the label to be?", name, null, MAX_MESSAGE_LEN)
@@ -145,7 +152,7 @@
var/mob/living/carbon/human/new_guest = locate() in contents
if(new_guest)
bodybag_occupant = new_guest
- update_name()
+ update_appearance()
return TRUE
return FALSE
@@ -154,7 +161,7 @@
. = ..()
if(bodybag_occupant)
bodybag_occupant = null
- update_name()
+ update_appearance()
/obj/structure/closet/bodybag/MouseDrop(over_object, src_location, over_location)
@@ -188,7 +195,8 @@
return ..()
-/obj/structure/closet/bodybag/update_icon()
+/obj/structure/closet/bodybag/update_icon_state()
+ . = ..()
if(!opened)
icon_state = icon_closed
for(var/mob/living/L in contents)
@@ -198,15 +206,15 @@
icon_state = icon_opened
-/obj/structure/closet/bodybag/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/closet/bodybag/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(opened)
return FALSE // stop xeno closing things
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- bodybag_occupant?.attack_alien(X)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ bodybag_occupant?.attack_alien(xeno_attacker)
open()
- X.visible_message(span_danger("\The [X] slashes \the [src] open!"), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] slashes \the [src] open!"), \
span_danger("We slash \the [src] open!"), null, 5)
return TRUE
@@ -326,19 +334,34 @@
/obj/structure/closet/bodybag/cryobag/examine(mob/living/user)
. = ..()
- if(!ishuman(bodybag_occupant))
+ var/mob/living/carbon/human/occupant = bodybag_occupant
+ if(!ishuman(occupant))
return
if(!hasHUD(user,"medical"))
return
for(var/datum/data/record/medical_record AS in GLOB.datacore.medical)
- if(medical_record.fields["name"] != bodybag_occupant.real_name)
+ if(medical_record.fields["name"] != occupant.real_name)
continue
if(!(medical_record.fields["last_scan_time"]))
. += "No scan report on record"
else
. += "Scan from [medical_record.fields["last_scan_time"]]"
break
-
+ if(occupant.stat != DEAD)
+ return
+ var/timer = 0 // variable for DNR timer check
+ timer = (TIME_BEFORE_DNR-(occupant.dead_ticks))*2 //Time to DNR left in seconds
+ if(!occupant.mind && !occupant.get_ghost(TRUE) || occupant.dead_ticks > TIME_BEFORE_DNR || occupant.suiciding) //We couldn't find a suitable ghost or patient has passed their DNR timer or suicided, this means the person is not returning
+ . += span_scanner("Patient is DNR")
+ else if(!occupant.mind && occupant.get_ghost(TRUE)) // Ghost is available but outside of the body
+ . += span_scanner("Defib patient to check departed status")
+ . += span_scanner("Patient have [timer] seconds left before DNR")
+ else if(!occupant.client) //Mind is in the body but no client, most likely currently disconnected.
+ . += span_scanner("Patient is almost departed")
+ . += span_scanner("Patient have [timer] seconds left before DNR")
+ else
+ . += span_scanner("Patient have [timer] seconds left before DNR")
+
/obj/structure/closet/bodybag/cryobag/Topic(href, href_list)
. = ..()
@@ -416,6 +439,7 @@
close_sound = 'sound/effects/vegetation_walk_2.ogg'
foldedbag_path = /obj/item/bodybag/tarp
closet_stun_delay = 0.5 SECONDS //Short delay to prevent ambushes from being too degenerate.
+ display_name = FALSE
var/serial_number //Randomized serial number used to stop point macros and such.
@@ -453,11 +477,6 @@
SIGNAL_HANDLER
open()
-
-/obj/structure/closet/bodybag/tarp/update_name()
- return //Shouldn't be revealing who's inside.
-
-
/obj/structure/closet/bodybag/tarp/MouseDrop(over_object, src_location, over_location)
. = ..()
var/obj/item/bodybag/tarp/folded_tarp = foldedbag_instance
diff --git a/code/game/objects/items/books/book.dm b/code/game/objects/items/books/book.dm
index 9b5b08a224639..383cc39b5bc2b 100644
--- a/code/game/objects/items/books/book.dm
+++ b/code/game/objects/items/books/book.dm
@@ -45,6 +45,8 @@
/obj/item/book/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen))
if(unique)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index fc123ad2594a2..945a3c36d0671 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -67,7 +67,7 @@
desc = "It's a card with a magnetic strip attached to some circuitry."
name = "cryptographic sequencer"
icon_state = "emag"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
/obj/item/card/id
@@ -76,7 +76,9 @@
icon_state = "id"
var/access = list()
var/registered_name = "Unknown" // The name registered_name on the card
- flags_equip_slot = ITEM_SLOT_ID
+ equip_slot_flags = ITEM_SLOT_ID
+ ///Miscelaneous ID flags
+ var/id_flags = CAN_BUY_LOADOUT
var/blood_type = "\[UNSET\]"
@@ -86,8 +88,6 @@
///What category of items can you buy - used for armor and poucehs
var/marine_buy_choices = list()
- var/can_buy_loadout = TRUE
-
//alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system
var/assignment = null //can be alt title or the actual job
var/rank = null //actual job
@@ -251,6 +251,7 @@
var/dogtag_taken = FALSE
/obj/item/card/id/dogtag/update_icon_state()
+ . = ..()
if(dogtag_taken)
icon_state = initial(icon_state) + "_taken"
return
@@ -340,6 +341,8 @@
/obj/item/dogtag/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/dogtag))
var/obj/item/dogtag/D = I
diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm
index 93954a07aa4b9..9a99c8da7e7af 100644
--- a/code/game/objects/items/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/circuitboards/circuitboard.dm
@@ -8,7 +8,7 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
)
item_state = "electronic"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
var/build_path = null
//Called when the circuitboard is used to contruct a new machine.
diff --git a/code/game/objects/items/circuitboards/computer.dm b/code/game/objects/items/circuitboards/computer.dm
index 65e8a0371e7b8..0eb2433e62348 100644
--- a/code/game/objects/items/circuitboards/computer.dm
+++ b/code/game/objects/items/circuitboards/computer.dm
@@ -175,6 +175,8 @@
/obj/item/circuitboard/computer/security/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
if(!check_access(I))
diff --git a/code/game/objects/items/circuitboards/machine.dm b/code/game/objects/items/circuitboards/machine.dm
index 044e5626dfbc9..581ab737e0895 100644
--- a/code/game/objects/items/circuitboards/machine.dm
+++ b/code/game/objects/items/circuitboards/machine.dm
@@ -88,6 +88,8 @@ to destroy them and players will be able to make replacements.
/obj/item/circuitboard/machine/unary_atmos/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
machine_dir = turn(machine_dir, 90)
diff --git a/code/game/objects/items/cloaking.dm b/code/game/objects/items/cloaking.dm
index 0b33c71291553..f7c8e8acbd487 100644
--- a/code/game/objects/items/cloaking.dm
+++ b/code/game/objects/items/cloaking.dm
@@ -6,8 +6,8 @@
name = "chameleon-projector"
icon = 'icons/obj/device.dmi'
icon_state = "shield0"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
item_icons = list(
slot_l_hand_str = 'icons/mob/inhands/equipment/engineering_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
diff --git a/code/game/objects/items/cocoon.dm b/code/game/objects/items/cocoon.dm
index 46dfd2b7b3b4f..3e9cbcd756b8d 100644
--- a/code/game/objects/items/cocoon.dm
+++ b/code/game/objects/items/cocoon.dm
@@ -42,11 +42,12 @@
/obj/structure/cocoon/process()
var/psych_points_output = COCOON_PSY_POINTS_REWARD_MIN + ((HIGH_PLAYER_POP - SSmonitor.maximum_connected_players_count) / HIGH_PLAYER_POP * (COCOON_PSY_POINTS_REWARD_MAX - COCOON_PSY_POINTS_REWARD_MIN))
psych_points_output = clamp(psych_points_output, COCOON_PSY_POINTS_REWARD_MIN, COCOON_PSY_POINTS_REWARD_MAX)
- SSpoints.add_psy_points(hivenumber, psych_points_output)
+ SSpoints.add_strategic_psy_points(hivenumber, psych_points_output)
+ SSpoints.add_tactical_psy_points(hivenumber, psych_points_output*0.25)
//Gives marine cloneloss for a total of 30.
victim.adjustCloneLoss(0.5)
-/obj/structure/cocoon/take_damage(damage_amount, damage_type, damage_flag, effects, attack_dir, armour_penetration)
+/obj/structure/cocoon/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
. = ..()
if(anchored && obj_integrity < max_integrity / 2)
unanchor_from_nest()
@@ -115,6 +116,7 @@
return ..()
/obj/structure/cocoon/update_icon_state()
+ . = ..()
if(anchored)
icon_state = "xeno_cocoon"
return
diff --git a/code/game/objects/items/coins.dm b/code/game/objects/items/coins.dm
index a6cc0074219db..bb1a2c1f017ce 100644
--- a/code/game/objects/items/coins.dm
+++ b/code/game/objects/items/coins.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/items/items.dmi'
name = "Coin"
icon_state = "coin"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_TINY
var/string_attached
var/sides = 2
@@ -49,6 +49,8 @@
/obj/item/coin/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/CC = I
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index e1a48cd55d424..44cc2c3024f7c 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -31,33 +31,33 @@
icon_state = "full_camo"
-/obj/item/facepaint/attack(mob/M as mob, mob/user as mob)
- if(!ismob(M)) return
+/obj/item/facepaint/attack(mob/M, mob/user)
+ . = ..()
+ if(!ishuman(M))
+ to_chat(user, span_warning("Foiled!"))
+ return
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.lip_style) //if they already have lipstick on
- to_chat(user, span_warning("You need to wipe the old paint off with paper first!"))
- return
- if(H == user)
- paint_face(H, user)
- return 1
- else
- to_chat(user, span_notice("You attempt to apply [src] on [H]..."))
- to_chat(H, span_notice("[user] is trying to apply [src] on your face..."))
- if(tgui_alert(H, "Will you allow [user] to paint your face?", null, list("Sure","No")) == "Sure")
- if( user && loc == user && (user in range(1,H)) ) //Have to be close and hold the thing.
- paint_face(H, user)
- return 1
+ var/mob/living/carbon/human/attacked_human = M
+ if(attacked_human.makeup_style) //if they already have lipstick on
+ to_chat(user, span_warning("You need to wipe the old paint off with paper first!"))
+ return
- to_chat(user, span_warning("Foiled!"))
+ if(attacked_human != user && attacked_human.client)
+ user.visible_message(span_notice("[user] is trying to apply [src] on [attacked_human]'s face..."), span_notice("You attempt to apply [src] on [attacked_human]..."))
+ if(tgui_alert(attacked_human, "Apply makeup", "Will you allow [user] to paint your face?", list("Yes","No")) != "Yes")
+ return
+ if(!user || loc != user || !user.Adjacent(attacked_human))
+ return
+ paint_face(attacked_human, user)
+///Handles applying the makeup
/obj/item/facepaint/proc/paint_face(mob/living/carbon/human/H, mob/user)
- if(!H || !user) return //In case they're passed as null.
+ if(!H || !user)
+ return //In case they're passed as null.
user.visible_message(span_notice("[user] carefully applies [src] on [H]'s face."), \
span_notice("You apply [src]."))
- H.lip_style = colour
+ H.makeup_style = colour
H.alpha = max(0, initial(H.alpha) - 1) // decreases your alpha by 1
H.update_body()
uses--
@@ -66,5 +66,3 @@
user.update_inv_l_hand(0)
user.update_inv_r_hand()
qdel(src)
-
-//you can wipe off lipstick with paper! see code/modules/paperwork/paper.dm, paper/attack()
diff --git a/code/game/objects/items/defibrillator.dm b/code/game/objects/items/defibrillator.dm
index e5572f75c6ae5..45be80a9d6097 100644
--- a/code/game/objects/items/defibrillator.dm
+++ b/code/game/objects/items/defibrillator.dm
@@ -4,9 +4,9 @@
icon = 'icons/obj/items/defibrillator.dmi'
icon_state = "defib_full"
item_state = "defib"
- flags_atom = CONDUCT
- flags_item = NOBLUDGEON
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ item_flags = NOBLUDGEON
+ equip_slot_flags = ITEM_SLOT_BELT
force = 5
throwforce = 6
w_class = WEIGHT_CLASS_NORMAL
@@ -44,6 +44,7 @@
/obj/item/defibrillator/update_icon_state()
+ . = ..()
icon_state = "defib"
if(ready)
icon_state += "_out"
@@ -126,7 +127,7 @@
stack_trace("Powercell deleted while powering the defib, this isn't supposed to happen normally.")
set_dcell(null)
-/mob/living/proc/get_ghost()
+/mob/living/proc/get_ghost(bypass_client_check = FALSE)
if(client) //Let's call up the correct ghost!
return null
for(var/mob/dead/observer/ghost AS in GLOB.observer_list)
@@ -136,7 +137,7 @@
continue
if(ghost.can_reenter_corpse.resolve() != src)
continue
- if(ghost.client)
+ if(ghost.client || bypass_client_check)
return ghost
return null
@@ -196,17 +197,20 @@
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Patient's organs are too damaged to sustain life. Deliver patient to a MD for surgical intervention."))
return
- if((H.wear_suit && H.wear_suit.flags_atom & CONDUCT))
+ if((H.wear_suit && H.wear_suit.atom_flags & CONDUCT))
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Paddles registering >100,000 ohms, Possible cause: Suit or Armor interferring."))
return
var/mob/dead/observer/G = H.get_ghost()
if(G)
G.reenter_corpse()
- else if(!H.client)
+ else if(!H.mind && !H.get_ghost(TRUE))
//We couldn't find a suitable ghost, this means the person is not returning
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Patient has a DNR."))
return
+ else if(!H.client) //Currently disconnected.
+ user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Patient's soul has almost departed. Please try again."))
+ return
user.visible_message(span_notice("[user] starts setting up the paddles on [H]'s chest."),
span_notice("You start setting up the paddles on [H]'s chest."))
@@ -230,7 +234,7 @@
H.visible_message(span_danger("[H]'s body convulses a bit."))
defib_cooldown = world.time + 10 //1 second cooldown before you can shock again
- if(H.wear_suit && H.wear_suit.flags_atom & CONDUCT)
+ if(H.wear_suit && H.wear_suit.atom_flags & CONDUCT)
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Defibrillation failed: Paddles registering >100,000 ohms, Possible cause: Suit or Armor interferring."))
return
@@ -252,19 +256,19 @@
user.visible_message("[icon2html(src, viewers(user))] \The [src] buzzes: Positronic brain missing, cannot reboot.")
return
- if(!H.client) //Freak case, no client at all. This is a braindead mob (like a colonist)
+ if(!H.client) //Either client disconnected after being dragged in, ghosted, or this mob isn't a player (but that is caught way earlier).
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: No soul detected, Attempting to revive..."))
- if(H.mind && !H.client) //Let's call up the correct ghost! Also, bodies with clients only, thank you.
- G = H.get_ghost()
+ if(!H.mind) //Check if their ghost still exists if they aren't in their body.
+ G = H.get_ghost(TRUE)
if(istype(G))
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Defibrillation failed. Patient's soul has almost departed, please try again."))
return
- //We couldn't find a suitable ghost, this means the person is not returning
+ //No mind and no associated ghost exists. This one is DNR.
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Patient has a DNR."))
return
- if(!H.client) //Freak case, no client at all. This is a braindead mob (like a colonist) or someone who didn't enter their body in time.
+ if(!H.client) //No client, but has a mind. This means the player was in their body, but potentially disconnected.
user.visible_message(span_warning("[icon2html(src, viewers(user))] \The [src] buzzes: Defibrillation failed. No soul detected. Please try again."))
playsound(get_turf(src), 'sound/items/defib_failed.ogg', 35, 0)
return
@@ -310,10 +314,18 @@
H.updatehealth() //One more time, so it doesn't show the target as dead on HUDs
H.dead_ticks = 0 //We reset the DNR time
H.initial_stage = 0 // RUTGMC ADDITION
+
+ //Checks if our "patient" is wearing a camera. Then it turns it on if it's off.
+ if(istype(H.wear_ear, /obj/item/radio/headset/mainship))
+ var/obj/item/radio/headset/mainship/cam_headset = H.wear_ear
+ if(!(cam_headset?.camera?.status))
+ cam_headset.camera.toggle_cam(null, FALSE)
+
REMOVE_TRAIT(H, TRAIT_PSY_DRAINED, TRAIT_PSY_DRAINED)
if(user.client)
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
personal_statistics.revives++
+ personal_statistics.mission_revives++
GLOB.round_statistics.total_human_revives[H.faction]++
SSblackbox.record_feedback("tally", "round_statistics", 1, "total_human_revives[H.faction]")
to_chat(H, span_notice("You suddenly feel a spark and your consciousness returns, dragging you back to the mortal plane."))
@@ -330,47 +342,74 @@
icon_state = "civ_defib_full"
item_state = "defib"
+/obj/item/defibrillator/internal
+ icon = 'icons/obj/clothing/gloves.dmi' //even though you'll never see this directly, it shows up in the chat panel due to icon2html
+ ready = TRUE
+ ready_needed = FALSE
+ ///Parent item containing this defib
+ var/obj/parent_obj
+
+/obj/item/defibrillator/internal/Initialize(mapload, obj/new_parent)
+ if(!istype(new_parent))
+ return INITIALIZE_HINT_QDEL
+ parent_obj = new_parent
+ return ..()
+
+/obj/item/defibrillator/internal/Destroy()
+ parent_obj = null
+ return ..()
-/obj/item/defibrillator/gloves
+/obj/item/defibrillator/internal/update_icon()
+ . = ..()
+ parent_obj.update_icon()
+
+/obj/item/clothing/gloves/defibrillator
name = "advanced medical combat gloves"
- desc = "Advanced medical gloves, these include small electrodes to defibrilate a patiant. No more bulky units!"
- icon_state = "defib_gloves"
+ desc = "Advanced medical gloves, these include small electrodes to defibrilate a patient No more bulky units!"
+ icon_state = "defib_out_full"
item_state = "defib_gloves"
- ready = TRUE
- ready_needed = FALSE
- flags_equip_slot = ITEM_SLOT_GLOVES
- w_class = WEIGHT_CLASS_SMALL
- icon = 'icons/obj/clothing/gloves.dmi'
- item_state_worn = TRUE
- siemens_coefficient = 0.50
- blood_sprite_state = "bloodyhands"
- flags_armor_protection = HANDS
- flags_equip_slot = ITEM_SLOT_GLOVES
- attack_verb = "zaps"
soft_armor = list(MELEE = 25, BULLET = 15, LASER = 10, ENERGY = 15, BOMB = 15, BIO = 5, FIRE = 15, ACID = 15)
- flags_cold_protection = HANDS
- flags_heat_protection = HANDS
+ cold_protection_flags = HANDS
+ heat_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
+ ///The internal defib item
+ var/obj/item/defibrillator/internal/internal_defib
-/obj/item/defibrillator/gloves/equipped(mob/living/carbon/human/user, slot)
+/obj/item/clothing/gloves/defibrillator/Initialize(mapload)
+ . = ..()
+ internal_defib = new(src, src)
+ update_icon()
+
+/obj/item/clothing/gloves/defibrillator/Destroy()
+ internal_defib = null
+ return ..()
+
+/obj/item/clothing/gloves/defibrillator/equipped(mob/living/carbon/human/user, slot)
. = ..()
if(user.gloves == src)
RegisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
else
UnregisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK)
-/obj/item/defibrillator/gloves/unequipped(mob/living/carbon/human/user, slot)
+/obj/item/clothing/gloves/defibrillator/unequipped(mob/living/carbon/human/user, slot)
. = ..()
UnregisterSignal(user, COMSIG_HUMAN_MELEE_UNARMED_ATTACK) //Unregisters in the case of getting delimbed
+/obj/item/clothing/gloves/defibrillator/examine(mob/user)
+ . = ..()
+ . += internal_defib.maybe_message_recharge_hint()
+
+/obj/item/clothing/gloves/defibrillator/update_icon_state()
+ . = ..()
+ if(!internal_defib) //should only happen on init
+ return
+ icon_state = internal_defib.icon_state
+
//when you are wearing these gloves, this will call the normal attack code to begin defibing the target
-/obj/item/defibrillator/gloves/proc/on_unarmed_attack(mob/living/carbon/human/user, mob/living/carbon/human/target)
+/obj/item/clothing/gloves/defibrillator/proc/on_unarmed_attack(mob/living/carbon/human/user, mob/living/carbon/human/target)
+ SIGNAL_HANDLER
if(user.a_intent != INTENT_HELP)
return
if(istype(user) && istype(target))
- defibrillate(target, user)
-
-/obj/item/defibrillator/gloves/update_icon_state()
- return
-
+ INVOKE_ASYNC(internal_defib, TYPE_PROC_REF(/obj/item/defibrillator, defibrillate), target, user)
diff --git a/code/game/objects/items/devices/squad_transfer_tablet.dm b/code/game/objects/items/devices/squad_transfer_tablet.dm
index 7099a4b6a72d3..bbcc5fa7cccad 100644
--- a/code/game/objects/items/devices/squad_transfer_tablet.dm
+++ b/code/game/objects/items/devices/squad_transfer_tablet.dm
@@ -3,7 +3,7 @@
desc = "A tablet for quickly transfering the squaddies from under one incompetent squad leader to another."
icon = 'icons/Marine/marine-navigation.dmi'
icon_state = "req_tablet_off"
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_SMALL
interaction_flags = INTERACT_MACHINE_TGUI
/// REF()s for all currently active transfering marines
diff --git a/code/game/objects/items/devices/tablets.dm b/code/game/objects/items/devices/tablets.dm
index 53140f52d5904..297ae718e807a 100644
--- a/code/game/objects/items/devices/tablets.dm
+++ b/code/game/objects/items/devices/tablets.dm
@@ -4,7 +4,7 @@
icon = 'icons/Marine/marine-navigation.dmi'
icon_state = "req_tablet_off"
req_access = list(ACCESS_NT_CORPORATE)
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_SMALL
interaction_flags = INTERACT_MACHINE_TGUI
@@ -50,6 +50,11 @@
dat += " delta"
network = list("delta")
req_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DELTA)
+ else
+ var/lowername = lowertext(squad.name)
+ dat = dat + " " + lowername
+ network = list(lowername)
+ req_access = list(ACCESS_MARINE_LEADER)
dat += " squad leader's"
if(/datum/job/terragov/command/captain)
dat += " captain's"
@@ -61,8 +66,12 @@
req_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_LEADER)
if(/datum/job/terragov/command/pilot)
dat += " pilot's"
- network = list("dropship1", "dropship2")
+ network = list("dropship1")
req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_DROPSHIP)
+ if(/datum/job/terragov/command/transportofficer)
+ dat += " transport officer's"
+ network = list("dropship2")
+ req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE)
name = dat + " hud tablet"
// Convert networks to lowercase
for(var/i in network)
@@ -252,10 +261,15 @@
/obj/item/hud_tablet/pilot
name = "pilot officers's hud tablet"
- network = list("dropship1", "dropship2")
+ network = list("dropship1")
req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_DROPSHIP)
max_view_dist = WORLD_VIEW_NUM
+/obj/item/hud_tablet/transportofficer
+ name = "transport officer's hud tablet"
+ network = list("dropship2")
+ req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE)
+ max_view_dist = WORLD_VIEW_NUM
/obj/item/hud_tablet/artillery
name = "artillery impact hud tablet"
diff --git a/code/game/objects/items/devices/tweezers.dm b/code/game/objects/items/devices/tweezers.dm
index d004f056f8a56..f4e4349e5cbed 100644
--- a/code/game/objects/items/devices/tweezers.dm
+++ b/code/game/objects/items/devices/tweezers.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/items/surgery_tools.dmi'
icon_state = "tweezers"
item_state = "tweezers"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
/* RUTGMC REMOVAL
@@ -19,7 +19,7 @@
icon = 'icons/obj/items/surgery_tools.dmi'
icon_state = "predator_bone-gel"
item_state = "predator_bone-gel"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
/obj/item/tweezers_advanced/Initialize(mapload)
diff --git a/code/game/objects/items/embedding.dm b/code/game/objects/items/embedding.dm
index 7d5d84cd68ce5..4eb47cd666cdf 100644
--- a/code/game/objects/items/embedding.dm
+++ b/code/game/objects/items/embedding.dm
@@ -79,7 +79,7 @@
stack_trace("limb_embed called for QDELETED [embedding]")
embedding?.unembed_ourself()
return FALSE
- if(HAS_TRAIT(embedding, TRAIT_NODROP) || (embedding.flags_item & DELONDROP))
+ if(HAS_TRAIT(embedding, TRAIT_NODROP) || (embedding.item_flags & DELONDROP))
stack_trace("limb_embed called for TRAIT_NODROP or DELONDROP [embedding]")
embedding.unembed_ourself()
return FALSE
diff --git a/code/game/objects/items/explosives/bombvest.dm b/code/game/objects/items/explosives/bombvest.dm
index 0afe25235fc1c..a69f9ff911813 100644
--- a/code/game/objects/items/explosives/bombvest.dm
+++ b/code/game/objects/items/explosives/bombvest.dm
@@ -4,8 +4,8 @@
icon_state = "boom_vest"
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
slowdown = 0
- flags_item_map_variant = NONE
- flags_armor_features = NONE
+ item_map_variant_flags = NONE
+ armor_features_flags = NONE
///Warcry to yell upon detonation
var/bomb_message
///List of warcries that are not allowed.
diff --git a/code/game/objects/items/explosives/grenades/bullet_grenade.dm b/code/game/objects/items/explosives/grenades/bullet_grenade.dm
new file mode 100644
index 0000000000000..58cd11676fb71
--- /dev/null
+++ b/code/game/objects/items/explosives/grenades/bullet_grenade.dm
@@ -0,0 +1,69 @@
+///bullet grenade: shoots bullets out from itself in a ring
+/obj/item/explosive/grenade/bullet
+ name = "\improper M90 leadburster grenade"
+ desc = "Leadburster grenades release a short burst of projectiles after detonation. Keep far away from friendlies. Or don't. I'm just a label."
+ icon_state = "grenade_rad"
+ item_state = "grenade_rad"
+ icon_state_mini = "grenade_red"
+ det_time = 40
+ arm_sound = 'sound/weapons/armbomb.ogg'
+ hud_state = "grenade_he"
+
+ /// amount of rotations that we will do with these bullets
+ var/rotations = 2
+ ///whether we randomly emit or in equal intervals
+ var/randomized = FALSE
+ ///sound to play while shooting
+ var/fire_sound = 'sound/weapons/burst_phaser2.ogg'
+ /// total amount of bullets to fire, split evenly between rotations
+ var/projectile_count = 30
+ /// range of the bullets
+ var/range = 7
+ /// speed of the bullets
+ var/speed = 2
+ /// ammo type to shoot out: can be ANY ammo type
+ var/datum/ammo/ammo_type = /datum/ammo/energy/lasgun/marine/heavy_laser
+
+/obj/item/explosive/grenade/bullet/prime()
+ var/list/bullets = list()
+ var/proj_type = /obj/projectile
+ if(initial(ammo_type.ammo_behavior_flags) & AMMO_HITSCAN)
+ proj_type = /obj/projectile/hitscan
+ for(var/i=1 to projectile_count)
+ var/obj/projectile/proj = new proj_type(src, initial(ammo_type.hitscan_effect_icon))
+ proj.generate_bullet(ammo_type)
+ bullets += proj
+
+ bullet_burst(src, bullets, null, fire_sound, range, speed, randomized, rotations)
+ qdel(src)
+
+
+/obj/item/explosive/grenade/bullet/laser
+ name = "\improper M80 lasburster grenade"
+ desc = "Lasburster grenades are supercharged to scatter a beam around them when detonating. Keep far away from friendlies. Or don't. I'm just a label."
+ icon_state = "grenade_lasburster"
+ item_state = "grenade_lasburster"
+ icon_state_mini = "grenade_lasburster"
+ det_time = 40
+ hud_state = "grenade_lasburster"
+
+ rotations = -1
+ fire_sound = 'sound/weapons/burst_phaser2.ogg'
+ projectile_count = 20
+ ammo_type = /datum/ammo/energy/lasburster
+
+/obj/item/explosive/grenade/bullet/hefa
+ name = "\improper M25 HEFA grenade"
+ desc = "High explosive fragmentation grenades cause a powerful yet very small explosion combined with a scattering ring of buckshot shrapnel, please throw very, very, VERY far away."
+ icon_state = "grenade_hefa2"
+ item_state = "grenade_hefa2"
+ icon_state_mini = "grenade_hefa"
+ hud_state = "grenade_hefa2"
+ rotations = -1
+ fire_sound = null
+ projectile_count = 50
+ ammo_type = /datum/ammo/bullet/hefa_buckshot
+
+/obj/item/explosive/grenade/bullet/hefa/prime()
+ explosion(loc, light_impact_range = 2, heavy_impact_range = 1)
+ return ..()
diff --git a/code/game/objects/items/explosives/grenades/chem_grenade.dm b/code/game/objects/items/explosives/grenades/chem_grenade.dm
index 45e48dfd03a88..4b01313956619 100644
--- a/code/game/objects/items/explosives/grenades/chem_grenade.dm
+++ b/code/game/objects/items/explosives/grenades/chem_grenade.dm
@@ -40,7 +40,7 @@
else
return ..()
-/obj/item/explosive/grenade/chem_grenade/razorburn_smol/attackby(obj/item/I, mob/user, params)
+/obj/item/explosive/grenade/chem_grenade/razorburn_small/attackby(obj/item/I, mob/user, params)
to_chat(user, span_notice("The [initial(name)] is hermetically sealed, and does not open."))
return
@@ -237,7 +237,7 @@
icon_state = initial(icon_state) +"_locked"
-/obj/item/explosive/grenade/chem_grenade/razorburn_smol
+/obj/item/explosive/grenade/chem_grenade/razorburn_small
name = "Razorburn Grenade"
desc = "Contains construction nanites ready to turn a small area into razorwire after a few seconds. DO NOT ENTER AREA WHILE ACTIVE."
icon_state = "grenade_razorburn"
@@ -247,7 +247,7 @@
icon_state_mini = "grenade_chem_yellow"
-/obj/item/explosive/grenade/chem_grenade/razorburn_smol/Initialize(mapload, ...)
+/obj/item/explosive/grenade/chem_grenade/razorburn_small/Initialize(mapload, ...)
. = ..()
var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm
index 1e4f136a485e3..71ef9d7067783 100644
--- a/code/game/objects/items/explosives/grenades/grenade.dm
+++ b/code/game/objects/items/explosives/grenades/grenade.dm
@@ -11,8 +11,8 @@
item_state = "grenade"
throw_speed = 3
throw_range = 7
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
hitsound = 'sound/weapons/smash.ogg'
icon_state_mini = "grenade_red"
///if launched from a UGL/grenade launcher
@@ -61,9 +61,10 @@
/obj/item/explosive/grenade/afterattack(atom/target, mob/user, has_proximity, click_parameters)
. = ..()
- if(!active)
+ if(!active || user.next_move > world.time)
return
- user.throw_item(target)
+ if(user.throw_item(target))
+ user.changeNext_move(CLICK_CD_THROWING)
/obj/item/explosive/grenade/proc/activate(mob/user)
if(active)
@@ -72,7 +73,8 @@
if(user)
log_bomber(user, "primed", src)
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
- personal_statistics.grenades_primed++
+ personal_statistics.grenades_primed ++
+ personal_statistics.mission_grenades_primed ++
icon_state = initial(icon_state) + "_active"
active = TRUE
@@ -125,7 +127,7 @@
///The range range for the grenade's weak effect
var/outer_range = 7
///The potency of the grenade
- var/rad_strength = 20
+ var/rad_strength = 16
/obj/item/explosive/grenade/rad/prime()
var/turf/impact_turf = get_turf(src)
diff --git a/code/game/objects/items/explosives/grenades/marines.dm b/code/game/objects/items/explosives/grenades/marines.dm
index 93d1350e079a2..6f617f5d1dab5 100644
--- a/code/game/objects/items/explosives/grenades/marines.dm
+++ b/code/game/objects/items/explosives/grenades/marines.dm
@@ -220,18 +220,14 @@
qdel(src)
-/proc/flame_radius(radius = 1, turf/epicenter, burn_intensity = 25, burn_duration = 25, burn_damage = 25, fire_stacks = 15, int_var = 0.5, dur_var = 0.5, colour = "red") //~Art updated fire.
+/proc/flame_radius(radius = 1, turf/epicenter, burn_intensity = 25, burn_duration = 25, burn_damage = 25, fire_stacks = 15, colour = "red") //~Art updated fire.
if(!isturf(epicenter))
CRASH("flame_radius used without a valid turf parameter")
radius = clamp(radius, 1, 50) //Sanitize inputs
- int_var = clamp(int_var, 0.1,0.5)
- dur_var = clamp(int_var, 0.1,0.5)
- fire_stacks = randfloat(burn_damage*(0.5-int_var),burn_damage*(0.5+int_var) ) + randfloat(burn_damage*(0.5-int_var),burn_damage*(0.5+int_var) )
- burn_damage = randfloat(burn_damage*(0.5-int_var),burn_damage*(0.5+int_var) ) + randfloat(burn_damage*(0.5-int_var),burn_damage*(0.5+int_var) )
for(var/t in filled_turfs(epicenter, radius, "circle", air_pass = TRUE))
var/turf/turf_to_flame = t
- turf_to_flame.ignite(randfloat(burn_intensity*(0.5-int_var), burn_intensity*(0.5+int_var)) + randfloat(burn_intensity*(0.5-int_var), burn_intensity*(0.5+int_var)), randfloat(burn_duration*(0.5-int_var), burn_duration*(0.5-int_var)) + randfloat(burn_duration*(0.5-int_var), burn_duration*(0.5-int_var)), colour, burn_damage, fire_stacks)
+ turf_to_flame.ignite(randfloat(burn_duration*0.75, burn_duration), burn_intensity, colour, burn_damage, fire_stacks)
/obj/item/explosive/grenade/incendiary/som
name = "\improper S30-I incendiary grenade"
@@ -287,7 +283,7 @@
/// smoke type created when the grenade is primed
var/datum/effect_system/smoke_spread/smoketype = /datum/effect_system/smoke_spread/bad
///radius this smoke grenade will encompass
- var/smokeradius = 7
+ var/smokeradius = 6
///The duration of the smoke
var/smoke_duration = 11
@@ -316,7 +312,6 @@
det_time = 4 SECONDS
dangerous = TRUE
smoketype = /datum/effect_system/smoke_spread/xeno/neuro/medium
- smokeradius = 6
/obj/item/explosive/grenade/smokebomb/acid
name = "\improper M40-A Acid smoke grenade"
@@ -326,7 +321,7 @@
hud_state = "grenade_acid"
det_time = 4 SECONDS
dangerous = TRUE
- smoketype = /datum/effect_system/smoke_spread/xeno/acid
+ smoketype = /datum/effect_system/smoke_spread/xeno/acid/opaque
smokeradius = 5
/obj/item/explosive/grenade/smokebomb/satrapine
@@ -338,7 +333,6 @@
det_time = 4 SECONDS
dangerous = TRUE
smoketype = /datum/effect_system/smoke_spread/satrapine
- smokeradius = 6
/obj/item/explosive/grenade/smokebomb/satrapine/activate(mob/user)
. = ..()
@@ -354,6 +348,7 @@
hud_state = "grenade_hide"
icon_state_mini = "grenade_green"
smoketype = /datum/effect_system/smoke_spread/tactical
+ smokeradius = 7
/obj/item/explosive/grenade/smokebomb/cloak/ags
name = "\improper AGLS-37 SCDP smoke grenade"
@@ -371,6 +366,19 @@
icon_state_mini = "grenade_blue"
dangerous = TRUE
smoketype = /datum/effect_system/smoke_spread/plasmaloss
+ smokeradius = 7
+
+/obj/item/explosive/grenade/smokebomb/antigas
+ name = "\improper M40-AG smoke grenade"
+ desc = "A gas grenade originally designed to remove any contaminants in the air for the purpose of cleaning, now repurposed to remove hostile gases."
+ icon_state = "grenade_agas"
+ item_state = "grenade_agas"
+ hud_state = "grenade_antigas"
+ det_time = 3 SECONDS
+ icon_state_mini = "grenade_antigas"
+ dangerous = TRUE
+ smoketype = /datum/effect_system/smoke_spread/antigas
+ smokeradius = 7
/obj/item/explosive/grenade/smokebomb/drain/agls
name = "\improper AGLS-T smoke grenade"
@@ -402,7 +410,7 @@
smoke.set_up(6, loc, 7)
smoke.start()
flame_radius(4, get_turf(src))
- flame_radius(1, get_turf(src), burn_intensity = 45, burn_duration = 75, burn_damage = 15, fire_stacks = 75) //The closer to the middle you are the more it hurts
+ flame_radius(1, get_turf(src), burn_intensity = 75, burn_duration = 45, burn_damage = 15, fire_stacks = 75) //The closer to the middle you are the more it hurts
qdel(src)
/obj/item/explosive/grenade/phosphorus/activate(mob/user)
@@ -439,7 +447,7 @@
qdel(src)
*/
-
+#define FLARE_FIRE_STACKS 5
/obj/item/explosive/grenade/flare
name = "\improper M40 FLDP grenade"
desc = "A TGMC standard issue flare utilizing the standard DP canister chassis. Capable of being loaded in any grenade launcher, or thrown by hand."
@@ -482,39 +490,36 @@
if(!fuel || !active)
turn_off()
-/obj/item/explosive/grenade/flare/proc/turn_off()
- active = FALSE
- fuel = 0
- heat = 0
- item_fire_stacks = 0
- force = initial(force)
- damtype = initial(damtype)
- update_brightness()
- icon_state = "[initial(icon_state)]_empty" // override icon state set by update_brightness
- STOP_PROCESSING(SSobj, src)
+/obj/item/explosive/grenade/flare/throw_impact(atom/hit_atom, speed)
+ if(isopenturf(hit_atom))
+ var/obj/alien/weeds/node/N = locate() in loc
+ if(N)
+ qdel(N)
+ turn_off()
+ . = ..()
+ if(!.)
+ return
+ if(!active)
+ return
-/obj/item/explosive/grenade/flare/proc/turn_on()
- active = TRUE
- force = 5
- throwforce = 10
- ENABLE_BITFIELD(resistance_flags, ON_FIRE)
- item_fire_stacks = 5
- heat = 1500
- damtype = BURN
- update_brightness()
- playsound(src,'sound/items/flare.ogg', 15, 1)
- START_PROCESSING(SSobj, src)
+ if(isliving(hit_atom))
+ var/mob/living/living_target = hit_atom
+ living_target.fire_stacks += FLARE_FIRE_STACKS
+ living_target.IgniteMob()
-/obj/item/explosive/grenade/flare/attack_self(mob/user)
+ var/target_zone = check_zone(living_target.zone_selected)
+ if(!target_zone || rand(40))
+ target_zone = "chest"
+ if(launched && CHECK_BITFIELD(resistance_flags, ON_FIRE) && !living_target.on_fire)
+ living_target.apply_damage(randfloat(throwforce * 0.75, throwforce * 1.25), BURN, target_zone, FIRE, updating_health = TRUE) //Do more damage if launched from a proper launcher and active
- // Usual checks
+/obj/item/explosive/grenade/flare/attack_self(mob/user)
if(!fuel)
to_chat(user, span_notice("It's out of fuel."))
return
if(active)
return
- // All good, turn it on.
user.visible_message(span_notice("[user] activates the flare."), span_notice("You depress the ignition button, activating it!"))
turn_on(user)
@@ -522,48 +527,46 @@
if(!active)
turn_on(user)
-/obj/item/explosive/grenade/flare/on/Initialize(mapload)
- . = ..()
- active = TRUE
- heat = 1500
- update_brightness()
- force = 5
- throwforce = 10
- ENABLE_BITFIELD(resistance_flags, ON_FIRE)
- item_fire_stacks = 5
- damtype = BURN
- START_PROCESSING(SSobj, src)
-
-/obj/item/explosive/grenade/flare/proc/update_brightness()
+/obj/item/explosive/grenade/flare/update_icon_state()
if(active && fuel > 0)
icon_state = "[initial(icon_state)]_active"
item_state = "[initial(item_state)]_active"
- set_light_on(TRUE)
+ else if(!fuel)
+ icon_state = "[initial(icon_state)]_empty"
+ item_state = "[initial(item_state)]_empty"
else
icon_state = initial(icon_state)
item_state = initial(item_state)
- set_light_on(FALSE)
-/obj/item/explosive/grenade/flare/throw_impact(atom/hit_atom, speed)
- if(isopenturf(hit_atom))
- var/obj/alien/weeds/node/N = locate() in loc
- if(N)
- qdel(N)
- turn_off()
- . = ..()
- if(!.)
- return
- if(!active)
- return
- if(isliving(hit_atom))
- var/mob/living/L = hit_atom
+///Shuts the flare off
+/obj/item/explosive/grenade/flare/proc/turn_off()
+ active = FALSE
+ fuel = 0
+ heat = 0
+ force = initial(force)
+ damtype = initial(damtype)
+ update_icon()
+ set_light_on(FALSE)
+ STOP_PROCESSING(SSobj, src)
- var/target_zone = check_zone(L.zone_selected)
- if(!target_zone || rand(40))
- target_zone = "chest"
- if(launched && CHECK_BITFIELD(resistance_flags, ON_FIRE) && !L.on_fire)
- L.apply_damage(randfloat(throwforce * 0.75, throwforce * 1.25), BURN, target_zone, FIRE, updating_health = TRUE) //Do more damage if launched from a proper launcher and active
+///Activates the flare
+/obj/item/explosive/grenade/flare/proc/turn_on()
+ active = TRUE
+ force = 5
+ throwforce = 10
+ ENABLE_BITFIELD(resistance_flags, ON_FIRE)
+ heat = 1500
+ damtype = BURN
+ update_icon()
+ set_light_on(TRUE)
+ playsound(src,'sound/items/flare.ogg', 15, 1)
+ START_PROCESSING(SSobj, src)
+
+//Starts on
+/obj/item/explosive/grenade/flare/on/Initialize(mapload)
+ . = ..()
+ turn_on()
/obj/item/explosive/grenade/flare/civilian
name = "flare"
@@ -612,8 +615,7 @@
upper_fuel_limit = 20
light_system = STATIC_LIGHT//movable light has a max range
light_color = LIGHT_COLOR_CYAN
- ///The brightness of the flare
- var/brightness = 12
+ light_range = 12
/obj/item/explosive/grenade/flare/strongerflare/throw_impact(atom/hit_atom, speed)
. = ..()
@@ -621,11 +623,6 @@
return
anchored = TRUE//prevents marines from picking up and running around with a stronger flare
-/obj/item/explosive/grenade/flare/strongerflare/update_brightness()
+/obj/item/explosive/grenade/flare/strongerflare/turn_off()
. = ..()
- if(active && fuel > 0)
- icon_state = "[initial(icon_state)]_active"
- set_light(brightness)
- else
- icon_state = initial(icon_state)
- set_light(0)
+ set_light(0)
diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm
index ee99ea48c8658..1d418eb3b8d72 100644
--- a/code/game/objects/items/explosives/mine.dm
+++ b/code/game/objects/items/explosives/mine.dm
@@ -18,7 +18,7 @@ Stepping directly on the mine will also blow it up
throwforce = 5
throw_range = 6
throw_speed = 3
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
///Trigger flags for this mine
var/target_mode = MINE_LIVING_ONLY
/// IFF signal - used to determine friendly units
@@ -42,11 +42,12 @@ Stepping directly on the mine will also blow it up
return ..()
/// Update the icon, adding "_armed" if appropriate to the icon_state.
-/obj/item/explosive/mine/update_icon()
+/obj/item/explosive/mine/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][armed ? "_armed" : ""]"
/// On explosion mines trigger their own explosion, assuming there were not deleted straight away (larger explosions or probability)
-/obj/item/explosive/mine/ex_act()
+/obj/item/explosive/mine/ex_act(severity)
. = ..()
if(!QDELETED(src))
INVOKE_ASYNC(src, PROC_REF(trigger_explosion))
@@ -101,6 +102,8 @@ Stepping directly on the mine will also blow it up
/// Supports diarming a mine
/obj/item/explosive/mine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!ismultitool(I) || !anchored)
return
@@ -162,15 +165,15 @@ Stepping directly on the mine will also blow it up
return TRUE
/// Alien attacks trigger the explosive to instantly detonate
-/obj/item/explosive/mine/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/item/explosive/mine/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(triggered) //Mine is already set to go off
return
- if(X.a_intent == INTENT_HELP)
+ if(xeno_attacker.a_intent == INTENT_HELP)
return
- X.visible_message(span_danger("[X] has slashed [src]!"), \
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] has slashed [src]!"), \
span_danger("We slash [src]!"))
playsound(loc, 'sound/weapons/slice.ogg', 25, 1)
INVOKE_ASYNC(src, PROC_REF(trigger_explosion))
@@ -238,6 +241,10 @@ Stepping directly on the mine will also blow it up
icon_state = "m92"
target_mode = MINE_VEHICLE_ONLY
+/obj/item/explosive/mine/anti_tank/update_icon(updates=ALL)
+ . = ..()
+ alpha = armed ? 50 : 255
+
/obj/item/explosive/mine/anti_tank/trigger_explosion()
if(triggered)
return
@@ -246,5 +253,27 @@ Stepping directly on the mine will also blow it up
QDEL_NULL(tripwire)
qdel(src)
-/obj/item/explosive/mine/anti_tank/ex_act()
- qdel(src)
+/obj/item/explosive/mine/anti_tank/ex_act(severity)
+ switch(severity)
+ if(EXPLODE_DEVASTATE)
+ take_damage(INFINITY, BRUTE, BOMB, 0)
+ return
+ if(EXPLODE_HEAVY)
+ take_damage(rand(100, 250), BRUTE, BOMB, 0)
+ if(prob(25))
+ return
+ if(EXPLODE_LIGHT)
+ take_damage(rand(10, 90), BRUTE, BOMB, 0)
+ if(prob(50))
+ return
+ if(EXPLODE_WEAK)
+ take_damage(rand(5, 45), BRUTE, BOMB, 0)
+ return //not strong enough to detonate
+ if(QDELETED(src))
+ return
+ if(!armed)
+ return
+ INVOKE_ASYNC(src, PROC_REF(trigger_explosion))
+
+/obj/item/explosive/mine/anti_tank/flamer_fire_act(burnlevel)
+ return //its highly exploitable if fire detonates these
diff --git a/code/game/objects/items/explosives/plastique.dm b/code/game/objects/items/explosives/plastique.dm
index 77fd64792ba4b..e658f8e33ab86 100644
--- a/code/game/objects/items/explosives/plastique.dm
+++ b/code/game/objects/items/explosives/plastique.dm
@@ -5,7 +5,7 @@
icon = 'icons/obj/det.dmi'
icon_state = "plastic-explosive"
item_state = "plasticx"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY
/// whether the plastic explosive is armed or not
var/armed = FALSE
@@ -21,12 +21,16 @@
var/datum/effect_system/smoke_spread/smoketype = /datum/effect_system/smoke_spread/bad
/// radius this smoke will encompass
var/smokeradius = 1
+ ///Current/last user of the c4
+ var/mob/living/last_user
/obj/item/explosive/plastique/Destroy()
plant_target = null
+ last_user = null
return ..()
/obj/item/explosive/plastique/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][plant_target ? "_set" : ""]"
if(armed)
icon_state = "[icon_state][alarm_sounded ? "_armed" : "_on"]"
@@ -93,6 +97,7 @@
forceMove(location)
armed = TRUE
timer = target.plastique_time_mod(timer)
+ last_user = user
log_bomber(user, "planted", src, "on [target] with a [timer] second fuse", message_admins = TRUE)
@@ -111,12 +116,6 @@
/obj/item/explosive/plastique/attack_hand(mob/living/user)
if(armed)
- to_chat(user, "Disarm [src] first to remove it!")
- return
- return ..()
-
-/obj/item/explosive/plastique/attackby(obj/item/I, mob/user, params)
- if(ismultitool(I) && armed)
if(!do_after(user, 2 SECONDS, NONE, plant_target, BUSY_ICON_HOSTILE))
return
@@ -141,7 +140,9 @@
armed = FALSE
alarm_sounded = FALSE
plant_target = null
+ last_user = null
update_icon()
+ return ..()
///Handles the actual explosion effects
/obj/item/explosive/plastique/proc/detonate()
@@ -155,7 +156,7 @@
var/datum/effect_system/smoke_spread/smoke = new smoketype()
smoke.set_up(smokeradius, plant_target, 2)
smoke.start()
- plant_target.plastique_act()
+ plant_target.plastique_act(last_user)
qdel(src)
///Triggers a warning beep prior to the actual detonation, while also setting the actual detonation timer
@@ -167,7 +168,7 @@
update_icon()
///Handles the effect of c4 on the atom - overridden as needed
-/atom/proc/plastique_act()
+/atom/proc/plastique_act(mob/living/plastique_user)
ex_act(EXPLODE_DEVASTATE)
/obj/item/explosive/plastique/genghis_charge
@@ -189,7 +190,7 @@
flame_target.ignite(10, 5)
qdel(src)
return
- new /obj/flamer_fire/autospread(flame_target, 17, 31)
+ new /obj/flamer_fire/autospread(flame_target, 9, 62)
playsound(plant_target, sound(get_sfx("explosion_small")), 100, FALSE, 25)
qdel(src)
@@ -225,7 +226,7 @@
spread_directions |= old_spreader.possible_directions
if(old_flame)
qdel(old_flame)
- new /obj/flamer_fire/autospread(turf_to_burn, 17, 31, flame_color, 0, 0, spread_directions)
+ new /obj/flamer_fire/autospread(turf_to_burn, 9, 62, flame_color, 0, 0, spread_directions)
///Allows the c4 timer to be tweaked on certain atoms as required
/atom/proc/plastique_time_mod(time)
diff --git a/code/game/objects/items/firesupport_binoculars.dm b/code/game/objects/items/firesupport_binoculars.dm
index d4402f608d33d..bb848ea686393 100644
--- a/code/game/objects/items/firesupport_binoculars.dm
+++ b/code/game/objects/items/firesupport_binoculars.dm
@@ -7,10 +7,11 @@
///Faction locks this item if specified
var/faction = null
///lase effect
- var/obj/effect/overlay/temp/laser_target/laser
+ var/image/laser_overlay
+ ///lasing time
var/target_acquisition_delay = 5 SECONDS
///Last stored turf targetted by rangefinders
- var/turf/targetturf
+ var/turf/target_atom
///Current mode for support request
var/datum/fire_support/mode = null
///firemodes available for these binos
@@ -41,11 +42,9 @@
. += span_warning("Available in [round(timeleft(mode.cooldown_timer) MILLISECONDS)] seconds.")
/obj/item/binoculars/fire_support/Destroy()
- if(laser)
- QDEL_NULL(laser)
+ unset_target()
mode = null
mode_list = null
- targetturf = null
return ..()
@@ -70,7 +69,7 @@
/obj/item/binoculars/fire_support/onunzoom(mob/living/user)
. = ..()
- QDEL_NULL(laser)
+ unset_target()
if(!user?.client)
return
@@ -115,77 +114,88 @@
update_icon()
///lases a target and calls fire support on it
-/obj/item/binoculars/fire_support/proc/acquire_target(atom/A, mob/living/carbon/human/user)
+/obj/item/binoculars/fire_support/proc/acquire_target(atom/target, mob/living/carbon/human/user)
set waitfor = 0
+ if(user.do_actions)
+ balloon_alert_to_viewers("Busy")
+ return
if(is_mainship_level(user.z))
user.balloon_alert(user, "Can't use here")
return
if(faction && user.faction != faction)
balloon_alert_to_viewers("Security locks engaged")
return
- if(laser)
+ if(laser_overlay)
to_chat(user, span_warning("You're already targeting something."))
return
- if(!mode)
- balloon_alert_to_viewers("Select a mode!")
- return
- if(!(mode.fire_support_flags & FIRESUPPORT_AVAILABLE))
- balloon_alert_to_viewers("[mode.name] unavailable")
- return
- if(!mode.uses)
- balloon_alert_to_viewers("[mode.name] expended")
- return
- if(mode.cooldown_timer)
- balloon_alert_to_viewers("On cooldown")
- return
-
- var/turf/TU = get_turf(A)
- var/distance = get_dist(TU, get_turf(user))
- var/zoom_screen_size = zoom_tile_offset + zoom_viewsize + 1
- if(TU.z != user.z || distance == -1 || (distance > zoom_screen_size))
- to_chat(user, span_warning("You can't focus properly through \the [src] while looking through something else."))
+ if(!bino_checks(target, user))
return
-
- if(!user.mind)
+ if(!can_see_target(target, user))
+ balloon_alert_to_viewers("No clear view")
return
- var/area/targ_area = get_area(A)
- if(isspacearea(targ_area))
- to_chat(user, span_warning("Cannot fire into space."))
- return
- if(targ_area.ceiling >= CEILING_UNDERGROUND)
- to_chat(user, span_warning("DEPTH WARNING: Target too deep for ordnance."))
- return
- if(user.do_actions)
- return
playsound(src, 'sound/effects/nightvision.ogg', 35)
to_chat(user, span_notice("INITIATING LASER TARGETING. Stand still."))
- var/obj/effect/overlay/temp/laser_target/cas/CS = new (TU)
- laser = CS
- if(!do_after(user, target_acquisition_delay, NONE, user, BUSY_ICON_HOSTILE))
+ target_atom = target
+ laser_overlay = image('icons/obj/items/projectiles.dmi', icon_state = "sniper_laser", layer =-LASER_LAYER)
+ target_atom.apply_fire_support_laser(laser_overlay)
+ if(!do_after(user, target_acquisition_delay, NONE, user, BUSY_ICON_HOSTILE, extra_checks = CALLBACK(src, PROC_REF(can_see_target), target, user)))
+ to_chat(user, span_danger("You lose sight of your target!"))
+ playsound(user,'sound/machines/click.ogg', 25, 1)
+ unset_target()
+ return
+ if(!bino_checks(target, user))
return
+
+ playsound(src, 'sound/effects/binoctarget.ogg', 35)
+ mode.initiate_fire_support(get_turf(target_atom), user)
+ unset_target()
+
+///Internal bino checks, mainly around firemode
+/obj/item/binoculars/fire_support/proc/bino_checks(atom/target, mob/living/user)
if(!mode)
balloon_alert_to_viewers("Select a mode!")
- return
+ return FALSE
if(!(mode.fire_support_flags & FIRESUPPORT_AVAILABLE))
balloon_alert_to_viewers("[mode.name] unavailable")
- return
+ return FALSE
if(!mode.uses)
balloon_alert_to_viewers("[mode.name] expended")
- return
+ return FALSE
if(mode.cooldown_timer)
balloon_alert_to_viewers("On cooldown")
- return
+ return FALSE
+ var/area/targ_area = get_area(target)
+ if(isspacearea(targ_area))
+ to_chat(user, span_warning("Cannot fire into space."))
+ return FALSE
+ if(targ_area.ceiling >= CEILING_UNDERGROUND)
+ to_chat(user, span_warning("DEPTH WARNING: Target too deep for ordnance."))
+ return FALSE
+ return TRUE
- playsound(src, 'sound/effects/binoctarget.ogg', 35)
- QDEL_NULL(laser)
- mode.initiate_fire_support(TU, user)
+///Checks if we can draw LOS to the target
+/obj/item/binoculars/fire_support/proc/can_see_target(atom/target, mob/living/user)
+ if(QDELETED(target))
+ return FALSE
+ if(target.z != user.z)
+ return FALSE
+ if(!(user in viewers(zoom_tile_offset + zoom_viewsize + 1, target)))
+ return FALSE
+ return TRUE
+
+///Unsets the target and cleans up
+/obj/item/binoculars/fire_support/proc/unset_target()
+ if(target_atom)
+ target_atom.remove_fire_support_laser(laser_overlay)
+ target_atom = null
+ if(laser_overlay)
+ QDEL_NULL(laser_overlay)
///Acquires coords of a target turf
/obj/item/binoculars/fire_support/proc/acquire_coordinates(atom/A, mob/living/carbon/human/user)
- var/turf/TU = get_turf(A)
- targetturf = TU
- to_chat(user, span_notice("COORDINATES: LONGITUDE [targetturf.x]. LATITUDE [targetturf.y]."))
+ var/turf/target_turf = get_turf(A)
+ to_chat(user, span_notice("COORDINATES: LONGITUDE [target_turf.x]. LATITUDE [target_turf.y]."))
playsound(src, 'sound/effects/binoctarget.ogg', 35)
@@ -215,3 +225,18 @@
FIRESUPPORT_TYPE_SATRAPINE_SMOKE_MORTAR,
FIRESUPPORT_TYPE_SMOKE_MORTAR_SOM,
)
+
+///Sets a laser overlay for fire support binos
+/atom/proc/apply_fire_support_laser(image/laser_overlay)
+ add_overlay(laser_overlay)
+
+/mob/living/carbon/apply_fire_support_laser(image/laser_overlay)
+ overlays_standing[LASER_LAYER] = laser_overlay
+ apply_overlay(LASER_LAYER)
+
+///Removes a laser overlay for fire support binos
+/atom/proc/remove_fire_support_laser(image/laser_overlay)
+ cut_overlay(laser_overlay)
+
+/mob/living/carbon/remove_fire_support_laser(image/laser_overlay)
+ remove_overlay(LASER_LAYER)
diff --git a/code/game/objects/items/flash.dm b/code/game/objects/items/flash.dm
index 85e52d03ec01f..be05ebdbc666d 100644
--- a/code/game/objects/items/flash.dm
+++ b/code/game/objects/items/flash.dm
@@ -8,7 +8,7 @@
w_class = WEIGHT_CLASS_SMALL
throw_speed = 4
throw_range = 10
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
var/times_used = 0 //Number of times it's been used.
var/broken = 0 //Is the flash burnt out?
diff --git a/code/game/objects/items/flashlight.dm b/code/game/objects/items/flashlight.dm
index b5d8d37b88aae..5a61ee9b61164 100644
--- a/code/game/objects/items/flashlight.dm
+++ b/code/game/objects/items/flashlight.dm
@@ -9,8 +9,8 @@
)
item_state = "flashlight"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
actions_types = list(/datum/action/item_action)
light_range = 5
light_power = 3 //luminosity when on
@@ -40,12 +40,12 @@
update_action_button_icons()
update_icon()
-/obj/item/flashlight/attack_alien(mob/living/carbon/xenomorph/X, isrightclick = FALSE)
- if(turn_light(X, FALSE) != CHECKS_PASSED)
+/obj/item/flashlight/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(turn_light(xeno_attacker, FALSE) != CHECKS_PASSED)
return
playsound(loc, "alien_claw_metal", 25, 1)
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- to_chat(X, span_warning("We disable the metal thing's lights.") )
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ to_chat(xeno_attacker, span_warning("We disable the metal thing's lights.") )
/obj/item/flashlight/update_icon_state()
. = ..()
@@ -65,6 +65,8 @@
/obj/item/flashlight/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/screwdriver))
if(!raillight_compatible) //No fancy messages, just no
@@ -92,8 +94,8 @@
var/mob/living/carbon/human/H = M //mob has protective eyewear
- if(ishuman(M) && ((H.head && H.head.flags_inventory & COVEREYES) || (H.wear_mask && H.wear_mask.flags_inventory & COVEREYES) || (H.glasses && H.glasses.flags_inventory & COVEREYES)))
- to_chat(user, span_notice("You're going to need to remove that [(H.head && H.head.flags_inventory & COVEREYES) ? "helmet" : (H.wear_mask && H.wear_mask.flags_inventory & COVEREYES) ? "mask": "glasses"] first."))
+ if(ishuman(M) && ((H.head && H.head.inventory_flags & COVEREYES) || (H.wear_mask && H.wear_mask.inventory_flags & COVEREYES) || (H.glasses && H.glasses.inventory_flags & COVEREYES)))
+ to_chat(user, span_notice("You're going to need to remove that [(H.head && H.head.inventory_flags & COVEREYES) ? "helmet" : (H.wear_mask && H.wear_mask.inventory_flags & COVEREYES) ? "mask": "glasses"] first."))
return
if(M == user) //they're using it on themselves
@@ -121,7 +123,7 @@
desc = "A pen-sized light, used by medical staff."
icon_state = "penlight"
item_state = ""
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
light_range = 2
w_class = WEIGHT_CLASS_TINY
raillight_compatible = FALSE
@@ -174,12 +176,12 @@
if(!usr.stat)
attack_self(usr)
-/obj/item/flashlight/lamp/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/item/flashlight/lamp/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- X.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
playsound(loc, 'sound/effects/metalhit.ogg', 20, TRUE)
- X.visible_message(span_danger("\The [X] smashes [src]!"), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] smashes [src]!"), \
span_danger("We smash [src]!"), null, 5)
deconstruct(FALSE)
diff --git a/code/game/objects/items/frames/alarms.dm b/code/game/objects/items/frames/alarms.dm
index 0c85a54efd62f..66c946de8456a 100644
--- a/code/game/objects/items/frames/alarms.dm
+++ b/code/game/objects/items/frames/alarms.dm
@@ -8,10 +8,12 @@ Code shamelessly copied from apc_frame
desc = "Used for building Fire Alarms"
icon = 'icons/obj/objects.dmi'
icon_state = "fire_bitem"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/obj/item/frame/fire_alarm/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
new /obj/item/stack/sheet/metal(loc, 2)
diff --git a/code/game/objects/items/frames/frame.dm b/code/game/objects/items/frames/frame.dm
index 0e312d9db56b3..50cfb05502a1e 100644
--- a/code/game/objects/items/frames/frame.dm
+++ b/code/game/objects/items/frames/frame.dm
@@ -14,10 +14,12 @@
desc = "Used for repairing or building APCs"
icon = 'icons/obj/objects.dmi'
icon_state = "apc_frame"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/obj/item/frame/apc/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
new /obj/item/stack/sheet/metal(loc, 2)
diff --git a/code/game/objects/items/frames/light_fixtures.dm b/code/game/objects/items/frames/light_fixtures.dm
index 907b862237656..5cecbe4ef2ffe 100644
--- a/code/game/objects/items/frames/light_fixtures.dm
+++ b/code/game/objects/items/frames/light_fixtures.dm
@@ -5,12 +5,14 @@
desc = "Used for building lights."
icon = 'icons/obj/lighting.dmi'
icon_state = "tube-construct-item"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
var/fixture_type = "tube"
var/sheets_refunded = 2
/obj/item/frame/light_fixture/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
new /obj/item/stack/sheet/metal(loc, sheets_refunded)
diff --git a/code/game/objects/items/frames/table_rack.dm b/code/game/objects/items/frames/table_rack.dm
index e13d0f43fe2f0..72167b1233c7a 100644
--- a/code/game/objects/items/frames/table_rack.dm
+++ b/code/game/objects/items/frames/table_rack.dm
@@ -16,13 +16,15 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
)
item_state = "table_parts"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
attack_verb = list("slammed", "bashed", "battered", "bludgeoned", "thrashed", "whacked")
var/table_type = /obj/structure/table //what type of table it creates when assembled
var/deconstruct_type = /obj/item/stack/sheet/metal
/obj/item/frame/table/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
var/turf/table_turf = get_turf(src)
if(iswrench(I) && deconstruct_type)
@@ -98,12 +100,14 @@
name = "wooden table parts"
desc = "A kit for a table, including a large, flat wooden surface and four legs. Some assembly required."
icon_state = "wood_tableparts"
- flags_atom = null
+ atom_flags = null
table_type = /obj/structure/table/woodentable
deconstruct_type = /obj/item/stack/sheet/wood
/obj/item/frame/table/wood/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/tile/carpet))
var/obj/item/stack/tile/carpet/C = I
@@ -128,12 +132,14 @@
name = "gamble table parts"
desc = "A kit for a table, including a large, flat wooden and carpet surface and four legs. Some assembly required."
icon_state = "gamble_tableparts"
- flags_atom = null
+ atom_flags = null
table_type = /obj/structure/table/gamblingtable
deconstruct_type = /obj/item/stack/sheet/wood
/obj/item/frame/table/gambling/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iscrowbar(I))
to_chat(user, span_notice("You pry the carpet out of [src]."))
@@ -159,11 +165,13 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
)
icon_state = "rack_parts"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/obj/item/frame/rack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
new /obj/item/stack/sheet/metal(loc)
diff --git a/code/game/objects/items/gift_wrappaper.dm b/code/game/objects/items/gift_wrappaper.dm
index 11cba3b1bae92..e100af4070f59 100644
--- a/code/game/objects/items/gift_wrappaper.dm
+++ b/code/game/objects/items/gift_wrappaper.dm
@@ -132,7 +132,7 @@
/obj/item/weapon/gun/launcher/rocket/m57a4/xmas
- flags_gun_features = NONE
+ gun_features_flags = NONE
/obj/item/weapon/gun/launcher/rocket/m57a4/xmas/able_to_fire(mob/living/user)
@@ -144,7 +144,7 @@
/obj/item/weapon/gun/rifle/sniper/elite/xmas
- flags_gun_features = NONE
+ gun_features_flags = NONE
/obj/item/weapon/gun/rifle/sniper/elite/xmas/able_to_fire(mob/living/user)
@@ -159,6 +159,8 @@
/obj/effect/spresent/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!iswirecutter(I))
to_chat(user, span_notice("You need wirecutters for that."))
@@ -186,6 +188,8 @@
/obj/item/wrapping_paper/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
var/a_used = 2 ** (w_class - 1)
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 98185408be90c..e5ac03a04b336 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -4,8 +4,8 @@
gender = PLURAL
icon = 'icons/obj/items/items.dmi'
icon_state = "handcuff"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 5
w_class = WEIGHT_CLASS_SMALL
throw_speed = 2
@@ -63,7 +63,7 @@
. = ..()
if(!.)
return
- flags_item |= DELONDROP
+ item_flags |= DELONDROP
@@ -100,6 +100,8 @@
/obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/rods))
var/obj/item/stack/rods/R = I
@@ -110,7 +112,7 @@
user.put_in_hands(W)
to_chat(user, span_notice("You wrap the cable restraint around the top of the rod."))
qdel(src)
- update_icon(user)
+ update_icon()
/obj/item/restraints/handcuffs/cyborg
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index e3129754e7df6..4ce67774952aa 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -16,7 +16,7 @@
///What level of malfunction/breakage this implant is at, used for functionality checks
var/malfunction = MALFUNCTION_NONE
///Implant secific flags
- var/flags_implant = GRANT_ACTIVATION_ACTION
+ var/implant_flags = GRANT_ACTIVATION_ACTION
///Whitelist for llimbs that this implavnt is allowed to be inserted into, all limbs by default
var/list/allowed_limbs
///Activation_action reference
@@ -27,7 +27,7 @@
/obj/item/implant/Initialize(mapload)
. = ..()
- if(flags_implant & GRANT_ACTIVATION_ACTION)
+ if(implant_flags & GRANT_ACTIVATION_ACTION)
activation_action = new(src, src)
if(allow_reagents)
reagents = new /datum/reagents(MAX_IMPLANT_REAGENTS)
@@ -43,7 +43,7 @@
return ..()
/obj/item/implant/ui_action_click(mob/user, datum/action/item_action/action)
- activate()
+ return activate()
///Handles the actual activation of the implant/it's effects. Returns TRUE on succesful activation and FALSE on failure for parentcalls
/obj/item/implant/proc/activate()
@@ -77,7 +77,7 @@
CRASH("[src] implanted into [target] [user ? "by [user]" : ""] but had no limb, despite being set to implant in [limb_targeting].")
affected.implants += src
part = affected
- if(flags_implant & ACTIVATE_ON_HEAR)
+ if(implant_flags & ACTIVATE_ON_HEAR)
RegisterSignal(src, COMSIG_MOVABLE_HEAR, PROC_REF(on_hear))
activation_action?.give_action(target)
embed_into(target, limb_targeting, TRUE)
@@ -92,7 +92,7 @@
if(!implanted)
return FALSE
activation_action?.remove_action(implant_owner)
- if(flags_implant & ACTIVATE_ON_HEAR)
+ if(implant_flags & ACTIVATE_ON_HEAR)
UnregisterSignal(src, COMSIG_MOVABLE_HEAR)
implanted = FALSE
part.implants -= src
diff --git a/code/game/objects/items/implants/implant_chem.dm b/code/game/objects/items/implants/implant_chem.dm
index b8224c063a75d..9dc0a00938a76 100644
--- a/code/game/objects/items/implants/implant_chem.dm
+++ b/code/game/objects/items/implants/implant_chem.dm
@@ -2,7 +2,7 @@
name = "chemical implant"
desc = "A chemical implant containing a single use chemical cocktail which is added via syringe."
allow_reagents = TRUE
- flags_implant = ACTIVATE_ON_HEAR|GRANT_ACTIVATION_ACTION
+ implant_flags = ACTIVATE_ON_HEAR|GRANT_ACTIVATION_ACTION
var/used = FALSE
var/activation_phrase = "aaaaaa help i dying help maint"
@@ -60,5 +60,4 @@
return FALSE
var/mob/living/carbon/carb_mob = implant_owner
- var/current_blood = carb_mob.blood_volume
- carb_mob.blood_volume += min(BLOOD_VOLUME_MAXIMUM - current_blood, blood_amount)
+ carb_mob.adjust_blood_volume(blood_amount)
diff --git a/code/game/objects/items/implants/implant_cloak.dm b/code/game/objects/items/implants/implant_cloak.dm
index cfa861c7df6c4..d25eabf60499a 100644
--- a/code/game/objects/items/implants/implant_cloak.dm
+++ b/code/game/objects/items/implants/implant_cloak.dm
@@ -5,7 +5,7 @@
name = "cloak implant"
desc = "A top of the line nanotrasen implant, designed for infiltration."
icon_state = "gripper"
- flags_implant = GRANT_ACTIVATION_ACTION
+ implant_flags = GRANT_ACTIVATION_ACTION
cooldown_time = 0
var/deactivation_timer
diff --git a/code/game/objects/items/implants/implant_items.dm b/code/game/objects/items/implants/implant_items.dm
index 81e3217d5ec1d..c9af32eed5577 100644
--- a/code/game/objects/items/implants/implant_items.dm
+++ b/code/game/objects/items/implants/implant_items.dm
@@ -69,8 +69,8 @@
item_state = "armblade"
force = 75
attack_speed = 8
- flags_atom = CONDUCT
- flags_equip_slot = NONE
+ atom_flags = CONDUCT
+ equip_slot_flags = NONE
w_class = WEIGHT_CLASS_BULKY //not needed but just in case why not
sharp = IS_SHARP_ITEM_BIG
hitsound = 'sound/weapons/slash.ogg'
diff --git a/code/game/objects/items/implants/implant_neurostim.dm b/code/game/objects/items/implants/implant_neurostim.dm
index 7d4292baa0bb0..469208177647c 100644
--- a/code/game/objects/items/implants/implant_neurostim.dm
+++ b/code/game/objects/items/implants/implant_neurostim.dm
@@ -2,7 +2,7 @@
name = "neurostimulator implant"
desc = "An implant which regulates nociception and sensory function. Benefits include pain reduction, improved balance, and improved resistance to overstimulation and disoritentation. To encourage compliance, negative stimulus is applied if the implant hears a (non-radio) spoken codeprhase. Implant may be degraded by the body's immune system over time, and thus may occasionally malfunction."
icon_state = "implant_evil"
- flags_implant = ACTIVATE_ON_HEAR
+ implant_flags = ACTIVATE_ON_HEAR
var/phrase = "supercalifragilisticexpialidocious"
/obj/item/implant/neurostim/get_data()
diff --git a/code/game/objects/items/implants/implant_suicidedust.dm b/code/game/objects/items/implants/implant_suicidedust.dm
index 9f860f7b9f256..72d479d4e0e00 100644
--- a/code/game/objects/items/implants/implant_suicidedust.dm
+++ b/code/game/objects/items/implants/implant_suicidedust.dm
@@ -2,7 +2,7 @@
///In order to prevent Marines from looting things they should not ever have
/obj/item/implant/suicide_dust
name = "self-dusting implant"
- flags_implant = NONE
+ implant_flags = NONE
/obj/item/implant/suicide_dust/implant(mob/living/carbon/human/target, mob/living/user)
. = ..()
diff --git a/code/game/objects/items/implants/implantcase.dm b/code/game/objects/items/implants/implantcase.dm
index 204d9a1b28bc5..5170cfd476ecb 100644
--- a/code/game/objects/items/implants/implantcase.dm
+++ b/code/game/objects/items/implants/implantcase.dm
@@ -25,6 +25,7 @@
return ..()
/obj/item/implantcase/update_icon_state()
+ . = ..()
if(imp)
icon_state = "implantcase-[imp.implant_color]"
else
@@ -33,6 +34,8 @@
/obj/item/implantcase/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen))
var/label = stripped_input(user, "What would you like the label to be?", "[name]", null)
diff --git a/code/game/objects/items/jetpack.dm b/code/game/objects/items/jetpack.dm
index 24fe22c49e1fe..849ea47fe7137 100644
--- a/code/game/objects/items/jetpack.dm
+++ b/code/game/objects/items/jetpack.dm
@@ -12,7 +12,7 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/backpacks_right.dmi',
)
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
obj_flags = CAN_BE_HIT
///Time between uses
var/cooldown_time = 10 SECONDS
@@ -26,11 +26,12 @@
var/speed = 1
///True when jetpack has flame overlay
var/lit = FALSE
- ///True if you can use shift click/middle click to use it
- var/selected = FALSE
+ ///Controlling action
+ var/datum/action/ability/activable/item_toggle/jetpack/toggle_action
/obj/item/jetpack_marine/Initialize(mapload)
. = ..()
+ toggle_action = new(src)
update_icon()
/obj/item/jetpack_marine/examine(mob/user, distance, infix, suffix)
@@ -45,40 +46,14 @@
/obj/item/jetpack_marine/equipped(mob/user, slot)
. = ..()
if(slot == SLOT_BACK)
- var/datum/action/item_action/toggle/action = new(src)
- action.give_action(user)
+ toggle_action.give_action(user)
/obj/item/jetpack_marine/dropped(mob/user)
. = ..()
- UnregisterSignal(user, list(COMSIG_MOB_MIDDLE_CLICK, COMSIG_MOB_CLICK_ALT_RIGHT, COMSIG_ITEM_EXCLUSIVE_TOGGLE))
- selected = FALSE
- LAZYCLEARLIST(actions)
-
-/obj/item/jetpack_marine/ui_action_click(mob/user, datum/action/item_action/action)
- if(selected)
- UnregisterSignal(user, list(COMSIG_MOB_MIDDLE_CLICK, COMSIG_MOB_CLICK_ALT_RIGHT, COMSIG_ITEM_EXCLUSIVE_TOGGLE))
- action.set_toggle(FALSE)
- else
- RegisterSignals(user, list(COMSIG_MOB_MIDDLE_CLICK, COMSIG_MOB_CLICK_ALT_RIGHT), PROC_REF(can_use_jetpack))
- SEND_SIGNAL(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE, user)
- RegisterSignal(user, COMSIG_ITEM_EXCLUSIVE_TOGGLE, PROC_REF(unselect))
- action.set_toggle(TRUE)
- selected = !selected
-
-///Signal handler for making it impossible to use middleclick to use the jetpack
-/obj/item/jetpack_marine/proc/unselect(datum/source, mob/user)
- SIGNAL_HANDLER
- if(!selected)
- return
- selected = FALSE
- UnregisterSignal(user, list(COMSIG_MOB_MIDDLE_CLICK, COMSIG_MOB_CLICK_ALT_RIGHT, COMSIG_ITEM_EXCLUSIVE_TOGGLE))
- for(var/action in user.actions)
- if (!istype(action, /datum/action/item_action))
- continue
- var/datum/action/item_action/iaction = action
- if(iaction?.holder_item == src)
- iaction.set_toggle(FALSE)
+ toggle_action.remove_action(user)
+/obj/item/jetpack_marine/ui_action_click(mob/user, datum/action/item_action/action, target)
+ return use_jetpack(target, user)
///remove the flame overlay
/obj/item/jetpack_marine/proc/reset_flame(mob/living/carbon/human/human_user)
@@ -105,8 +80,8 @@
human_user.update_inv_back()
update_icon()
new /obj/effect/temp_visual/smoke(get_turf(human_user))
- human_user.fly_at(A, calculate_range(human_user), speed)
RegisterSignal(human_user, COMSIG_MOVABLE_POST_THROW, PROC_REF(reset_flame))
+ human_user.fly_at(A, calculate_range(human_user), speed)
return TRUE
///Calculate the max range of the jetpack, changed by some item slowdown
@@ -122,21 +97,6 @@
if(1.2 to INFINITY)//heavy armor with shield and tyr mk2
return 2
-///Check if we can use the jetpack and give feedback to the users
-/obj/item/jetpack_marine/proc/can_use_jetpack(datum/source, atom/A)
- SIGNAL_HANDLER
- var/mob/living/carbon/human/human_user = usr
- if(human_user.incapacitated() || human_user.lying_angle)
- return
- var/time_left = S_TIMER_COOLDOWN_TIMELEFT(src, COOLDOWN_JETPACK)
- if(time_left)
- balloon_alert(human_user, "[time_left * 0.1] seconds")
- return
- if(fuel_left < FUEL_USE)
- balloon_alert(human_user, "No fuel")
- return
- INVOKE_ASYNC(src, PROC_REF(use_jetpack), A, human_user)
-
/obj/item/jetpack_marine/update_overlays()
. = ..()
switch(fuel_indicator)
@@ -190,6 +150,8 @@
/obj/item/jetpack_marine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/ammo_magazine/flamer_tank))
return
var/obj/item/ammo_magazine/flamer_tank/FT = I
@@ -206,6 +168,27 @@
balloon_alert(user, "Refilled")
update_icon()
+/datum/action/ability/activable/item_toggle/jetpack
+ name = "Use jetpack"
+ action_icon_state = "axe_sweep"
+ desc = "Briefly fly using your jetpack."
+ use_state_flags = ABILITY_USE_STAGGERED|ABILITY_USE_BUSY
+ keybinding_signals = list(KEYBINDING_NORMAL = COMSIG_ITEM_TOGGLE_JETPACK)
+
+/datum/action/ability/activable/item_toggle/jetpack/New(Target, obj/item/holder)
+ . = ..()
+ var/obj/item/jetpack_marine/jetpack = Target
+ cooldown_duration = jetpack.cooldown_time
+
+/datum/action/ability/activable/item_toggle/jetpack/can_use_ability(silent, override_flags, selecting)
+ var/mob/living/carbon/carbon_owner = owner
+ if(carbon_owner.incapacitated() || carbon_owner.lying_angle)
+ return FALSE
+ var/obj/item/jetpack_marine/jetpack = holder_item
+ if(jetpack.fuel_left < FUEL_USE)
+ carbon_owner.balloon_alert(carbon_owner, "No fuel")
+ return
+ return ..()
/obj/item/jetpack_marine/heavy
name = "heavy lift jetpack"
diff --git a/code/game/objects/items/lightreplacer.dm b/code/game/objects/items/lightreplacer.dm
index e69b12102395d..80d5fabb41674 100644
--- a/code/game/objects/items/lightreplacer.dm
+++ b/code/game/objects/items/lightreplacer.dm
@@ -31,8 +31,8 @@
)
item_state = "electronic"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
@@ -52,6 +52,8 @@
/obj/item/lightreplacer/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
diff --git a/code/game/objects/items/loot_box.dm b/code/game/objects/items/loot_box.dm
index 2d2d5238a91af..d5274f30c93f7 100644
--- a/code/game/objects/items/loot_box.dm
+++ b/code/game/objects/items/loot_box.dm
@@ -421,7 +421,7 @@
/obj/item/storage/box/crate/loot/sadarclassic_pack,
)
rare_list = list(
- /obj/item/storage/box/crate/loot/tl102_pack,
+ /obj/item/storage/box/crate/loot/hsg_102_pack,
/obj/item/storage/box/crate/loot/mortar_pack,
/obj/structure/closet/crate/loot/howitzer_pack,
/obj/item/storage/box/crate/loot/sentry_pack,
@@ -620,10 +620,10 @@
new /obj/item/mortal_shell/howitzer/white_phos(src)
new /obj/item/mortal_shell/howitzer/white_phos(src)
-/obj/item/storage/box/crate/loot/tl102_pack/Initialize(mapload)
+/obj/item/storage/box/crate/loot/hsg_102_pack/Initialize(mapload)
. = ..()
- new /obj/item/storage/box/tl102(src)
- new /obj/item/storage/box/tl102(src)
+ new /obj/item/storage/box/hsg_102(src)
+ new /obj/item/storage/box/hsg_102(src)
/obj/item/storage/box/crate/loot/agl_pack/Initialize(mapload)
. = ..()
@@ -676,5 +676,5 @@
/obj/item/storage/box/crate/loot/sadarclassic_pack/Initialize(mapload)
. = ..()
new /obj/item/weapon/gun/launcher/rocket/sadar(src)
- new /obj/item/storage/backpack/marine/satchel/scout_cloak/scout(src)
+ new /obj/item/storage/backpack/marine/satchel/scout_cloak(src)
new /obj/item/ammo_magazine/rocket/sadar/ap(src)
diff --git a/code/game/objects/items/marine_gear.dm b/code/game/objects/items/marine_gear.dm
index 07f1d72c973fa..f17e9eb1bfb98 100644
--- a/code/game/objects/items/marine_gear.dm
+++ b/code/game/objects/items/marine_gear.dm
@@ -64,7 +64,7 @@
list("dark chocolate TGMC protein bar","The dark chocolate flavor helps it out a bit, but its still a cheap protein bar.","#5a3b1d",list("bitter dark chocolate" = 1)),
list("milk chocolate TGMC protein bar","A nice milky addition to a otherwise bland protein taste.","#efc296",list("off flavor milk chocolate"= 1)),
list("raspberry lime TGMC protein bar","A flavored protein bar, some might say a bit too strongly flavored for their tastes.","#ff0066",list("sour raspberry and lime" = 1)),
- list("chicken TGMC protein bar","Protein bar covered with chicken powder one might find in ramen. Get some extra sodium with your protein.","#cccc00",list= ("powdered chicken")),
+ list("chicken TGMC protein bar","Protein bar covered with chicken powder one might find in ramen. Get some extra sodium with your protein.","#cccc00",list("powdered chicken" = 1)),
list("blueberry TGMC protein bar","A nice blueberry crunch into your otherwise stale and boring protein bar.","#4e39c5",list("blueberry" = 1)),
list("cement TGMC protein bar", "A gray bar that's allegedly made of cement. It seems to have hardened up. Perhaps it'll make you harden up, too.", "#B2B2B2", list("cement" = 1))
),
@@ -77,7 +77,7 @@
list("milk chocolate SOM protein bar","A nice milky addition to a otherwise bland protein taste.","#efc296",list("off flavor milk chocolate"= 1)),
list("beef SOM protein bar","A beef flavored protein bar, doesn't taste like any cow you've ever tried.","#ff0066",list("meat substitute" = 1)),
list("meat SOM protein bar","A surprisingly tasty protein bar made from an unspecified meat. Rumors claiming they're made from reconstituted TGMC personnel have been widely dismissed.","#a7576b",list("pork" = 1)),
- list("chicken SOM protein bar","Protein bar covered with chicken powder one might find in ramen. Get some extra sodium with your protein.","#cccc00",list= ("powdered chicken")),
+ list("chicken SOM protein bar","Protein bar covered with chicken powder one might find in ramen. Get some extra sodium with your protein.","#cccc00",list("powdered chicken" = 1)),
list("blueberry SOM protein bar","A nice blueberry crunch into your otherwise stale and boring protein bar.","#4e39c5",list("blueberry" = 1))
),
)
@@ -248,11 +248,11 @@
icon = 'icons/obj/clothing/belts.dmi'
icon_state = "gun_sling"
item_state = "gun_sling"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_BULKY
equip_delay_self = 2 SECONDS
unequip_delay_self = 1 SECONDS
- flags_inventory = NOQUICKEQUIP
+ inventory_flags = NOQUICKEQUIP
///The current attacher. Gets remade for every new item
var/datum/component/reequip/reequip_component
diff --git a/code/game/objects/items/megaphone.dm b/code/game/objects/items/megaphone.dm
index 738397e174100..991d22eef181c 100644
--- a/code/game/objects/items/megaphone.dm
+++ b/code/game/objects/items/megaphone.dm
@@ -9,7 +9,7 @@
)
item_state = "radio"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
var/spamcheck = 0
var/list/voicespan = list(SPAN_COMMAND)
diff --git a/code/game/objects/items/misc.dm b/code/game/objects/items/misc.dm
index c216bbb75e074..9b94a042cb8be 100644
--- a/code/game/objects/items/misc.dm
+++ b/code/game/objects/items/misc.dm
@@ -123,3 +123,11 @@
desc = "A small set of servos and gears, coupled to a battery, antenna and circuitry. Attach it to a mortar to allow a shipborne AI to remotely target it."
icon = 'icons/obj/items/items.dmi'
icon_state = "modkit"
+
+/obj/item/rosary
+ name = "Rosary"
+ desc = "A small hematite-beaded silver rosary"
+ icon = 'icons/obj/items/items.dmi'
+ icon_state = "rosary"
+ item_state = "rosary"
+ w_class = WEIGHT_CLASS_TINY
diff --git a/code/game/objects/items/motion_detector.dm b/code/game/objects/items/motion_detector.dm
index 6afe631102738..1169178dbd9c0 100644
--- a/code/game/objects/items/motion_detector.dm
+++ b/code/game/objects/items/motion_detector.dm
@@ -24,6 +24,7 @@
qdel(src)
/obj/effect/blip/edge_blip/update_icon_state()
+ . = ..()
icon_state = "edge_blip_[identifier]"
/obj/effect/blip/close_blip
@@ -52,7 +53,7 @@
desc = "A device that detects hostile movement. Hostiles appear as red blips. Friendlies with the correct IFF signature appear as green, and their bodies as blue, unrevivable bodies as dark blue. It has a mode selection interface."
icon_state = "minidetector"
slot = ATTACHMENT_SLOT_RAIL
- attachment_action_type = /datum/action/item_action/toggle/motion_detector
+ attachment_action_type = /datum/action/item_action/toggle
/// Who's using this item
var/mob/living/carbon/human/operator
///If a hostile was detected
@@ -65,19 +66,20 @@
var/list/obj/effect/blip/blips_list = list()
/obj/item/attachable/motiondetector/Destroy()
- clean_operator()
+ clean_operator(forced = TRUE)
return ..()
/obj/item/attachable/motiondetector/activate(mob/user, turn_off)
if(operator)
- clean_operator()
- return
+ clean_operator(forced = TRUE)
+ return TRUE
operator = user
RegisterSignals(operator, list(COMSIG_QDELETING, COMSIG_GUN_USER_UNSET), PROC_REF(clean_operator))
RegisterSignals(src, list(COMSIG_ITEM_EQUIPPED_TO_SLOT, COMSIG_ITEM_REMOVED_INVENTORY), PROC_REF(clean_operator))
UnregisterSignal(operator, COMSIG_GUN_USER_SET)
START_PROCESSING(SSobj, src)
update_icon()
+ return TRUE
///Activate the attachement when your are putting the gun out of your suit slot
/obj/item/attachable/motiondetector/proc/start_processing_again(datum/source, obj/item/weapon/gun/equipping)
@@ -93,12 +95,8 @@
/obj/item/attachable/motiondetector/attack_self(mob/user)
activate(user)
-/obj/item/attachable/motiondetector/update_icon()
- . = ..()
- for(var/datum/action/action AS in master_gun?.actions)
- action.update_button_icon()
-
/obj/item/attachable/motiondetector/update_icon_state()
+ . = ..()
icon_state = initial(icon_state) + (isnull(operator) ? "" : "_on")
/obj/item/attachable/motiondetector/equipped(mob/user, slot)
@@ -108,12 +106,12 @@
/obj/item/attachable/motiondetector/removed_from_inventory(mob/user)
. = ..()
- clean_operator()
+ clean_operator(forced = TRUE) //Exploit prevention. If you are putting the tac sensor into a storage in your hand (Like holding a satchel), hand == loc will return
/// Signal handler to clean out user vars
-/obj/item/attachable/motiondetector/proc/clean_operator()
+/obj/item/attachable/motiondetector/proc/clean_operator(datum/source, obj/item/weapon/gun/gun, forced = FALSE)
SIGNAL_HANDLER
- if(operator && (operator.l_hand == src || operator.r_hand == src || operator.l_hand == loc || operator.r_hand == loc))
+ if(!forced && operator && (operator.l_hand == src || operator.r_hand == src || operator.l_hand == loc || operator.r_hand == loc))
return
STOP_PROCESSING(SSobj, src)
clean_blips()
diff --git a/code/game/objects/items/multitool.dm b/code/game/objects/items/multitool.dm
index 72c0a5593aac0..a97dea728da00 100644
--- a/code/game/objects/items/multitool.dm
+++ b/code/game/objects/items/multitool.dm
@@ -8,7 +8,7 @@
name = "multitool"
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors."
icon_state = "multitool"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 5
w_class = WEIGHT_CLASS_SMALL
throwforce = 5
diff --git a/code/game/objects/items/pamphlets.dm b/code/game/objects/items/pamphlets.dm
new file mode 100644
index 0000000000000..ce2adbc2788d6
--- /dev/null
+++ b/code/game/objects/items/pamphlets.dm
@@ -0,0 +1,41 @@
+//skill modifying item
+/obj/item/pamphlet
+ name = "generic phamplet"
+ desc = "you shouldnt see this"
+ icon = 'icons/obj/items/paper.dmi'
+ icon_state = "paper_words"
+ var/cqc
+ var/melee_weapons
+ var/firearms
+ var/pistols
+ var/shotguns
+ var/rifles
+ var/smgs
+ var/heavy_weapons
+ var/smartgun
+ var/engineer
+ var/construction
+ var/leadership
+ var/medical
+ var/surgery
+ var/pilot
+ var/police
+ var/powerloader
+ var/large_vehicle
+ var/stamina
+
+/obj/item/pamphlet/attack_self(mob/living/user)
+ . = ..()
+ if(!do_after(user, 5 SECONDS, NONE, user))
+ return
+ user.set_skills(user.skills.modifyRating(cqc, melee_weapons, firearms, pistols, shotguns, rifles, smgs, heavy_weapons, smartgun, \
+ engineer, construction, leadership, medical, surgery, pilot, police, powerloader, large_vehicle, stamina))
+ user.temporarilyRemoveItemFromInventory(src)
+ qdel(src)
+
+
+/obj/item/pamphlet/tank_loader
+ name = "loader's instruction manual"
+ desc = "A crude drawing depicting what you think is loading a tank gun. Is that crayon?"
+ large_vehicle = 1
+
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
index ec28ba5951f8c..98e16d7e3103a 100644
--- a/code/game/objects/items/pinpointer.dm
+++ b/code/game/objects/items/pinpointer.dm
@@ -2,8 +2,8 @@
name = "Xeno structure pinpointer"
icon = 'icons/Marine/marine-navigation.dmi'
icon_state = "pinoff"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_TINY
item_icons = list(
slot_l_hand_str = 'icons/mob/inhands/equipment/engineering_left.dmi',
diff --git a/code/game/objects/items/plantable_flags.dm b/code/game/objects/items/plantable_flags.dm
index 4f172ae09b931..4a9d4bdbbff08 100644
--- a/code/game/objects/items/plantable_flags.dm
+++ b/code/game/objects/items/plantable_flags.dm
@@ -25,7 +25,7 @@
playsound(loc, 'sound/effects/thud.ogg', 100)
user.dropItemToGround(src)
is_collapsed = FALSE
- update_icon_state()
+ update_appearance()
/obj/item/flag_base/attack_hand(mob/living/user)
@@ -34,8 +34,8 @@
to_chat(user, "You decide against removing the flag here.")
return
is_collapsed = TRUE
- update_icon_state()
- . = ..()
+ update_appearance()
+ return ..()
/obj/item/flag_base/update_icon_state()
diff --git a/code/game/objects/items/portable_vendor.dm b/code/game/objects/items/portable_vendor.dm
index dc8748f926559..54ac8f97ea0b2 100644
--- a/code/game/objects/items/portable_vendor.dm
+++ b/code/game/objects/items/portable_vendor.dm
@@ -11,7 +11,7 @@
slot_l_hand_str = 'icons/mob/inhands/items/containers_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/items/containers_right.dmi',
)
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 8
hitsound = "swing_hit"
throw_speed = 1
@@ -132,7 +132,7 @@
playsound(src, "sound/machines/fax.ogg", 5)
balloon_alert(user, "fabricating")
fabricating = TRUE
- update_overlays()
+ update_appearance()
addtimer(CALLBACK(src, PROC_REF(do_vend), L[3], user), 1 SECONDS)
/obj/item/portable_vendor/proc/do_vend(thing, mob/user)
@@ -140,7 +140,7 @@
if(loc == user)
user.put_in_hands(IT)
fabricating = FALSE
- update_overlays()
+ update_appearance()
/obj/item/portable_vendor/update_overlays()
. = ..()
@@ -161,7 +161,7 @@
/obj/item/portable_vendor/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
- update_overlays()
+ update_appearance()
/obj/item/portable_vendor/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -173,7 +173,7 @@
T.visible_message(span_warning("[src] shudders as its internal components break apart!"))
broken = 1
STOP_PROCESSING(SSobj, src)
- update_overlays()
+ update_appearance()
playsound(src, 'sound/effects/sparks4.ogg', 60, 1)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
diff --git a/code/game/objects/items/quickdeploy_cade.dm b/code/game/objects/items/quickdeploy_cade.dm
index 1e2c2fc1f5e4e..78ba11f4e3349 100644
--- a/code/game/objects/items/quickdeploy_cade.dm
+++ b/code/game/objects/items/quickdeploy_cade.dm
@@ -51,7 +51,7 @@
for(var/obj/thing in user.loc)
if(!thing.density) //not dense, move on
continue
- if(!(thing.flags_atom & ON_BORDER)) //dense and non-directional, end
+ if(!(thing.atom_flags & ON_BORDER)) //dense and non-directional, end
balloon_alert(user, "No space")
return FALSE
if(thing.dir != user.dir)
diff --git a/code/game/objects/items/radio/detpack.dm b/code/game/objects/items/radio/detpack.dm
index 788c674ee354d..f43da27d5e8e8 100644
--- a/code/game/objects/items/radio/detpack.dm
+++ b/code/game/objects/items/radio/detpack.dm
@@ -9,7 +9,7 @@
slot_r_hand_str = 'icons/mob/inhands/weapons/explosives_right.dmi',
)
item_state = "plasticx"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
layer = MOB_LAYER - 0.1
var/frequency = 1457
@@ -70,6 +70,7 @@
/obj/item/detpack/update_icon_state()
+ . = ..()
icon_state = "detpack_[plant_target ? "set_" : ""]"
if(on)
icon_state = "[icon_state][armed ? "armed" : "on"]"
@@ -79,6 +80,8 @@
/obj/item/detpack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(ismultitool(I) && armed)
if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_METAL)
@@ -136,8 +139,9 @@
if(!signal || !on)
return
- var/turf/location = get_turf(signal.source)
- if(location.z != z)
+ var/turf/source_location = get_turf(signal.source)
+ var/turf/det_location = get_turf(src)
+ if(source_location.z != det_location.z)
return
if(signal.data["code"] != code)
@@ -340,15 +344,13 @@
//Time to go boom
playsound(src.loc, 'sound/weapons/ring.ogg', 200, FALSE)
boom = TRUE
+ var/turf/det_location = get_turf(plant_target)
+ plant_target.ex_act(EXPLODE_DEVASTATE)
+ plant_target = null
if(det_mode == TRUE) //If we're on demolition mode, big boom.
- explosion(plant_target, 3, 5, 6, 0, 6)
+ explosion(det_location, 3, 5, 6, 0, 6)
else //if we're not, focused boom.
- explosion(plant_target, 2, 2, 3, 0, 3, throw_range = FALSE)
- if(plant_target)
- if(isobj(plant_target))
- plant_target = null
- if(!istype(plant_target,/obj/vehicle/multitile/root/cm_armored))
- qdel(plant_target)
+ explosion(det_location, 2, 2, 3, 0, 3, throw_range = FALSE)
qdel(src)
diff --git a/code/game/objects/items/radio/electropack.dm b/code/game/objects/items/radio/electropack.dm
index 424b0913b6b25..ed39207150ba8 100644
--- a/code/game/objects/items/radio/electropack.dm
+++ b/code/game/objects/items/radio/electropack.dm
@@ -8,8 +8,8 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/security_right.dmi',
)
item_state = "electropack"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BACK
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
diff --git a/code/game/objects/items/radio/encryptionkey.dm b/code/game/objects/items/radio/encryptionkey.dm
index 1d4d60343636b..204d4459dd634 100644
--- a/code/game/objects/items/radio/encryptionkey.dm
+++ b/code/game/objects/items/radio/encryptionkey.dm
@@ -124,6 +124,11 @@ GLOBAL_LIST_EMPTY_TYPED(custom_updating_encryptkeys, /obj/item/encryptionkey)
channels = list(RADIO_CHANNEL_ICC = TRUE)
independent = TRUE
+/obj/item/encryptionkey/retired
+ name = "\improper retirement home encryption key"
+ channels = list(RADIO_CHANNEL_RETIRED = TRUE)
+ independent = TRUE
+
/obj/item/encryptionkey/sectoid
name = "\improper alien encryption key"
channels = list(RADIO_CHANNEL_SECTOID = TRUE)
diff --git a/code/game/objects/items/radio/headset.dm b/code/game/objects/items/radio/headset.dm
index c607f3097ba67..f3e4d131bb0f0 100644
--- a/code/game/objects/items/radio/headset.dm
+++ b/code/game/objects/items/radio/headset.dm
@@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
subspace_transmission = TRUE
canhear_range = 0 // can't hear headsets from very far away
- flags_equip_slot = ITEM_SLOT_EARS
+ equip_slot_flags = ITEM_SLOT_EARS
var/obj/item/encryptionkey/keyslot2 = null
@@ -54,6 +54,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
/obj/item/radio/headset/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
if(keyslot || keyslot2)
@@ -170,7 +172,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
icon_state = "cargo_headset"
item_state = "headset"
frequency = FREQ_COMMON
- flags_atom = CONDUCT | PREVENT_CONTENTS_EXPLOSION
+ atom_flags = CONDUCT | PREVENT_CONTENTS_EXPLOSION
freerange = TRUE
var/obj/machinery/camera/camera
var/datum/atom_hud/squadhud = null
@@ -210,7 +212,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
/obj/item/radio/headset/mainship/proc/safety_protocol(mob/living/carbon/human/user)
balloon_alert_to_viewers("Explodes")
playsound(user, 'sound/effects/explosion_micro1.ogg', 50, 1)
- user.ex_act(EXPLODE_LIGHT)
+ if(wearer)
+ wearer.ex_act(EXPLODE_LIGHT)
qdel(src)
/* RUTGMC DELETION, SL_locator beheading runtime fix
@@ -234,7 +237,6 @@ GLOBAL_LIST_INIT(channel_tokens, list(
if(wearer)
if(headset_hud_on && wearer.wear_ear == src)
squadhud.remove_hud_from(wearer)
- wearer.SL_directional = null
if(wearer.assigned_squad)
SSdirection.stop_tracking(wearer.assigned_squad.tracking_id, wearer)
wearer = null
@@ -286,8 +288,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
if(HAS_TRAIT(wearer, TRAIT_UNDEFIBBABLE))
SSminimaps.add_marker(wearer, marker_flags, image('icons/UI_icons/map_blips.dmi', null, "undefibbable"))
return
- if(!wearer.client)
- var/mob/dead/observer/ghost = wearer.get_ghost()
+ if(!wearer.mind)
+ var/mob/dead/observer/ghost = wearer.get_ghost(TRUE)
if(!ghost?.can_reenter_corpse)
SSminimaps.add_marker(wearer, marker_flags, image('icons/UI_icons/map_blips.dmi', null, "undefibbable"))
return
@@ -450,7 +452,10 @@ GLOBAL_LIST_INIT(channel_tokens, list(
/obj/item/radio/headset/mainship/marine/Initialize(mapload, datum/squad/squad, rank)
if(squad)
- icon_state = "headset_marine_[lowertext(squad.name)]"
+ icon_state = "headset_marine_greyscale"
+ var/image/coloring = image(icon, icon_state="headset_marine_overlay")
+ coloring.color = squad.color
+ add_overlay(coloring)
var/dat = "marine [lowertext(squad.name)]"
frequency = squad.radio_freq
if(ispath(rank, /datum/job/terragov/squad/leader))
@@ -649,6 +654,11 @@ GLOBAL_LIST_INIT(channel_tokens, list(
name = "\improper Echo Task Force headset"
keyslot = /obj/item/encryptionkey/echo
+/obj/item/radio/headset/distress/retired
+ name = "retirement home headset"
+ keyslot = /obj/item/encryptionkey/retired
+ frequency = FREQ_RETIRED
+
//SOM headsets
/obj/item/radio/headset/mainship/som
diff --git a/code/game/objects/items/radio/intercom.dm b/code/game/objects/items/radio/intercom.dm
index 6f6dd8adf3bae..d28bd5154d1bd 100644
--- a/code/game/objects/items/radio/intercom.dm
+++ b/code/game/objects/items/radio/intercom.dm
@@ -6,7 +6,7 @@
anchored = TRUE
w_class = WEIGHT_CLASS_BULKY
canhear_range = 2
- flags_atom = CONDUCT|NOBLOODY
+ atom_flags = CONDUCT|NOBLOODY
light_range = 1.5
light_power = 0.5
light_color = LIGHT_COLOR_EMISSIVE_YELLOW
@@ -28,15 +28,15 @@
pixel_x = 32
START_PROCESSING(SSobj, src)
become_hearing_sensitive()
- update_icon()
+ check_light()
/obj/item/radio/intercom/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/radio/intercom/update_icon()
- . = ..()
+///Checks if we're on, if so a light turns on
+/obj/item/radio/intercom/proc/check_light()
if(!on)
set_light(0)
return
@@ -44,6 +44,7 @@
set_light(initial(light_range))
/obj/item/radio/intercom/update_icon_state()
+ . = ..()
if(!on)
icon_state = "intercom_unpowered"
else
@@ -56,16 +57,14 @@
. += emissive_appearance(icon, "[icon_state]_emissive")
/obj/item/radio/intercom/attack_ai(mob/user as mob)
- spawn (0)
- attack_self(user)
+ attack_self(user)
/obj/item/radio/intercom/attack_hand(mob/living/user)
. = ..()
if(.)
return
- spawn (0)
- attack_self(user)
+ attack_self(user)
/obj/item/radio/intercom/can_receive(freq, list/levels)
@@ -100,7 +99,7 @@
return
else
on = new_state
- update_icon()
+ check_light()
/obj/item/radio/intercom/general
name = "General Listening Channel"
diff --git a/code/game/objects/items/radio/radio.dm b/code/game/objects/items/radio/radio.dm
index b2dc331551c43..a784a5b1efa19 100644
--- a/code/game/objects/items/radio/radio.dm
+++ b/code/game/objects/items/radio/radio.dm
@@ -8,8 +8,8 @@
)
item_state = "radio"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throw_speed = 2
throw_range = 9
w_class = WEIGHT_CLASS_SMALL
@@ -292,10 +292,21 @@
return
var/area/A = get_area(src)
- if(!isnull(A) && (A.ceiling >= CEILING_UNDERGROUND) && !(A.flags_area & ALWAYS_RADIO))
+ var/radio_disruption = CAVE_NO_INTERFERENCE
+ if(!isnull(A) && (A.ceiling >= CEILING_UNDERGROUND) && !(A.area_flags & ALWAYS_RADIO))
+ radio_disruption = CAVE_MINOR_INTERFERENCE
if(A.ceiling >= CEILING_DEEP_UNDERGROUND)
+ radio_disruption = CAVE_FULL_INTERFERENCE
+
+ var/list/inplace_interference = list(radio_disruption)
+ SEND_SIGNAL(talking_movable, COMSIG_CAVE_INTERFERENCE_CHECK, inplace_interference)
+ radio_disruption = inplace_interference[1]
+
+ switch(radio_disruption)
+ if(CAVE_MINOR_INTERFERENCE)
+ signal.data["compression"] += rand(20, 40)
+ if(CAVE_FULL_INTERFERENCE)
return
- signal.data["compression"] += rand(20, 40)
// All non-independent radios make an attempt to use the subspace system first
signal.send_to_receivers()
@@ -345,8 +356,23 @@
var/turf/position = get_turf(src)
if(!position || !(position.z in levels))
return FALSE
+ var/radio_disruption = CAVE_NO_INTERFERENCE
var/area/A = get_area(src)
- if(A?.ceiling >= CEILING_DEEP_UNDERGROUND)
+ if(A?.ceiling >= CEILING_UNDERGROUND && !(A.area_flags & ALWAYS_RADIO))
+ radio_disruption = CAVE_MINOR_INTERFERENCE //Unused for this case but may aswell create parity on what the value of the var is.
+ if(A.ceiling >= CEILING_DEEP_UNDERGROUND)
+ radio_disruption = CAVE_FULL_INTERFERENCE
+ var/list/potential_owners = get_nested_locs(src) //Sometimes not equipped, sometimes not even equippable, sometimes in storage, this feels like it's an okay way to do it.
+ var/mob/living/found_owner
+ for(var/mob/living/candidate in potential_owners)
+ found_owner = candidate
+ break
+
+ if(found_owner)
+ var/inplace_interference = list(radio_disruption)
+ SEND_SIGNAL(found_owner, COMSIG_CAVE_INTERFERENCE_CHECK, inplace_interference)
+ radio_disruption = inplace_interference[1]
+ if(radio_disruption == CAVE_FULL_INTERFERENCE)
return FALSE
// allow checks: are we listening on that frequency?
@@ -372,6 +398,8 @@
/obj/item/radio/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && !subspace_transmission)
unscrewed = !unscrewed
if(unscrewed)
diff --git a/code/game/objects/items/rcd.dm b/code/game/objects/items/rcd.dm
index ef0ba36e35755..ca528c098d9be 100644
--- a/code/game/objects/items/rcd.dm
+++ b/code/game/objects/items/rcd.dm
@@ -6,7 +6,7 @@
opacity = FALSE
density = FALSE
anchored = FALSE
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 10
throwforce = 10
throw_speed = 1
diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm
index e9982bf2388b8..60a1a1157abd1 100644
--- a/code/game/objects/items/reagent_containers/autoinjectors.dm
+++ b/code/game/objects/items/reagent_containers/autoinjectors.dm
@@ -11,6 +11,7 @@
list_reagents = list(/datum/reagent/consumable/sodiumchloride = 30)
/obj/item/reagent_containers/hypospray/autoinjector/update_icon_state()
+ . = ..()
if(!(reagents.total_volume) && is_drawable())
icon_state += "X"
name = "expended [name]" //So people can see what have been expended since we have smexy new sprites people aren't used too...
@@ -309,7 +310,7 @@
icon_state = "autoinjector-6"
amount_per_transfer_from_this = 1
volume = 1
- list_reagents = list(/datum/reagent/medicine/research/medicalnanites = 1)
+ list_reagents = list(/datum/reagent/medicalnanites = 1)
free_refills = FALSE
/obj/item/reagent_containers/hypospray/autoinjector/pain //made for debugging
diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm
index 760e4b61a802a..05909c8ccb68a 100644
--- a/code/game/objects/items/reagent_containers/blood_pack.dm
+++ b/code/game/objects/items/reagent_containers/blood_pack.dm
@@ -20,7 +20,7 @@
update_icon()
/obj/item/reagent_containers/blood/update_icon_state()
-
+ . = ..()
var/percent = PERCENT(reagents.total_volume / volume)
switch(percent)
if(0 to 9.9)
diff --git a/code/game/objects/items/reagent_containers/dropper.dm b/code/game/objects/items/reagent_containers/dropper.dm
index f1a7bd01052c8..4f3a89d1986a2 100644
--- a/code/game/objects/items/reagent_containers/dropper.dm
+++ b/code/game/objects/items/reagent_containers/dropper.dm
@@ -42,10 +42,10 @@
var/obj/item/safe_thing = null
if( victim.wear_mask )
- if ( victim.wear_mask.flags_inventory & COVEREYES )
+ if ( victim.wear_mask.inventory_flags & COVEREYES )
safe_thing = victim.wear_mask
if( victim.head )
- if ( victim.head.flags_inventory & COVEREYES )
+ if ( victim.head.inventory_flags & COVEREYES )
safe_thing = victim.head
if(victim.glasses)
if ( !safe_thing )
diff --git a/code/game/objects/items/reagent_containers/food/burgers.dm b/code/game/objects/items/reagent_containers/food/burgers.dm
index d38e885308b47..f6cc39b46f9cf 100644
--- a/code/game/objects/items/reagent_containers/food/burgers.dm
+++ b/code/game/objects/items/reagent_containers/food/burgers.dm
@@ -294,6 +294,8 @@
// Human Burger + cheese wedge = cheeseburger
/obj/item/reagent_containers/food/snacks/burger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/food/snacks/cheesewedge))
new /obj/item/reagent_containers/food/snacks/burger/cheese(src)
@@ -305,6 +307,8 @@
// Burger + cheese wedge = cheeseburger
/obj/item/reagent_containers/food/snacks/burger/plain/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/food/snacks/cheesewedge))
new /obj/item/reagent_containers/food/snacks/burger/cheese(src)
@@ -330,6 +334,8 @@
/obj/item/reagent_containers/food/snacks/burger/bun/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
// Bun + meatball = burger
if(istype(I, /obj/item/reagent_containers/food/snacks/meatball))
new /obj/item/reagent_containers/food/snacks/burger/plain(src)
diff --git a/code/game/objects/items/reagent_containers/food/cans.dm b/code/game/objects/items/reagent_containers/food/cans.dm
index d1670b2e7a2d4..3d1cf57458099 100644
--- a/code/game/objects/items/reagent_containers/food/cans.dm
+++ b/code/game/objects/items/reagent_containers/food/cans.dm
@@ -3,10 +3,10 @@
init_reagent_flags = NONE
var/canopened = FALSE
-/obj/item/reagent_containers/food/drinks/cans/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/reagent_containers/food/drinks/cans/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
/obj/item/reagent_containers/food/drinks/cans/attack_self(mob/user as mob)
diff --git a/code/game/objects/items/reagent_containers/food/donuts.dm b/code/game/objects/items/reagent_containers/food/donuts.dm
index 1eb1531fc6621..2b6af43e10d2a 100644
--- a/code/game/objects/items/reagent_containers/food/donuts.dm
+++ b/code/game/objects/items/reagent_containers/food/donuts.dm
@@ -179,7 +179,7 @@
desc = "Goes great with a bottle of Bastion Burbon!"
icon_state = "donut_laugh"
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/laughter = 3)
- tastes = list("donut" = 3, "fizzy tutti frutti" = 1,)
+ tastes = list("donut" = 3, "fizzy tutti frutti" = 1)
/obj/item/reagent_containers/food/snacks/donut/jelly/trumpet
name = "spaceman's jelly donut"
diff --git a/code/game/objects/items/reagent_containers/food/drinks.dm b/code/game/objects/items/reagent_containers/food/drinks.dm
index 8c9965b70f511..3ee18a0e283bc 100644
--- a/code/game/objects/items/reagent_containers/food/drinks.dm
+++ b/code/game/objects/items/reagent_containers/food/drinks.dm
@@ -113,7 +113,7 @@
amount_per_transfer_from_this = 20
possible_transfer_amounts = null
volume = 150
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/obj/item/reagent_containers/food/drinks/golden_cup/tournament_26_06_2011
desc = "A golden cup. It will be presented to a winner of tournament 26 june and name of the winner will be graved on it."
diff --git a/code/game/objects/items/reagent_containers/food/drinks/bottle.dm b/code/game/objects/items/reagent_containers/food/drinks/bottle.dm
index abbdd3e56ce5a..53fa066ccff34 100644
--- a/code/game/objects/items/reagent_containers/food/drinks/bottle.dm
+++ b/code/game/objects/items/reagent_containers/food/drinks/bottle.dm
@@ -74,10 +74,10 @@
//Finally, smash the bottle. This kills (del) the bottle.
smash(target, user)
-/obj/item/reagent_containers/food/drinks/bottle/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/reagent_containers/food/drinks/bottle/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
/obj/item/reagent_containers/food/drinks/bottle/gin
name = "\improper Griffeater Gin"
diff --git a/code/game/objects/items/reagent_containers/food/drinks/drinkingglass.dm b/code/game/objects/items/reagent_containers/food/drinks/drinkingglass.dm
index 6ba09eadaddf1..83de06e7a5321 100644
--- a/code/game/objects/items/reagent_containers/food/drinks/drinkingglass.dm
+++ b/code/game/objects/items/reagent_containers/food/drinks/drinkingglass.dm
@@ -611,10 +611,10 @@
center_of_mass = list("x"=16, "y"=10)
return
-/obj/item/reagent_containers/food/drinks/drinkingglass/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/reagent_containers/food/drinks/drinkingglass/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
// for /obj/machinery/vending/sovietsoda
/obj/item/reagent_containers/food/drinks/drinkingglass/soda
diff --git a/code/game/objects/items/reagent_containers/food/pizzapasta.dm b/code/game/objects/items/reagent_containers/food/pizzapasta.dm
index 0b6c83ce48681..7a2bf6ca795fd 100644
--- a/code/game/objects/items/reagent_containers/food/pizzapasta.dm
+++ b/code/game/objects/items/reagent_containers/food/pizzapasta.dm
@@ -171,56 +171,55 @@
var/list/boxes = list() // If the boxes are stacked, they come here
var/boxtag = ""
-/obj/item/pizzabox/update_icon()
-
- overlays = list()
-
- // Set appropriate description
- if( open && pizza )
+/obj/item/pizzabox/update_desc(updates)
+ . = ..()
+ if(open && pizza)
desc = "A box suited for pizzas. It appears to have a [pizza.name] inside."
- else if( boxes.len > 0 )
+ else if(boxes.len > 0)
desc = "A pile of boxes suited for pizzas. There appears to be [boxes.len + 1] boxes in the pile."
var/obj/item/pizzabox/topbox = boxes[boxes.len]
var/toptag = topbox.boxtag
- if( toptag != "" )
+ if(toptag != "")
desc = "[desc] The box on top has a tag, it reads: '[toptag]'."
else
desc = "A box suited for pizzas."
- if( boxtag != "" )
+ if(boxtag != "")
desc = "[desc] The box has a tag, it reads: '[boxtag]'."
- // Icon states and overlays
- if( open )
- if( ismessy )
+/obj/item/pizzabox/update_icon_state()
+ . = ..()
+ if(open)
+ if(ismessy)
icon_state = "pizzabox_messy"
else
icon_state = "pizzabox_open"
+ return
- if( pizza )
- var/image/pizzaimg = image("pizzaspaghetti.dmi", icon_state = pizza.icon_state)
- pizzaimg.pixel_y = -3
- overlays += pizzaimg
+ icon_state = "pizzabox[boxes.len+1]"
+/obj/item/pizzabox/update_overlays()
+ . = ..()
+ if(open && pizza)
+ var/image/pizzaimg = image("pizzaspaghetti.dmi", icon_state = pizza.icon_state)
+ pizzaimg.pixel_y = -3
+ . += pizzaimg
return
+ // Stupid code because byondcode sucks - imagine blaming the engine for you being bad at coding. TODO: clean this up
+ var/doimgtag = 0
+ if(boxes.len > 0)
+ var/obj/item/pizzabox/topbox = boxes[boxes.len]
+ if(topbox.boxtag != "")
+ doimgtag = 1
else
- // Stupid code because byondcode sucks
- var/doimgtag = 0
- if( boxes.len > 0 )
- var/obj/item/pizzabox/topbox = boxes[boxes.len]
- if( topbox.boxtag != "" )
- doimgtag = 1
- else
- if( boxtag != "" )
- doimgtag = 1
+ if(boxtag != "")
+ doimgtag = 1
- if( doimgtag )
- var/image/tagimg = image("pizzaspaghetti.dmi", icon_state = "pizzabox_tag")
- tagimg.pixel_y = boxes.len * 3
- overlays += tagimg
-
- icon_state = "pizzabox[boxes.len+1]"
+ if(doimgtag)
+ var/image/tagimg = image("pizzaspaghetti.dmi", icon_state = "pizzabox_tag")
+ tagimg.pixel_y = boxes.len * 3
+ . += tagimg
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/pizzabox/attack_hand(mob/living/user)
@@ -261,6 +260,8 @@
/obj/item/pizzabox/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/pizzabox))
var/obj/item/pizzabox/box = I
diff --git a/code/game/objects/items/reagent_containers/food/sandwich.dm b/code/game/objects/items/reagent_containers/food/sandwich.dm
index 1578d3c6aabd0..d6e90327c2b02 100644
--- a/code/game/objects/items/reagent_containers/food/sandwich.dm
+++ b/code/game/objects/items/reagent_containers/food/sandwich.dm
@@ -3,6 +3,8 @@
/obj/item/reagent_containers/food/snacks/sandwiches/breadslice/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/shard) || istype(I, /obj/item/reagent_containers/food/snacks))
var/obj/item/reagent_containers/food/snacks/sandwiches/csandwich/S = new(loc)
@@ -82,6 +84,8 @@
/obj/item/reagent_containers/food/snacks/sandwiches/csandwich/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
var/sandwich_limit = 4
for(var/obj/item/reagent_containers/food/snacks/sandwiches/breadslice/B in ingredients)
diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm
index 27887aa2022f7..626ec4b121ff3 100644
--- a/code/game/objects/items/reagent_containers/food/snacks.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks.dm
@@ -47,10 +47,10 @@
/obj/item/reagent_containers/food/snacks/attack_self(mob/user as mob)
return
-/obj/item/reagant_containers/food/snacks/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/reagant_containers/food/snacks/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
/obj/item/reagent_containers/food/snacks/attack(mob/M, mob/user, def_zone)
if(!reagents.total_volume) //Shouldn't be needed but it checks to see if it has anything left in it.
@@ -144,6 +144,8 @@
/obj/item/reagent_containers/food/snacks/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/kitchen/utensil)) //todo early return
var/obj/item/tool/kitchen/utensil/U = I
@@ -173,6 +175,8 @@
/obj/item/reagent_containers/food/snacks/sliceable/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(I.sharp == IS_NOT_SHARP_ITEM)
if(I.w_class >= WEIGHT_CLASS_SMALL)
@@ -1164,6 +1168,8 @@
// Flour + egg = dough
/obj/item/reagent_containers/food/snacks/flour/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/food/snacks/egg))
new /obj/item/reagent_containers/food/snacks/dough(src)
@@ -1174,6 +1180,8 @@
// Egg + flour = dough
/obj/item/reagent_containers/food/snacks/egg/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/food/snacks/flour))
new /obj/item/reagent_containers/food/snacks/dough(src)
@@ -1205,6 +1213,8 @@
// Dough + rolling pin = flat dough
/obj/item/reagent_containers/food/snacks/dough/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/kitchen/rollingpin))
new /obj/item/reagent_containers/food/snacks/sliceable/flatdough(src)
@@ -1243,6 +1253,8 @@
/obj/item/reagent_containers/food/snacks/meat/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/kitchen/knife))
new /obj/item/reagent_containers/food/snacks/rawcutlet(src)
@@ -1282,6 +1294,8 @@
/obj/item/reagent_containers/food/snacks/rawcutlet/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/kitchen/knife))
new /obj/item/reagent_containers/food/snacks/rawmeatball(src)
@@ -1479,12 +1493,12 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/coco = 10)
tastes = list("compressed matter" = 1)
-/obj/item/reagent_containers/food/snacks/wrapped/barcardine
- name = "Barcardine Bars"
+/obj/item/reagent_containers/food/snacks/wrapped/barcaridine
+ name = "Barcaridine Bars"
desc = "A bar of chocolate, it smells like the medical bay. \"Chocolate always helps the pain go away.\""
icon_state = "barcardine"
- wrapper = /obj/item/trash/barcardine
- list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/coco = 2, /datum/reagent/medicine/tramadol = 1, /datum/reagent/medicine/tramadol = 1)
+ wrapper = /obj/item/trash/barcaridine
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/coco = 2, /datum/reagent/medicine/tramadol = 2)
tastes = list ("cough syrup" = 1)
/obj/item/reagent_containers/food/snacks/wrapped/berrybar
@@ -1498,7 +1512,8 @@
/datum/reagent/medicine/tramadol = 10,
/datum/reagent/medicine/bicaridine = 10,
/datum/reagent/medicine/kelotane = 10,
- /datum/reagent/medicine/tricordrazine = 10,)
+ /datum/reagent/medicine/tricordrazine = 10,
+ )
tastes = list("delicious processed berries" = 1)
bitesize = 9
@@ -1562,7 +1577,7 @@
icon = 'icons/obj/items/lollipop.dmi'
icon_state = "lollipop_stick"
item_state = "lollipop_stick"
- flags_equip_slot = ITEM_SLOT_MASK
+ equip_slot_flags = ITEM_SLOT_MASK
w_class = WEIGHT_CLASS_TINY
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 4)
tastes = list("candy" = 1)
diff --git a/code/game/objects/items/reagent_containers/food/snacks/grown.dm b/code/game/objects/items/reagent_containers/food/snacks/grown.dm
index f5286f2881d8f..95ffd212116cd 100644
--- a/code/game/objects/items/reagent_containers/food/snacks/grown.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks/grown.dm
@@ -82,6 +82,8 @@
/obj/item/reagent_containers/food/snacks/grown/potato/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iscablecoil(I))
var/obj/item/stack/cable_coil/C = I
@@ -246,6 +248,8 @@
/obj/item/reagent_containers/food/snacks/grown/pumpkin/attackby(obj/item/I, mob/user, param)
. = ..()
+ if(.)
+ return
if(I.sharp == IS_SHARP_ITEM_ACCURATE || I.sharp == IS_SHARP_ITEM_BIG)
to_chat(user, span_notice("You carve a face into [src]!"))
diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm
index d3eca61d7cb04..4fc8598173621 100644
--- a/code/game/objects/items/reagent_containers/glass.dm
+++ b/code/game/objects/items/reagent_containers/glass.dm
@@ -107,6 +107,8 @@
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen) || istype(I, /obj/item/flashlight/pen))
var/tmp_label = stripped_input(user, "Enter a label for [name]", "Label", label_text)
@@ -151,28 +153,35 @@
return
update_icon()
-/obj/item/reagent_containers/glass/beaker/update_icon()
- overlays.Cut()
+/obj/item/reagent_containers/glass/beaker/update_overlays()
+ . = ..()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
var/percent = round((reagents.total_volume / volume) * 100)
switch(percent)
- if(0 to 9) filling.icon_state = "[icon_state]-10"
- if(10 to 24) filling.icon_state = "[icon_state]10"
- if(25 to 49) filling.icon_state = "[icon_state]25"
- if(50 to 74) filling.icon_state = "[icon_state]50"
- if(75 to 79) filling.icon_state = "[icon_state]75"
- if(80 to 90) filling.icon_state = "[icon_state]80"
- if(91 to INFINITY) filling.icon_state = "[icon_state]100"
+ if(0 to 9)
+ filling.icon_state = "[icon_state]-10"
+ if(10 to 24)
+ filling.icon_state = "[icon_state]10"
+ if(25 to 49)
+ filling.icon_state = "[icon_state]25"
+ if(50 to 74)
+ filling.icon_state = "[icon_state]50"
+ if(75 to 79)
+ filling.icon_state = "[icon_state]75"
+ if(80 to 90)
+ filling.icon_state = "[icon_state]80"
+ if(91 to INFINITY)
+ filling.icon_state = "[icon_state]100"
filling.color = mix_color_from_reagents(reagents.reagent_list)
- overlays += filling
+ . += filling
if(!is_open_container())
var/image/lid = image(icon, src, "lid_[initial(icon_state)]")
- overlays += lid
+ . += lid
/obj/item/reagent_containers/glass/beaker/large
name = "large beaker"
@@ -250,6 +259,8 @@
/obj/item/reagent_containers/glass/bucket/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/mop))
if(reagents.total_volume < 1)
@@ -260,12 +271,12 @@
to_chat(user, span_notice("You wet [I] in [src]."))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
-/obj/item/reagent_containers/glass/bucket/update_icon()
- overlays.Cut()
+/obj/item/reagent_containers/glass/bucket/update_overlays()
+ . = ..()
if(!is_open_container())
var/image/lid = image(icon, src, "lid_[initial(icon_state)]")
- overlays += lid
+ . += lid
/obj/item/reagent_containers/glass/bucket/janibucket
name = "janitorial bucket"
@@ -276,14 +287,17 @@
update_icon()
-/obj/item/reagent_containers/glass/bucket/janibucket/update_icon()
- ..()
+/obj/item/reagent_containers/glass/bucket/janibucket/update_icon_state()
+ . = ..()
if(reagents.total_volume)
var/percent = round((reagents.total_volume / volume) * 100)
switch(percent)
- if(0 to 9) icon_state = "janibucket"
- if(10 to 65) icon_state = "janibucket_half"
- if(66 to INFINITY) icon_state = "janibucket_full"
+ if(0 to 9)
+ icon_state = "janibucket"
+ if(10 to 65)
+ icon_state = "janibucket_half"
+ if(66 to INFINITY)
+ icon_state = "janibucket_full"
else
icon_state = "janibucket"
diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm
index c85f4415119b1..2e241ee381472 100644
--- a/code/game/objects/items/reagent_containers/glass/bottle.dm
+++ b/code/game/objects/items/reagent_containers/glass/bottle.dm
@@ -34,28 +34,35 @@
if(!icon_state)
icon_state = "bottle-[rand(1, 5)]"
-/obj/item/reagent_containers/glass/bottle/update_icon()
- overlays.Cut()
+/obj/item/reagent_containers/glass/bottle/update_overlays()
+ . = ..()
if(reagents.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4")) //only for those who have reagentfillings icons
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
var/percent = round((reagents.total_volume / volume) * 100)
switch(percent)
- if(0 to 9) filling.icon_state = "[icon_state]--10"
- if(10 to 24) filling.icon_state = "[icon_state]-10"
- if(25 to 49) filling.icon_state = "[icon_state]-25"
- if(50 to 74) filling.icon_state = "[icon_state]-50"
- if(75 to 79) filling.icon_state = "[icon_state]-75"
- if(80 to 90) filling.icon_state = "[icon_state]-80"
- if(91 to INFINITY) filling.icon_state = "[icon_state]-100"
+ if(0 to 9)
+ filling.icon_state = "[icon_state]--10"
+ if(10 to 24)
+ filling.icon_state = "[icon_state]-10"
+ if(25 to 49)
+ filling.icon_state = "[icon_state]-25"
+ if(50 to 74)
+ filling.icon_state = "[icon_state]-50"
+ if(75 to 79)
+ filling.icon_state = "[icon_state]-75"
+ if(80 to 90)
+ filling.icon_state = "[icon_state]-80"
+ if(91 to INFINITY)
+ filling.icon_state = "[icon_state]-100"
filling.color = mix_color_from_reagents(reagents.reagent_list)
- overlays += filling
+ . += filling
if (!is_open_container())
var/image/lid = image(icon, src, "lid_bottle")
- overlays += lid
+ . += lid
/obj/item/reagent_containers/glass/bottle/empty //Because the parent has RNG icon_state
icon_state = "bottle-1" //Same one when you make a bottle in the chem master
@@ -245,6 +252,6 @@
/obj/item/reagent_containers/glass/bottle/doctor_delight
name = "\improper Doctor's Delight bottle"
- desc = "A small bottle. Contains Doctor's Delight."
+ desc = "A small bottle. Contains Doctor's Delight - functions similar to tricordrazine, but is weaker and makes the patient hungry."
icon_state = "bottle3"
list_reagents = list(/datum/reagent/consumable/drink/doctor_delight = 60)
diff --git a/code/game/objects/items/reagent_containers/hypospray.dm b/code/game/objects/items/reagent_containers/hypospray.dm
index 55b8431ca479c..8ca2e249240a3 100644
--- a/code/game/objects/items/reagent_containers/hypospray.dm
+++ b/code/game/objects/items/reagent_containers/hypospray.dm
@@ -12,22 +12,18 @@
possible_transfer_amounts = list(1, 3, 5, 10, 15, 20, 30)
volume = 60
init_reagent_flags = OPENCONTAINER
- flags_equip_slot = ITEM_SLOT_BELT
- flags_item = NOBLUDGEON
+ equip_slot_flags = ITEM_SLOT_BELT
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
+ interaction_flags = INTERACT_OBJ_UI
var/skilllock = 1
var/inject_mode = HYPOSPRAY_INJECT_MODE_INJECT
var/core_name = "hypospray"
+ ///If we add a custom label, our name becomes "[core_name] ([label])"
var/label = null
/// Small description appearing as an overlay
var/description_overlay = ""
-/obj/item/reagent_containers/hypospray/advanced
- name = "Advanced hypospray"
- desc = "The hypospray is a sterile, air-needle reusable autoinjector for rapid administration of drugs to patients with customizable dosages. Comes complete with an internal reagent analyzer, digital labeler and 2 letter tagger. Handy."
- core_name = "hypospray"
-
-
/obj/item/reagent_containers/hypospray/proc/empty(mob/user)
if(tgui_alert(user, "Are you sure you want to empty [src]?", "Flush [src]:", list("Yes", "No")) != "Yes")
return
@@ -70,6 +66,11 @@
if(!reagents.total_volume)
balloon_alert(user, "Hypospray is Empty.")
return
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if((C.species.species_flags & NO_CHEM_METABOLIZATION) || (C.species.species_flags & IS_SYNTHETIC))
+ C.balloon_alert(user, "Can't inject (robot)")
+ return
if(!A.is_injectable() && !ismob(A))
A.balloon_alert(user, "Can't fill.")
return
@@ -205,119 +206,110 @@
desc.maptext_width = 16
. += desc
-/obj/item/reagent_containers/hypospray/advanced
- icon_state = "hypo"
- init_reagent_flags = REFILLABLE|DRAINABLE
- liquifier = TRUE
+/obj/item/reagent_containers/hypospray/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Hypospray", name)
+ ui.open()
+
+/obj/item/reagent_containers/hypospray/ui_data(mob/user)
+ var/list/data = list()
+ data["IsAdvanced"] = liquifier
+ data["InjectMode"] = inject_mode
+ data["CurrentLabel"] = label
+ data["CurrentTag"] = description_overlay
+ data["TransferAmount"] = amount_per_transfer_from_this
-/obj/item/reagent_containers/hypospray/open_ui(mob/user)
- var/dat = {"
- Activate Autolabeler
- Current Label: [label]
-
- Activate Tagger
- Current Tag: [description_overlay]
-
- Toggle Mode:
- Current Mode: [inject_mode ? "Inject" : "Draw"]
-
- Set Transfer Amount:
- Current Transfer Amount [amount_per_transfer_from_this]
-
- Empty Hypospray:
- "}
-
- var/datum/browser/popup = new(user, "hypospray")
- popup.set_content(dat)
- popup.open()
-
-
-/obj/item/reagent_containers/hypospray/advanced/open_ui(mob/user)
- var/dat = {"
- Activate Autolabeler
- Current Label: [label]
-
- Activate Tagger
- Current Tag: [description_overlay]
-
- Toggle Mode:
- Current Mode: [inject_mode ? "Inject" : "Draw"]
-
- Set Transfer Amount:
- Current Transfer Amount: [amount_per_transfer_from_this]
-
- Display Reagent Content:
-
-
- Empty Hypospray:
- "}
-
- var/datum/browser/popup = new(user, "hypospray")
- popup.set_content(dat)
- popup.open()
-
-
-/obj/item/reagent_containers/hypospray/Topic(href, href_list)
+ return data
+
+/obj/item/reagent_containers/hypospray/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- if(href_list["inject_mode"])
- if(inject_mode)
- to_chat(usr, span_notice("[src] has been set to draw mode. It will now drain reagents."))
-
- else
- to_chat(usr, span_notice("[src] has been set to inject mode. It will now inject reagents."))
- inject_mode = !inject_mode
- update_icon()
-
- else if(href_list["autolabeler"])
- var/mob/user = usr
- var/str = copytext(reject_bad_text(input(user,"Hypospray label text?", "Set label", "")), 1, MAX_NAME_LEN)
- if(!length(str))
- user.balloon_alert(user, "Invalid text.")
- return
- balloon_alert(user, "Labeled \"[str]\".")
- name = "[core_name] ([str])"
- label = str
-
- else if(href_list["overlayer"])
- var/mob/user = usr
- var/str = copytext(reject_bad_text(input(user,"Hypospray tag text?", "Set tag", "")), 1, MAX_NAME_HYPO)
- if(!length(str))
- user.balloon_alert(user, "Invalid text.")
- return
- user.balloon_alert(user, "You tag [src] as \"[str]\".")
- description_overlay = str
- update_icon()
+ switch(action)
+ if("ActivateAutolabeler")
+ var/mob/user = usr
+ var/str = copytext(reject_bad_text(input(user,"Hypospray label text?", "Set label", "")), 1, MAX_NAME_LEN)
+ if(!length(str))
+ user.balloon_alert(user, "Invalid text.")
+ return
+ balloon_alert(user, "Labeled \"[str]\".")
+ name = "[core_name] ([str])"
+ label = str
+
+ if("ActivateTagger")
+ var/mob/user = usr
+ var/str = copytext(reject_bad_text(input(user,"Hypospray tag text?", "Set tag", "")), 1, MAX_NAME_HYPO)
+ if(!length(str))
+ user.balloon_alert(user, "Invalid text.")
+ return
+ user.balloon_alert(user, "You tag [src] as \"[str]\".")
+ description_overlay = str
+ update_icon()
+
+ if("ToggleMode")
+ if(inject_mode)
+ to_chat(usr, span_notice("[src] has been set to draw mode. It will now drain reagents."))
- else if(href_list["set_transfer"])
- var/N = tgui_input_list(usr, "Amount per transfer from this:", "[src]", possible_transfer_amounts)
- if(!N)
- return
+ else
+ to_chat(usr, span_notice("[src] has been set to inject mode. It will now inject reagents."))
+ inject_mode = !inject_mode
+ update_icon()
- amount_per_transfer_from_this = N
+ if("SetTransferAmount")
+ var/N = tgui_input_list(usr, "Amount per transfer from this:", "[src]", possible_transfer_amounts)
+ if(!N)
+ return
- else if(href_list["flush"])
- empty(usr)
+ amount_per_transfer_from_this = N
- updateUsrDialog()
+ if("EmptyHypospray")
+ empty(usr)
+/obj/item/reagent_containers/hypospray/advanced
+ name = "Advanced hypospray"
+ desc = "The hypospray is a sterile, air-needle reusable autoinjector for rapid administration of drugs to patients with customizable dosages. Comes complete with an internal reagent analyzer, digital labeler and 2 letter tagger. Handy."
+ core_name = "hypospray"
+ icon_state = "hypo"
+ init_reagent_flags = REFILLABLE|DRAINABLE
+ liquifier = TRUE
-/obj/item/reagent_containers/hypospray/advanced/Topic(href, href_list)
+/obj/item/reagent_containers/hypospray/advanced/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- if(href_list["displayreagents"])
+ if(action == "DisplayReagentContent")
to_chat(usr, display_reagents())
+ return TRUE
+/obj/item/reagent_containers/hypospray/advanced/update_icon_state()
+ . = ..()
+ if(!reagents?.total_volume)
+ icon_state = "[initial(icon_state)]_0"
+ return
+ var/percent = round((reagents.total_volume / volume) * 100)
+ switch(percent)
+ if(0 to 9)
+ icon_state = initial(icon_state)
+ if(10 to 24)
+ icon_state = "[initial(icon_state)]_10"
+ if(25 to 49)
+ icon_state = "[initial(icon_state)]_25"
+ if(50 to 64)
+ icon_state = "[initial(icon_state)]_50"
+ if(65 to 79)
+ icon_state = "[initial(icon_state)]_65"
+ if(80 to 90)
+ icon_state = "[initial(icon_state)]_80"
+ if(91 to INFINITY)
+ icon_state = "[initial(icon_state)]_100"
/obj/item/reagent_containers/hypospray/advanced/update_overlays()
. = ..()
- overlays.Cut()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
@@ -327,37 +319,28 @@
filling.icon_state = "[initial(icon_state)]-10"
if(10 to 24)
filling.icon_state = "[initial(icon_state)]10"
- icon_state = "[initial(icon_state)]_10"
if(25 to 49)
filling.icon_state = "[initial(icon_state)]25"
- icon_state = "[initial(icon_state)]_25"
if(50 to 64)
filling.icon_state = "[initial(icon_state)]50"
- icon_state = "[initial(icon_state)]_50"
if(65 to 79)
filling.icon_state = "[initial(icon_state)]65"
- icon_state = "[initial(icon_state)]_65"
if(80 to 90)
filling.icon_state = "[initial(icon_state)]80"
- icon_state = "[initial(icon_state)]_80"
if(91 to INFINITY)
filling.icon_state = "[initial(icon_state)]100"
- icon_state = "[initial(icon_state)]_100"
filling.color = mix_color_from_reagents(reagents.reagent_list)
- overlays += filling
-
- else
- icon_state = "[initial(icon_state)]_0"
+ . += filling
if(ismob(loc))
var/injoverlay
switch(inject_mode)
- if (HYPOSPRAY_INJECT_MODE_DRAW)
+ if(HYPOSPRAY_INJECT_MODE_DRAW)
injoverlay = "draw"
- if (HYPOSPRAY_INJECT_MODE_INJECT)
+ if(HYPOSPRAY_INJECT_MODE_INJECT)
injoverlay = "inject"
- add_overlay(injoverlay)
+ . += injoverlay
/obj/item/reagent_containers/hypospray/advanced/examine(mob/user as mob)
. = ..()
@@ -483,7 +466,7 @@
list_reagents = list(
/datum/reagent/hypervene = 60,
)
- description_overlay = "Ht"
+ description_overlay = "Hy"
/obj/item/reagent_containers/hypospray/advanced/nanoblood
name = "nanoblood hypospray"
diff --git a/code/game/objects/items/reagent_containers/reagent_container.dm b/code/game/objects/items/reagent_containers/reagent_container.dm
index dd13fced78263..7fe1bed0895ca 100644
--- a/code/game/objects/items/reagent_containers/reagent_container.dm
+++ b/code/game/objects/items/reagent_containers/reagent_container.dm
@@ -21,7 +21,6 @@
///Whether we can restock this in a vendor without it having its starting reagents
var/free_refills = TRUE
-
/obj/item/reagent_containers/Initialize(mapload)
. = ..()
create_reagents(volume, init_reagent_flags, list_reagents)
@@ -30,41 +29,27 @@
/obj/item/reagent_containers/attack_hand_alternate(mob/living/user)
. = ..()
+ change_transfer_amount(user)
+
+/obj/item/reagent_containers/attack_self_alternate(mob/living/user)
+ . = ..()
+ change_transfer_amount(user)
+
+///Opens a tgui_input_list and changes the transfer_amount of our container based on our selection
+/obj/item/reagent_containers/proc/change_transfer_amount(mob/living/user)
if(!possible_transfer_amounts)
- return
+ return FALSE
var/result = tgui_input_list(user, "Amount per transfer from this:","[src]", possible_transfer_amounts)
if(result)
amount_per_transfer_from_this = result
-
-/obj/item/reagent_containers/interact(mob/user)
- . = ..()
- if(.)
- return
-
- open_ui(user)
-
-///Opens the relevant UI
-/obj/item/reagent_containers/proc/open_ui(mob/user)
- if(!length(possible_transfer_amounts))
- return
-
- var/N = tgui_input_list(user, "Amount per transfer from this:", "[src]", possible_transfer_amounts)
- if(!N)
- return
-
- amount_per_transfer_from_this = N
+ return TRUE
/obj/item/reagent_containers/verb/set_APTFT()
set name = "Set transfer amount"
set category = "Object"
set src in view(1)
- var/N = tgui_input_list(usr, "Amount per transfer from this:", "[src]", possible_transfer_amounts)
- if(!N)
- return
-
- amount_per_transfer_from_this = N
-
+ change_transfer_amount(usr)
//returns a text listing the reagents (and their volume) in the atom. Used by Attack logs for reagents in pills
/obj/item/reagent_containers/proc/get_reagent_list_text()
diff --git a/code/game/objects/items/reagent_containers/spray.dm b/code/game/objects/items/reagent_containers/spray.dm
index b4436911e92ad..e4b0077838d37 100644
--- a/code/game/objects/items/reagent_containers/spray.dm
+++ b/code/game/objects/items/reagent_containers/spray.dm
@@ -9,8 +9,8 @@
)
item_state = "cleaner"
init_reagent_flags = OPENCONTAINER_NOUNIT
- flags_item = NOBLUDGEON
- flags_equip_slot = ITEM_SLOT_BELT
+ item_flags = NOBLUDGEON
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 3
w_class = WEIGHT_CLASS_SMALL
throw_speed = 2
diff --git a/code/game/objects/items/reagent_containers/syringes.dm b/code/game/objects/items/reagent_containers/syringes.dm
index f919b6c787daa..6b8f32ebec3a0 100644
--- a/code/game/objects/items/reagent_containers/syringes.dm
+++ b/code/game/objects/items/reagent_containers/syringes.dm
@@ -20,7 +20,7 @@
possible_transfer_amounts = null //list(5,10,15)
volume = 15
w_class = WEIGHT_CLASS_TINY
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
sharp = IS_SHARP_ITEM_SIMPLE
var/mode = SYRINGE_DRAW
@@ -185,32 +185,37 @@
update_icon()
-/obj/item/reagent_containers/syringe/update_icon()
+/obj/item/reagent_containers/syringe/update_icon_state()
+ . = ..()
if(mode == SYRINGE_BROKEN)
icon_state = "broken"
- overlays.Cut()
return
+
var/rounded_vol = round(reagents.total_volume,5)
- overlays.Cut()
+ icon_state = "[rounded_vol]"
+ item_state = "syringe_[rounded_vol]"
+
+/obj/item/reagent_containers/syringe/update_overlays()
+ . = ..()
+ if(mode == SYRINGE_BROKEN)
+ return
if(ismob(loc))
var/injoverlay
switch(mode)
- if (SYRINGE_DRAW)
+ if(SYRINGE_DRAW)
injoverlay = "draw"
- if (SYRINGE_INJECT)
+ if(SYRINGE_INJECT)
injoverlay = "inject"
- overlays += injoverlay
- icon_state = "[rounded_vol]"
- item_state = "syringe_[rounded_vol]"
+ . += injoverlay
+ var/rounded_vol = round(reagents.total_volume,5)
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
filling.icon_state = "syringe[rounded_vol]"
filling.color = mix_color_from_reagents(reagents.reagent_list)
- overlays += filling
-
+ . += filling
/obj/item/reagent_containers/syringe/proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index fbe752d120bf8..4fdc489b68000 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -7,8 +7,8 @@
)
item_state = "buildpipe"
icon_state = "blank"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
var/list/part
/obj/item/robot_parts/l_arm
@@ -53,7 +53,7 @@
/obj/item/robot_parts/biotic
name = "biotic limbs"
icon = 'icons/mob/human_races/r_human.dmi'
- flags_atom = NONE
+ atom_flags = NONE
/obj/item/robot_parts/biotic/l_arm
name = "biotic left arm"
diff --git a/code/game/objects/items/scanners.dm b/code/game/objects/items/scanners.dm
index 0adbe90c14a7a..e45da80161c85 100644
--- a/code/game/objects/items/scanners.dm
+++ b/code/game/objects/items/scanners.dm
@@ -16,8 +16,8 @@ REAGENT SCANNER
icon = 'icons/obj/device.dmi'
icon_state = "t-ray0"
var/on = 0
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
item_icons = list(
slot_l_hand_str = 'icons/mob/inhands/equipment/engineering_left.dmi',
@@ -71,8 +71,8 @@ REAGENT SCANNER
)
item_state = "healthanalyzer"
desc = "A hand-held body scanner able to distinguish vital signs of the subject. The front panel is able to provide the basic readout of the subject's status."
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 3
w_class = WEIGHT_CLASS_SMALL
throw_speed = 5
@@ -267,12 +267,13 @@ REAGENT SCANNER
)
damaged_organs += list(current_organ)
data["damaged_organs"] = damaged_organs
-
+ var/ssd = null
if(patient.has_brain() && patient.stat != DEAD && ishuman(patient))
if(!patient.key)
- data["ssd"] = "No soul detected." // they ghosted
+ ssd = "No soul detected." // they ghosted
else if(!patient.client)
- data["ssd"] = "SSD detected." // SSD
+ ssd = "SSD detected." // SSD
+ data["ssd"] = ssd
return data
@@ -286,18 +287,18 @@ REAGENT SCANNER
desc = "Advanced medical gloves, these include a built-in analyzer to quickly scan patients."
icon_state = "medscan_gloves"
item_state = "medscan_gloves"
- flags_equip_slot = ITEM_SLOT_GLOVES
+ equip_slot_flags = ITEM_SLOT_GLOVES
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/clothing/gloves.dmi'
item_state_worn = TRUE
siemens_coefficient = 0.50
blood_sprite_state = "bloodyhands"
- flags_armor_protection = HANDS
- flags_equip_slot = ITEM_SLOT_GLOVES
+ armor_protection_flags = HANDS
+ equip_slot_flags = ITEM_SLOT_GLOVES
attack_verb = "scans"
soft_armor = list(MELEE = 25, BULLET = 15, LASER = 10, ENERGY = 15, BOMB = 15, BIO = 5, FIRE = 15, ACID = 15)
- flags_cold_protection = HANDS
- flags_heat_protection = HANDS
+ cold_protection_flags = HANDS
+ heat_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
@@ -350,8 +351,8 @@ REAGENT SCANNER
icon_state = "atmos"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 5
throw_speed = 4
throw_range = 20
@@ -400,14 +401,13 @@ REAGENT SCANNER
icon_state = "spectrometer"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 5
throw_speed = 4
throw_range = 20
var/details = FALSE
- var/recent_fail = TRUE
/obj/item/mass_spectrometer/Initialize(mapload)
. = ..()
@@ -422,9 +422,6 @@ REAGENT SCANNER
/obj/item/mass_spectrometer/attack_self(mob/user as mob)
if (user.stat)
return
- if (crit_fail)
- to_chat(user, span_warning("This device has critically failed and is no longer functional!"))
- return
if(!reagents.total_volume)
return
var/list/blood_traces
@@ -438,16 +435,7 @@ REAGENT SCANNER
break
var/dat = "Trace Chemicals Found: "
for(var/R in blood_traces)
- if(prob(reliability))
- dat += "\n\t[R][details ? " ([blood_traces[R]] units)" : "" ]"
- recent_fail = FALSE
- else if(recent_fail)
- crit_fail = TRUE
- reagents.clear_reagents()
- to_chat(user, span_warning("Device malfunction occured. Please consult manual for manufacturer contact and warranty."))
- return
- else
- recent_fail = TRUE
+ dat += "\n\t[R][details ? " ([blood_traces[R]] units)" : "" ]"
to_chat(user, "[dat]")
reagents.clear_reagents()
@@ -464,14 +452,13 @@ REAGENT SCANNER
icon_state = "spectrometer"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 5
throw_speed = 4
throw_range = 20
var/details = FALSE
- var/recent_fail = FALSE
/obj/item/reagent_scanner/afterattack(obj/O, mob/user as mob, proximity)
if(!proximity)
@@ -480,24 +467,13 @@ REAGENT SCANNER
return
if(!istype(O))
return
- if (crit_fail)
- to_chat(user, span_warning("This device has critically failed and is no longer functional!"))
- return
if(!O.reagents || !length(O.reagents.reagent_list))
to_chat(user, span_notice("No chemical agents found in [O]"))
return
var/dat = ""
var/one_percent = O.reagents.total_volume / 100
for (var/datum/reagent/R in O.reagents.reagent_list)
- if(prob(reliability))
- dat += "\n \t [span_notice(" [R.name][details ? ": [R.volume / one_percent]%" : ""]")]"
- recent_fail = FALSE
- else if(recent_fail)
- crit_fail = TRUE
- to_chat(user, span_warning("Device malfunction occured. Please consult manual for manufacturer contact and warranty."))
- return
- else
- recent_fail = TRUE
+ dat += "\n \t [span_notice(" [R.name][details ? ": [R.volume / one_percent]%" : ""]")]"
to_chat(user, span_notice("Chemicals found: [dat]"))
/obj/item/reagent_scanner/adv
diff --git a/code/game/objects/items/shards.dm b/code/game/objects/items/shards.dm
index 63b9b2bec1409..92921b3e8ae2b 100644
--- a/code/game/objects/items/shards.dm
+++ b/code/game/objects/items/shards.dm
@@ -16,7 +16,7 @@
)
item_state = "shard-glass"
attack_verb = list("stabbed", "slashed", "sliced", "cut")
- var/source_sheet_type = /obj/item/stack/sheet/glass
+ var/source_sheet_type = /obj/item/stack/sheet/glass/glass
var/shardsize
/obj/item/shard/suicide_act(mob/user)
@@ -52,6 +52,8 @@
/obj/item/shard/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswelder(I))
var/obj/item/tool/weldingtool/WT = I
@@ -106,7 +108,7 @@
if(H.species.species_flags & ROBOTIC_LIMBS || H.species.species_flags & IS_INSULATED)
return
- if(!H.shoes && !(H.wear_suit?.flags_armor_protection & FEET))
+ if(!H.shoes && !(H.wear_suit?.armor_protection_flags & FEET))
INVOKE_ASYNC(src, PROC_REF(pierce_foot), H)
/obj/item/shard/proc/pierce_foot(mob/living/carbon/human/target)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 0a4d9e13477f9..e8896d7639905 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -28,7 +28,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "target_stake"
density = TRUE
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
max_integrity = 15000 //important that what the marines are shooting at doesn't break, we don't make it invulnerable because we still need to plasma cutter it sometimes
soft_armor = list(MELEE = 80, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 120, BIO = 100, FIRE = 100, ACID = 0)
///ungas need to actually hit this
@@ -36,6 +36,8 @@
/obj/structure/target_stake/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/target))
return
var/obj/item/target/targetcushion = I
diff --git a/code/game/objects/items/stacks/barbed_wire.dm b/code/game/objects/items/stacks/barbed_wire.dm
index 147f877a19b83..d02df54cc31ed 100644
--- a/code/game/objects/items/stacks/barbed_wire.dm
+++ b/code/game/objects/items/stacks/barbed_wire.dm
@@ -4,7 +4,7 @@
desc = "A spiky length of wire."
icon = 'icons/Marine/marine-items.dmi'
icon_state = "barbed_wire"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
singular_name = "length"
w_class = WEIGHT_CLASS_SMALL
force = 0
@@ -29,6 +29,8 @@
/obj/item/stack/barbed_wire/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/stack/rods))
return
diff --git a/code/game/objects/items/stacks/catwalk.dm b/code/game/objects/items/stacks/catwalk.dm
index 1ad00da269d96..4f0b5f8f543be 100644
--- a/code/game/objects/items/stacks/catwalk.dm
+++ b/code/game/objects/items/stacks/catwalk.dm
@@ -9,5 +9,5 @@
throwforce = 8
throw_speed = 3
throw_range = 6
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
max_amount = 60
diff --git a/code/game/objects/items/stacks/flags.dm b/code/game/objects/items/stacks/flags.dm
index 897b9aa943ab3..565626bfe3cc9 100644
--- a/code/game/objects/items/stacks/flags.dm
+++ b/code/game/objects/items/stacks/flags.dm
@@ -31,6 +31,8 @@
/obj/item/stack/flag/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(upright && istype(I, type))
return attack_hand(user)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 44d5863abcb4f..97f0dd6bc97af 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -181,28 +181,10 @@
/obj/item/stack/medical/heal_pack/advanced
dir = NORTH
- flags_atom = DIRLOCK
+ atom_flags = DIRLOCK
skill_level_needed = SKILL_MEDICAL_PRACTICED
unskilled_delay = SKILL_TASK_EASY
-/* //RUTGMC edit - turning off unused proc
-/obj/item/stack/medical/heal_pack/advanced/update_icon_state()
- if(max_amount < 1 || amount > max_amount)
- return
- var/percentage = round(amount / max_amount) * 100
- switch(percentage)
- if(1 to 20)
- setDir(SOUTH)
- if(21 to 40)
- setDir(EAST)
- if(41 to 60)
- setDir(SOUTHEAST)
- if(61 to 80)
- setDir(WEST)
- if(81 to INFINITY)
- setDir(NORTH)
-*/
-
/obj/item/stack/medical/heal_pack/advanced/bruise_pack
name = "advanced trauma kit"
singular_name = "advanced trauma kit"
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index e58b980c2ce17..f9506ec160417 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -18,7 +18,7 @@
var/datum/limb/S = H.get_limb(user.zone_selected)
if(H.species.species_flags & IS_SYNTHETIC)
- H.blood_volume = BLOOD_VOLUME_NORMAL
+ H.set_blood_volume(BLOOD_VOLUME_NORMAL)
if(S.surgery_open_stage == 0)
if (S && (S.limb_status & LIMB_ROBOT))
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 13d889e577293..153a5aab8c8c1 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -3,7 +3,7 @@
desc = "Some rods. Can be used for building, or something."
singular_name = "metal rod"
icon_state = "rods"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_NORMAL
force = 9
throwforce = 15
@@ -14,7 +14,9 @@
/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob)
- ..()
+ . = ..()
+ if(.)
+ return
if(istype(W, /obj/item/stack/barbed_wire)) // making razorwire obstacles
var/obj/item/stack/barbed_wire/B = W
@@ -46,8 +48,6 @@
if (!R && replace)
user.put_in_hands(new_item)
return
- ..()
-
/obj/item/stack/rods/attack_self(mob/user as mob)
diff --git a/code/game/objects/items/stacks/sandbags.dm b/code/game/objects/items/stacks/sandbags.dm
index 9408d2360f9f2..cada5cca97479 100644
--- a/code/game/objects/items/stacks/sandbags.dm
+++ b/code/game/objects/items/stacks/sandbags.dm
@@ -22,6 +22,8 @@
/obj/item/stack/sandbags_empty/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/shovel))
var/obj/item/tool/shovel/ET = I
@@ -86,5 +88,5 @@
/obj/item/stack/sandbags/attack_self(mob/living/user)
. = ..()
- var/building_time = LERP(2 SECONDS, 1 SECONDS, user.skills.getPercent(SKILL_CONSTRUCTION, SKILL_ENGINEER_MASTER))
+ var/building_time = LERP(2 SECONDS, 1 SECONDS, user.skills.getPercent(SKILL_CONSTRUCTION, SKILL_ENGINEER_EXPERT))
create_object(user, new/datum/stack_recipe("sandbag barricade", /obj/structure/barricade/sandbags, 5, time = building_time, max_per_turf = STACK_RECIPE_ONE_DIRECTIONAL_PER_TILE, on_floor = TRUE), 1)
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 3dbd6282c5bbf..112f298f23c9f 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -15,7 +15,6 @@
singular_name = "glass sheet"
icon_state = "sheet-glass"
item_state = "sheet-glass"
- merge_type = /obj/item/stack/sheet/glass
var/created_window = /obj/structure/window
var/reinforced_type = /obj/item/stack/sheet/glass/reinforced
var/is_reinforced = FALSE
@@ -58,6 +57,8 @@ GLOBAL_LIST_INIT(glass_radial_images, list(
/obj/item/stack/sheet/glass/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(is_reinforced)
return
@@ -74,8 +75,9 @@ GLOBAL_LIST_INIT(glass_radial_images, list(
V.use(1)
if(!src && !RG)
user.put_in_hands(RG)
-
-/obj/item/stack/sheet/glass/large_stack
+/obj/item/stack/sheet/glass/glass //this exists because otherwise glass can be merger into any ofthe other glass types.
+ merge_type = /obj/item/stack/sheet/glass/glass
+/obj/item/stack/sheet/glass/glass/large_stack
amount = 50
@@ -88,6 +90,7 @@ GLOBAL_LIST_INIT(glass_radial_images, list(
singular_name = "reinforced glass sheet"
icon_state = "sheet-rglass"
item_state = "sheet-rglass"
+ merge_type = /obj/item/stack/sheet/glass/reinforced
created_window = /obj/structure/window/reinforced
is_reinforced = TRUE
@@ -101,9 +104,11 @@ GLOBAL_LIST_INIT(glass_radial_images, list(
desc = "Phoron glass is a silicate-phoron alloy turned into a non-crystalline solid. It is transparent just like glass, even if visibly tainted pink, and very resistant to damage and heat."
singular_name = "phoron glass sheet"
icon_state = "sheet-phoronglass"
+ merge_type = /obj/item/stack/sheet/glass/phoronglass
created_window = /obj/structure/window/phoronbasic
reinforced_type = /obj/item/stack/sheet/glass/phoronrglass
+
/*
* Reinforced phoron glass sheets
*/
@@ -112,5 +117,6 @@ GLOBAL_LIST_INIT(glass_radial_images, list(
desc = "Reinforced phoron glass is made out of squares of silicate-phoron alloy glass layered on a metallic rod matrice. It is insanely resistant to both physical shock and heat."
singular_name = "reinforced phoron glass sheet"
icon_state = "sheet-phoronrglass"
+ merge_type = /obj/item/stack/sheet/glass/phoronrglass
created_window = /obj/structure/window/phoronreinforced
is_reinforced = TRUE
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 7baaa36b7a4ee..b7279d03f79d9 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -88,6 +88,8 @@
//Step one - dehairing.
/obj/item/stack/sheet/animalhide/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(I.sharp)
user.visible_message(span_notice(" \the [user] starts cutting hair off \the [src]"), span_notice(" You start cutting the hair off \the [src]"), "You hear the sound of a knife rubbing against flesh")
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index a338918e27f91..6c0896d6f3d40 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -32,21 +32,21 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
new/datum/stack_recipe("reinforced table parts", /obj/item/frame/table/reinforced, 2), \
new/datum/stack_recipe("rack parts", /obj/item/frame/rack, 1), \
new/datum/stack_recipe_list("airlock assemblies", list( \
- new/datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
- new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \
+ new/datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
+ new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 5 SECONDS, max_per_turf = STACK_RECIPE_ONE_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_EXPERT), \
), 4), \
null, \
))
@@ -66,9 +66,9 @@ GLOBAL_LIST_INIT(metal_radial_images, list(
singular_name = "metal sheet"
icon_state = "sheet-metal"
item_state = "sheet-metal"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
throwforce = 14
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
merge_type = /obj/item/stack/sheet/metal
number_of_extra_variants = 3
@@ -132,9 +132,9 @@ GLOBAL_LIST_INIT(metal_radial_images, list(
desc = "This sheet is an alloy of iron and phoron."
icon_state = "sheet-plasteel"
item_state = "sheet-plasteel"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
throwforce = 15
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
merge_type = /obj/item/stack/sheet/plasteel
number_of_extra_variants = 3
diff --git a/code/game/objects/items/stacks/snow.dm b/code/game/objects/items/stacks/snow.dm
index 91c1af488d74f..91e29432d2c77 100644
--- a/code/game/objects/items/stacks/snow.dm
+++ b/code/game/objects/items/stacks/snow.dm
@@ -15,6 +15,8 @@
/obj/item/stack/snow/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/tool/shovel))
return
@@ -61,7 +63,8 @@
return
var/turf/open/T = target
if(T.get_dirt_type() == DIRT_TYPE_SNOW)
- if(T.slayer >= 3)
+ var/turf/open/floor/plating/ground/snow/snowy_turf = T
+ if(snowy_turf.slayer >= 3)
to_chat(user, "This ground is already full of snow.")
return
if(amount < 5)
@@ -70,11 +73,12 @@
to_chat(user, "You start putting some snow back on the ground.")
if(!do_after(user, 15, IGNORE_HELD_ITEM, target, BUSY_ICON_BUILD))
return
- if(T.slayer >= 3)
+ if(snowy_turf.slayer >= 3)
return
to_chat(user, "You put a new snow layer on the ground.")
- T.slayer += 1
- T.update_icon(TRUE, FALSE)
+ snowy_turf.slayer += 1
+ snowy_turf.update_appearance()
+ snowy_turf.update_sides()
use(5)
/obj/item/stack/snow/attack_self(mob/user)
@@ -93,7 +97,7 @@
//Using same safeties as other constructions
for(var/obj/O in user.loc) //Objects, we don't care about mobs. Turfs are checked elsewhere
if(O.density)
- if(O.flags_atom & ON_BORDER)
+ if(O.atom_flags & ON_BORDER)
if(O.dir == user.dir)
to_chat(user, span_warning("There is already \a [O.name] in this direction!"))
return
@@ -109,7 +113,7 @@
return
for(var/obj/O in user.loc) //Objects, we don't care about mobs. Turfs are checked elsewhere
if(O.density)
- if(!(O.flags_atom & ON_BORDER) || O.dir == user.dir)
+ if(!(O.atom_flags & ON_BORDER) || O.dir == user.dir)
return
var/obj/structure/barricade/snow/SB = new(user.loc, user.dir)
user.visible_message(span_notice("[user] assembles a snow barricade."),
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index a6363a127de57..4a38cb9ec68fd 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -56,6 +56,7 @@
/obj/item/stack/update_icon_state()
+ . = ..()
if(!number_of_extra_variants)
return
var/ratio = round((amount * (number_of_extra_variants + 1)) / max_amount)
@@ -271,7 +272,7 @@
continue
if(!AM.density)
continue
- if(AM.flags_atom & ON_BORDER && AM.dir != user.dir)
+ if(AM.atom_flags & ON_BORDER && AM.dir != user.dir)
if(istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(!W.is_full_window())
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 1c23e9e576337..f5d8d0c4d83e6 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -32,7 +32,7 @@
throwforce = 8
throw_speed = 3
throw_range = 6
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
turf_type = /turf/open/floor
///Creates plating, used for space turfs only
@@ -87,6 +87,8 @@
/obj/item/stack/tile/light/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/crowbar))
new /obj/item/stack/sheet/metal(user.loc)
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index cd6a0f5a815a6..227e446ef74ea 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -19,7 +19,7 @@
"Ratcher Combat Robot" = 'icons/mob/species/robot/backpack.dmi',
)
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK //ERROOOOO
+ equip_slot_flags = ITEM_SLOT_BACK //ERROOOOO
max_w_class = WEIGHT_CLASS_NORMAL
storage_slots = null
max_storage_space = 24
@@ -66,28 +66,11 @@
max_w_class = WEIGHT_CLASS_BULKY
max_storage_space = 28
-/obj/item/storage/backpack/holding/proc/failcheck(mob/user)
- if (prob(reliability))
- return TRUE //No failure
- if (prob(reliability))
- to_chat(user, span_warning("The Bluespace portal resists your attempt to add another item."))
- else
- to_chat(user, span_warning("The Bluespace generator malfunctions!"))
- for (var/obj/O in src.contents) //it broke, delete what was in it
- qdel(O)
- crit_fail = 1
- icon_state = "brokenpack"
-
/obj/item/storage/backpack/holding/attackby(obj/item/I, mob/user, params)
- if(crit_fail)
- to_chat(user, span_warning("The Bluespace generator isn't working."))
-
- else if(istype(I, /obj/item/storage/backpack/holding) && !I.crit_fail)
- to_chat(user, span_warning("The Bluespace interfaces of the two devices conflict and malfunction."))
- qdel(I)
-
- else
+ if(!istype(I, /obj/item/storage/backpack/holding))
return ..()
+ to_chat(user, span_warning("The Bluespace interfaces of the two devices conflict and malfunction."))
+ qdel(I)
/obj/item/storage/backpack/santabag
name = "Santa's Gift Bag"
@@ -314,6 +297,7 @@
. += span_warning("Its defibrillator recharge unit does not have a power cell installed!")
/obj/item/storage/backpack/marine/corpsman/update_icon_state()
+ . = ..()
icon_state = icon_skin
if(cell?.charge >= 0)
switch(PERCENT(cell.charge/cell.maxcharge))
@@ -329,13 +313,18 @@
icon_state += "_0"
/obj/item/storage/backpack/marine/corpsman/MouseDrop_T(obj/item/W, mob/living/user) //Dragging the defib/power cell onto the backpack will trigger its special functionality.
+ var/obj/item/defibrillator/defib
if(istype(W, /obj/item/defibrillator))
+ defib = W
+ else if(istype(W, /obj/item/clothing/gloves/defibrillator))
+ var/obj/item/clothing/gloves/defibrillator/defib_gloves = W
+ defib = defib_gloves.internal_defib
+ if(defib)
if(cell)
- var/obj/item/defibrillator/D = W
- var/charge_difference = D.dcell.maxcharge - D.dcell.charge
+ var/charge_difference = defib.dcell.maxcharge - defib.dcell.charge
if(charge_difference) //If the defib has less than max charge, recharge it.
use_charge(user, charge_difference) //consume an appropriate amount of charge
- D.dcell.charge += min(charge_difference, cell.charge) //Recharge the defibrillator battery with the lower of the difference between its present and max cap, or the remaining charge
+ defib.dcell.charge += min(charge_difference, cell.charge) //Recharge the defibrillator battery with the lower of the difference between its present and max cap, or the remaining charge
else
to_chat(user, span_warning("This defibrillator is already at maximum charge!"))
else
@@ -358,14 +347,14 @@
/obj/item/storage/backpack/marine/tech
name = "\improper TGMC technician backpack"
- desc = "The standard-issue backpack worn by TGMC technicians. Specially equipped to hold sentry gun and M56D emplacement parts."
+ desc = "The standard-issue backpack worn by TGMC technicians. Specially equipped to hold sentry gun and HSG-102 emplacement parts."
icon_state = "marinepackt"
item_state = "marinepackt"
bypass_w_limit = list(
/obj/item/weapon/gun/sentry/big_sentry,
/obj/item/weapon/gun/sentry/mini,
- /obj/item/weapon/gun/tl102,
- /obj/item/ammo_magazine/tl102,
+ /obj/item/weapon/gun/hsg_102,
+ /obj/item/ammo_magazine/hsg_102,
/obj/item/ammo_magazine/sentry,
/obj/item/ammo_magazine/minisentry,
/obj/item/mortal_shell,
@@ -405,7 +394,7 @@
item_state = "marinesatt"
bypass_w_limit = list(
/obj/item/weapon/gun/sentry/mini,
- /obj/item/ammo_magazine/tl102,
+ /obj/item/ammo_magazine/hsg_102,
/obj/item/ammo_magazine/sentry,
/obj/item/ammo_magazine/minisentry,
/obj/item/mortal_shell,
@@ -462,8 +451,6 @@
var/stealth_delay = null
actions_types = list(/datum/action/item_action/toggle)
-/obj/item/storage/backpack/marine/satchel/scout_cloak/scout
-
/obj/item/storage/backpack/marine/satchel/scout_cloak/Destroy()
camo_off()
return ..()
@@ -474,13 +461,48 @@
STOP_PROCESSING(SSprocessing, src)
return ..()
-/obj/item/storage/backpack/marine/satchel/scout_cloak/verb/use_camouflage()
- set name = "Toggle M68 Thermal Camouflage"
- set desc = "Activate your cloak's camouflage."
- set category = "Scout"
-
+/obj/item/storage/backpack/marine/satchel/scout_cloak/attack_self(mob/user)
+ . = ..()
camouflage()
+/obj/item/storage/backpack/marine/satchel/scout_cloak/process()
+ if(!wearer)
+ camo_off()
+ return
+ else if(wearer.stat != CONSCIOUS)
+ camo_off(wearer)
+ return
+
+ stealth_delay = world.time - SCOUT_CLOAK_STEALTH_DELAY
+ if(camo_last_shimmer > stealth_delay) //Shimmer after taking aggressive actions; no energy regeneration
+ wearer.alpha = shimmer_alpha //50% invisible
+ else if(camo_last_stealth > stealth_delay ) //We have an initial reprieve at max invisibility allowing us to reposition; no energy recovery during this time
+ wearer.alpha = SCOUT_CLOAK_STILL_ALPHA
+ return
+ //Stationary stealth
+ else if( wearer.last_move_intent < stealth_delay ) //If we're standing still and haven't shimmed in the past 3 seconds we become almost completely invisible
+ wearer.alpha = SCOUT_CLOAK_STILL_ALPHA //95% invisible
+ camo_adjust_energy(wearer, SCOUT_CLOAK_ACTIVE_RECOVERY)
+
+///Handles the wearer moving with the cloak active
+/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/handle_movement(mob/living/carbon/human/source, atom/old_loc, movement_dir, forced, list/old_locs)
+ SIGNAL_HANDLER
+ if(!camo_active)
+ return
+ if(camo_last_shimmer > world.time - SCOUT_CLOAK_STEALTH_DELAY) //Shimmer after taking aggressive actions
+ source.alpha = SCOUT_CLOAK_RUN_ALPHA
+ camo_adjust_energy(src, SCOUT_CLOAK_RUN_DRAIN)
+ else if(camo_last_stealth > world.time - SCOUT_CLOAK_STEALTH_DELAY) //We have an initial reprieve at max invisibility allowing us to reposition, albeit at a high drain rate
+ source.alpha = SCOUT_CLOAK_STILL_ALPHA
+ camo_adjust_energy(src, SCOUT_CLOAK_RUN_DRAIN)
+ else if(source.m_intent == MOVE_INTENT_WALK)
+ source.alpha = SCOUT_CLOAK_WALK_ALPHA
+ camo_adjust_energy(src, SCOUT_CLOAK_WALK_DRAIN)
+ else
+ source.alpha = SCOUT_CLOAK_RUN_ALPHA
+ camo_adjust_energy(src, SCOUT_CLOAK_RUN_DRAIN)
+
+///Activates the cloak
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/camouflage()
if (usr.incapacitated(TRUE))
return
@@ -497,6 +519,7 @@
camo_off(usr)
return
+ //other sources of cloaking
if(SEND_SIGNAL(M, COMSIG_MOB_ENABLE_STEALTH) & STEALTH_ALREADY_ACTIVE)
to_chat(M, span_warning("You are already cloaked!"))
return FALSE
@@ -509,7 +532,6 @@
camo_last_stealth = world.time
wearer = M
- RegisterSignal(wearer, COMSIG_MOB_ENABLE_STEALTH, PROC_REF(on_other_activate))
M.visible_message("[M] fades into thin air!", span_notice("You activate your cloak's camouflage."))
playsound(M.loc,'sound/effects/cloak_scout_on.ogg', 15, 1)
@@ -537,11 +559,11 @@
COMSIG_MOB_ITEM_ATTACK), PROC_REF(action_taken))
START_PROCESSING(SSprocessing, src)
- wearer.cloaking = TRUE
+ RegisterSignal(wearer, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement))
return TRUE
-
+///Sig handler for other sources of cloaking
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/on_other_activate()
SIGNAL_HANDLER
return STEALTH_ALREADY_ACTIVE
@@ -592,9 +614,10 @@
COMSIG_MOB_GUN_AUTOFIRED,
COMSIG_MOB_ATTACHMENT_FIRED,
COMSIG_MOB_THROW,
- COMSIG_MOB_ITEM_ATTACK))
+ COMSIG_MOB_ITEM_ATTACK,
+ COMSIG_MOVABLE_MOVED,
+ ))
STOP_PROCESSING(SSprocessing, src)
- wearer.cloaking = FALSE
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/process_camo_cooldown(mob/living/user, cooldown)
if(!camo_cooldown_timer)
@@ -630,11 +653,6 @@
return FALSE
return TRUE
-
-/obj/item/storage/backpack/marine/satchel/scout_cloak/attack_self(mob/user)
- . = ..()
- camouflage()
-
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/camo_adjust_energy(mob/user, drain = SCOUT_CLOAK_WALK_DRAIN)
camo_energy = clamp(camo_energy - drain,0,initial(camo_energy))
@@ -658,34 +676,16 @@
camo_last_shimmer = world.time //Reduces transparency to 50%
wearer.alpha = max(wearer.alpha,shimmer_alpha)
-/obj/item/storage/backpack/marine/satchel/scout_cloak/process()
- if(!wearer)
- camo_off()
- return
- else if(wearer.stat != CONSCIOUS)
- camo_off(wearer)
- return
-
- stealth_delay = world.time - SCOUT_CLOAK_STEALTH_DELAY
- if(camo_last_shimmer > stealth_delay) //Shimmer after taking aggressive actions; no energy regeneration
- wearer.alpha = shimmer_alpha //50% invisible
- else if(camo_last_stealth > stealth_delay ) //We have an initial reprieve at max invisibility allowing us to reposition; no energy recovery during this time
- wearer.alpha = SCOUT_CLOAK_STILL_ALPHA
- return
- //Stationary stealth
- else if( wearer.last_move_intent < stealth_delay ) //If we're standing still and haven't shimmed in the past 3 seconds we become almost completely invisible
- wearer.alpha = SCOUT_CLOAK_STILL_ALPHA //95% invisible
- camo_adjust_energy(wearer, SCOUT_CLOAK_ACTIVE_RECOVERY)
-
/obj/item/storage/backpack/marine/satchel/scout_cloak/sniper
name = "\improper M68-B Thermal Cloak"
icon_state = "smock"
desc = "The M68-B thermal cloak is a variant custom-purposed for snipers, allowing for faster, superior, stationary concealment at the expense of mobile concealment. It is designed to be paired with the lightweight M3 recon battle armor. Serves as a satchel."
shimmer_alpha = SCOUT_CLOAK_RUN_ALPHA * 0.5 //Half the normal shimmer transparency.
-/obj/item/storage/backpack/marine/satchel/scout_cloak/sniper/equippedsniper/Initialize(mapload)
- . = ..()
- new /obj/item/detpack(src)
+/obj/item/storage/backpack/marine/satchel/scout_cloak/sniper/handle_movement(mob/living/carbon/human/source, atom/old_loc, movement_dir, forced, list/old_locs)
+ if(!camo_active)
+ return
+ source.alpha = initial(source.alpha) //Sniper variant has *no* mobility stealth, but no drain on movement either
/obj/item/storage/backpack/marine/satchel/scout_cloak/sniper/process()
if(!wearer)
@@ -707,7 +707,7 @@
/obj/item/storage/backpack/marine/engineerpack
name = "\improper TGMC technician welderpack"
- desc = "A specialized backpack worn by TGMC technicians. It carries a fueltank for quick welder refueling and use,"
+ desc = "A specialized backpack worn by TGMC technicians. It carries a fueltank for quick welder refueling."
icon_state = "engineerpack"
item_state = "engineerpack"
var/max_fuel = 260
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 70b204e0bcb93..6dda103b35603 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -20,7 +20,7 @@
allow_quick_empty = 1
display_contents_with_number = 0 // UNStABLE AS FuCK, turn on when it stops crashing clients
use_to_pickup = 1
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
// -----------------------------
// Trash bag
@@ -39,6 +39,7 @@
cant_hold = list(/obj/item/disk/nuclear)
/obj/item/storage/bag/trash/update_icon_state()
+ . = ..()
if(length(contents) == 0)
icon_state = "trashbag0"
else if(length(contents) < 12)
@@ -75,7 +76,7 @@
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
storage_slots = 50
max_storage_space = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index b73abf8ee40e7..019fdcaa04894 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -7,7 +7,7 @@
icon_state = "utilitybelt"
item_state = "utility"
item_state_worn = TRUE
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
attack_verb = list("whipped", "lashed", "disciplined")
w_class = WEIGHT_CLASS_BULKY
allow_drawing_method = TRUE
@@ -177,6 +177,30 @@
new /obj/item/reagent_containers/hypospray/autoinjector/dexalinplus(src)
new /obj/item/healthanalyzer(src)
+/obj/item/storage/belt/lifesaver/beginner/Initialize(mapload, ...) //For beginner vendor
+ . = ..()
+ new /obj/item/storage/pill_bottle/bicaridine(src)
+ new /obj/item/storage/pill_bottle/meralyne(src)
+ new /obj/item/storage/pill_bottle/kelotane(src)
+ new /obj/item/storage/pill_bottle/dermaline(src)
+ new /obj/item/storage/pill_bottle/tramadol(src)
+ new /obj/item/storage/pill_bottle/tricordrazine(src)
+ new /obj/item/storage/pill_bottle/dylovene(src)
+ new /obj/item/storage/pill_bottle/inaprovaline(src)
+ new /obj/item/storage/pill_bottle/isotonic(src)
+ new /obj/item/storage/pill_bottle/spaceacillin(src)
+ new /obj/item/storage/pill_bottle/alkysine(src)
+ new /obj/item/storage/pill_bottle/imidazoline(src)
+ new /obj/item/storage/pill_bottle/quickclot(src)
+ new /obj/item/storage/pill_bottle/hypervene(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/healthanalyzer(src)
+
/obj/item/storage/belt/lifesaver/full/upp
name ="\improper Type 41 pattern lifesaver bag"
desc = "The Type 41 load rig is the standard-issue LBE of the UPP military. This configuration mounts a satchel filled with a range of injectors and light medical supplies, common among medics and partisans."
@@ -325,15 +349,15 @@
new /obj/item/storage/pill_bottle/tricordrazine(src)
new /obj/item/storage/pill_bottle/dylovene(src)
new /obj/item/storage/pill_bottle/inaprovaline(src)
- new /obj/item/storage/pill_bottle/dexalin(src)
+ new /obj/item/storage/pill_bottle/isotonic(src)
new /obj/item/storage/pill_bottle/spaceacillin(src)
new /obj/item/storage/pill_bottle/alkysine(src)
new /obj/item/storage/pill_bottle/imidazoline(src)
new /obj/item/storage/pill_bottle/quickclot(src)
new /obj/item/storage/pill_bottle/hypervene(src)
+ new /obj/item/bodybag/cryobag(src)
new /obj/item/defibrillator(src)
new /obj/item/tool/research/excavation_tool(src)
- new /obj/item/tool/research/xeno_analyzer(src)
new /obj/item/healthanalyzer(src)
/obj/item/storage/belt/hypospraybelt
@@ -352,7 +376,7 @@
/obj/item/storage/syringe_case,
)
-/obj/item/storage/belt/hypospraybelt/Initialize(mapload) //The belt, with all it's magic inside!
+/obj/item/storage/belt/hypospraybelt/full/Initialize(mapload) //The belt, with all it's magic inside!
. = ..()
new /obj/item/reagent_containers/glass/bottle/bicaridine(src)
new /obj/item/reagent_containers/glass/bottle/kelotane(src)
@@ -372,6 +396,31 @@
new /obj/item/reagent_containers/hypospray/advanced/hypervene(src)
new /obj/item/healthanalyzer(src)
+/obj/item/storage/belt/hypospraybelt/beginner/Initialize(mapload)
+ . = ..()
+ new /obj/item/reagent_containers/glass/bottle/bicaridine(src)
+ new /obj/item/reagent_containers/glass/bottle/kelotane(src)
+ new /obj/item/reagent_containers/glass/bottle/tramadol(src)
+ new /obj/item/reagent_containers/glass/bottle/tricordrazine(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/bicaridine(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/kelotane(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/tramadol(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/tricordrazine(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/combatmix(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/dylovene(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/inaprovaline(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/isotonic(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/spaceacillin(src)
+ new /obj/item/reagent_containers/hypospray/advanced/big/quickclot(src)
+ new /obj/item/reagent_containers/hypospray/advanced/imialky(src)
+ new /obj/item/reagent_containers/hypospray/advanced/hypervene(src)
+ new /obj/item/reagent_containers/hypospray/advanced/peridaxonplus(src)
+ new /obj/item/reagent_containers/hypospray/advanced/quickclotplus(src)
+ new /obj/item/storage/syringe_case/meraderm(src)
+ new /obj/item/storage/syringe_case/meraderm(src)
+ new /obj/item/reagent_containers/hypospray/advanced/meraderm(src)
+
+
/obj/item/storage/belt/security
name = "\improper M276 pattern security rig"
desc = "The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. This configuration is commonly seen among TGMC Military Police and peacekeepers, though it can hold some light munitions."
@@ -718,12 +767,11 @@
/obj/item/storage/belt/shotgun/attackby(obj/item/I, mob/user, params)
-
if(istype(I, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/M = I
- if(CHECK_BITFIELD(M.flags_magazine, MAGAZINE_HANDFUL))
+ if(CHECK_BITFIELD(M.magazine_flags, MAGAZINE_HANDFUL))
return ..()
- if(M.flags_magazine & MAGAZINE_REFILLABLE)
+ if(M.magazine_flags & MAGAZINE_REFILLABLE)
if(!M.current_rounds)
to_chat(user, span_warning("[M] is empty."))
return
@@ -862,47 +910,44 @@
/obj/item/storage/belt/shotgun/martini
name = "martini henry ammo belt"
desc = "A belt good enough for holding all your .577/400 ball rounds."
- icon_state = ".557_belt"
+ icon_state = "martini_belt"
storage_slots = 12
max_storage_space = 24
-
+ sprite_slots = 6
draw_mode = 1
- flags_atom = DIRLOCK
+ atom_flags = DIRLOCK
/obj/item/storage/belt/shotgun/martini/Initialize(mapload, ...)
. = ..()
update_icon()
-/obj/item/storage/belt/shotgun/martini/update_icon()
- if(!length(contents))
- icon_state = initial(icon_state) + "_e"
- return
- icon_state = initial(icon_state)
+/obj/item/storage/belt/shotgun/martini/attackby(obj/item/I, mob/user, params)
+ if(!istype(I, /obj/item/ammo_magazine))
+ update_icon()
+ return ..()
- var/holding = round((length(contents) + 1) / 2)
- setDir(holding + round(holding/3))
+ var/obj/item/ammo_magazine/new_mag = I
+ if(new_mag.caliber != CALIBER_557)
+ to_chat(user, span_notice("[src] can only be filled with .557/440 ball rifle rounds."))
+ return
-/obj/item/storage/belt/shotgun/martini/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/ammo_magazine))
- var/obj/item/ammo_magazine/new_mag = I
- if(new_mag.caliber != CALIBER_557)
- to_chat(user, span_notice("[src] can only be filled with .557/440 ball rifle rounds."))
- return
- . = ..()
- update_icon()
+ return ..()
/obj/item/storage/belt/shotgun/martini/attack_hand(mob/living/user)
- if (loc != user)
+ if(!ishuman(user))
+ return
+
+ if(loc != user)
. = ..()
for(var/mob/M in content_watchers)
close(M)
- if(!draw_mode || !ishuman(user) && !length(contents))
- open(user)
-
if(!length(contents))
- return
+ open(user) //Empty belt? Open the inventory
+
+ if(!draw_mode)
+ return ..() //No draw mode so we just click like normal
var/obj/item/I = contents[length(contents)]
if(!istype(I, /obj/item/ammo_magazine/handful))
@@ -917,7 +962,6 @@
existing_handful.create_handful(user, 1)
update_icon()
-
/obj/item/storage/belt/knifepouch
name="\improper M276 pattern knife rig"
desc="The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. This version is specially designed with six holsters to store throwing knives. Not commonly issued, but kept in service."
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 1aafb5ffc2fa0..81807542d8cf4 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -235,7 +235,7 @@
icon_state = "matchbox"
item_state = "zippo"
w_class = WEIGHT_CLASS_TINY
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/tool/match
spawn_number = 14
@@ -349,6 +349,7 @@
spawn_number = 5
/obj/item/storage/box/explosive_mines/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(!length(contents))
icon_state += "_e"
@@ -381,7 +382,8 @@
spawn_type = /obj/item/explosive/grenade/flare
spawn_number = 14
-/obj/item/storage/box/m94/update_icon()
+/obj/item/storage/box/m94/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(!length(contents))
icon_state += "_e"
@@ -445,7 +447,8 @@
if(. && !length(contents) && !gc_destroyed)
qdel(src)
-/obj/item/storage/box/MRE/update_icon()
+/obj/item/storage/box/MRE/update_icon_state()
+ . = ..()
if(!isopened)
isopened = 1
icon_state += "opened"
@@ -668,7 +671,7 @@
/obj/item/ammo_magazine/smg,
/obj/item/ammo_magazine/sniper,
/obj/item/ammo_magazine/standard_gpmg,
- /obj/item/ammo_magazine/tl102,
+ /obj/item/ammo_magazine/hsg_102,
/obj/item/ammo_magazine/standard_lmg,
/obj/item/ammo_magazine/standard_mmg,
/obj/item/ammo_magazine/heavymachinegun,
@@ -1148,9 +1151,9 @@
/obj/item/storage/box/visual/grenade/phosphorus
name = "\improper M40 HPDP grenade box"
desc = "A secure box holding 15 M40 HPDP white phosphorous grenades. War crimes for the entire platoon!"
- storage_slots = 15
+ storage_slots = 25
max_storage_space = 30
- spawn_number = 15
+ spawn_number = 25
spawn_type = /obj/item/explosive/grenade/phosphorus
closed_overlay = "grenade_box_overlay_phosphorus"
@@ -1182,13 +1185,20 @@
spawn_type = /obj/item/explosive/grenade/smokebomb/drain
closed_overlay = "grenade_box_overlay_drain"
+/obj/item/storage/box/visual/grenade/antigas
+ name = "\improper M40-AG grenade box"
+ desc = "A secure box holding 25 M40-AG gas grenades. Quickly clears out hostile smoke."
+ spawn_number = 25
+ spawn_type = /obj/item/explosive/grenade/smokebomb/antigas
+ closed_overlay = "grenade_box_overlay_antigas"
+
/obj/item/storage/box/visual/grenade/razorburn
name = "razorburn grenade box"
desc = "A secure box holding 15 razor burn grenades. Used for quick flank coverage."
- storage_slots = 15
+ storage_slots = 25
max_storage_space = 30
- spawn_number = 15
- spawn_type = /obj/item/explosive/grenade/chem_grenade/razorburn_smol
+ spawn_number = 25
+ spawn_type = /obj/item/explosive/grenade/chem_grenade/razorburn_small
closed_overlay = "grenade_box_overlay_razorburn"
/obj/item/storage/box/visual/grenade/razorburn_large
@@ -1206,6 +1216,20 @@
spawn_type = /obj/item/explosive/grenade/chem_grenade/teargas
closed_overlay = "grenade_box_overlay_teargas"
+/obj/item/storage/box/visual/grenade/lasburster
+ name = "\improper M80 lasburster grenade box"
+ desc = "A secure box holding 25 M80 lasburster grenades."
+ spawn_number = 25
+ spawn_type = /obj/item/explosive/grenade/bullet/laser
+ closed_overlay = "grenade_box_overlay_grenade_lasburster"
+
+/obj/item/storage/box/visual/grenade/hefa
+ name = "\improper M25 HEFA grenade box"
+ desc = "A secure box holding 25 M25 high explosive fragmentation grenades. Keep very far away from extreme heat and flame."
+ spawn_number = 25
+ spawn_type = /obj/item/explosive/grenade/bullet/hefa
+ closed_overlay = "grenade_box_overlay_grenade_hefa2"
+
/obj/item/storage/box/visual/grenade/training
name = "\improper M07 training grenade box"
desc = "A secure box holding 25 M07 training grenades. Harmless and reusable."
diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm
index 78b42fa622799..ba9e334cd2650 100644
--- a/code/game/objects/items/storage/briefcase.dm
+++ b/code/game/objects/items/storage/briefcase.dm
@@ -3,7 +3,7 @@
desc = "It's made of AUTHENTIC faux-leather and has a price-tag still attached. Its owner must be a real professional."
icon_state = "briefcase"
item_state = "briefcase"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 8
throw_speed = 1
throw_range = 4
@@ -16,7 +16,7 @@
desc = "A well made, expensive looking case, made to fit an R-76 Magnum and its accessories. For the discerning gun owner."
icon_state = "magnum_case"
item_state = "briefcase"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 12
throw_speed = 1
throw_range = 4
diff --git a/code/game/objects/items/storage/dispenser.dm b/code/game/objects/items/storage/dispenser.dm
index 44a70023e47d4..481c060426308 100644
--- a/code/game/objects/items/storage/dispenser.dm
+++ b/code/game/objects/items/storage/dispenser.dm
@@ -113,7 +113,7 @@
desc = "The TX-9000 also known as \"Dispenser\" is a machine capable of holding a big amount of items on it, while also healing nearby synthetics. Your allies will often ask you to lay down one of those."
icon = 'icons/obj/items/storage/storage_48.dmi'
icon_state = "dispenser"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
max_storage_space = 48
max_integrity = 250
@@ -122,12 +122,12 @@
AddComponent(/datum/component/deployable_item, /obj/machinery/deployable/dispenser, 0, 0)
/obj/item/storage/backpack/dispenser/attack_hand(mob/living/user)
- if(!CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(!CHECK_BITFIELD(item_flags, IS_DEPLOYED))
return ..()
open(user)
/obj/item/storage/backpack/dispenser/open(mob/user)
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYED))
return ..()
/obj/item/storage/backpack/dispenser/attempt_draw_object(mob/living/user)
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index 02d96ac9f7e01..5e6fb8ca22eea 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -29,6 +29,7 @@
new spawn_type(src)
/obj/item/storage/fancy/update_icon_state()
+ . = ..()
icon_state = "[icon_type]box[length(contents)]"
/obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location, mob/user)
@@ -75,7 +76,7 @@
item_state = "candlebox5"
storage_slots = 5
throwforce = 2
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/tool/candle
spawn_number = 5
@@ -111,6 +112,8 @@
/obj/item/storage/fancy/crayons/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
@@ -131,7 +134,7 @@
item_state = "cigpacket"
w_class = WEIGHT_CLASS_TINY
throwforce = 2
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
max_storage_space = 18
storage_slots = 18
can_hold = list(
@@ -146,6 +149,7 @@
new /obj/item/clothing/mask/cigarette(src)
/obj/item/storage/fancy/cigarettes/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][length(contents)]"
/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
@@ -170,7 +174,7 @@
item_state = "chempacketbox"
w_class = WEIGHT_CLASS_TINY
throwforce = 2
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
max_storage_space = 18
storage_slots = 18
can_hold = list(
@@ -192,10 +196,10 @@
// for(var/i in 1 to 5)
// new /obj/item/clothing/mask/cigarette/antitox(src)
- new /obj/item/clothing/mask/cigarette/emergency(src)
new /obj/item/tool/lighter(src)
/obj/item/storage/fancy/chemrettes/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][length(contents)]"
/obj/item/storage/fancy/cigarettes/dromedaryco
@@ -231,13 +235,14 @@
w_class = WEIGHT_CLASS_TINY
throwforce = 2
w_class = WEIGHT_CLASS_SMALL
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
storage_slots = 7
spawn_type = /obj/item/clothing/mask/cigarette/cigar
spawn_number = 7
icon_type = "cigar"
/obj/item/storage/fancy/cigar/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][length(contents)]"
@@ -287,8 +292,9 @@
. = ..()
update_icon()
-/obj/item/storage/lockbox/vials/update_icon(itemremoved = 0)
- icon_state = "vialbox[length(contents)-itemremoved]"
+/obj/item/storage/lockbox/vials/update_icon_state()
+ . = ..()
+ icon_state = "vialbox[length(contents)]"
/obj/item/storage/lockbox/vials/update_overlays()
. = ..()
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index 0afa7561e1ca3..19a3522bf950d 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -36,7 +36,8 @@
fill_firstaid_kit()
-/obj/item/storage/firstaid/update_icon()
+/obj/item/storage/firstaid/update_icon_state()
+ . = ..()
if(!length(contents))
icon_state = icon_state += "_empty"
else
@@ -351,6 +352,7 @@
pill_type_to_fill = /obj/item/reagent_containers/pill/kelotane
greyscale_colors = "#CC9900#FFFFFF"
description_overlay = "Ke"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/dermaline
name = "dermaline pill bottle"
@@ -366,6 +368,7 @@
pill_type_to_fill = /obj/item/reagent_containers/pill/dylovene
greyscale_colors = "#669900#ffffff"
description_overlay = "Dy"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/isotonic
name = "isotonic pill bottle"
@@ -373,6 +376,7 @@
pill_type_to_fill = /obj/item/reagent_containers/pill/isotonic
greyscale_colors = "#5c0e0e#ffffff"
description_overlay = "Is"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/inaprovaline
name = "inaprovaline pill bottle"
@@ -388,6 +392,7 @@
pill_type_to_fill = /obj/item/reagent_containers/pill/tramadol
greyscale_colors = "#8a8686#ffffff"
description_overlay = "Ta"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/paracetamol
name = "paracetamol pill bottle"
@@ -397,6 +402,7 @@
greyscale_config = /datum/greyscale_config/pillbottlebox
greyscale_colors = "#f8f4f8#ffffff"
description_overlay = "Pa"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/spaceacillin
name = "spaceacillin pill bottle"
@@ -412,6 +418,7 @@
pill_type_to_fill = /obj/item/reagent_containers/pill/bicaridine
greyscale_colors = "#DA0000#ffffff"
description_overlay = "Bi"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/meralyne
name = "meralyne pill bottle"
@@ -480,6 +487,7 @@
greyscale_colors = "#f8f8f8#ffffff"
greyscale_config = /datum/greyscale_config/pillbottleround
description_overlay = "Ti"
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/happy
name = "happy pill bottle"
diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm
index b6d76933f91f5..af1ad9d6756e0 100644
--- a/code/game/objects/items/storage/holsters.dm
+++ b/code/game/objects/items/storage/holsters.dm
@@ -7,7 +7,7 @@
max_w_class = WEIGHT_CLASS_BULKY ///normally the special item will be larger than what should fit. Child items will have lower limits and an override
storage_slots = 1
max_storage_space = 4
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
draw_mode = 1
allow_drawing_method = TRUE
storage_type_limits = list(/obj/item/weapon = 1)
@@ -70,6 +70,7 @@
return ..()
/obj/item/storage/holster/update_icon_state()
+ . = ..()
if(holstered_item)
icon_state = initial(icon_state) + "_full"
else
@@ -78,7 +79,7 @@
/obj/item/storage/holster/update_icon()
. = ..()
- if(flags_item & HAS_UNDERLAY)
+ if(item_flags & HAS_UNDERLAY)
update_underlays()
var/mob/user = loc
if(!istype(user))
@@ -91,10 +92,7 @@
///Adds or removes underlay sprites, checks holstered_item to see which underlay to add
/obj/item/storage/holster/proc/update_underlays()
if(holstered_item && !holstered_item_underlay)
- if(holstered_item.greyscale_config && holstered_item.greyscale_colors)
- holstered_item_underlay = image(SSgreyscale.GetColoredIconByType(holstered_item.greyscale_config, holstered_item.greyscale_colors), "belt")
- else
- holstered_item_underlay = image(icon, src, holstered_item.icon_state)
+ holstered_item_underlay = image(icon, src, holstered_item.icon_state)
underlays += holstered_item_underlay
else
underlays -= holstered_item_underlay
@@ -157,9 +155,9 @@
/obj/item/weapon/gun/launcher/rocket/recoillessrifle,
/obj/item/weapon/gun/launcher/rocket/recoillessrifle/low_impact,
)
- bypass_w_limit = list(/obj/item/weapon/gun/launcher/rocket/recoillessrifle,)
+ bypass_w_limit = list(/obj/item/weapon/gun/launcher/rocket/recoillessrifle)
///only one RR per bag
- storage_type_limits = list(/obj/item/weapon/gun/launcher/rocket/recoillessrifle = 1,)
+ storage_type_limits = list(/obj/item/weapon/gun/launcher/rocket/recoillessrifle = 1)
can_hold = list(
/obj/item/ammo_magazine/rocket,
/obj/item/weapon/gun/launcher/rocket/recoillessrifle,
@@ -250,9 +248,9 @@
storage_slots = null
max_storage_space = 30
access_delay = 0
- holsterable_allowed = list(/obj/item/mortar_kit,)
- bypass_w_limit = list(/obj/item/mortar_kit,)
- storage_type_limits = list(/obj/item/mortar_kit = 1,)
+ holsterable_allowed = list(/obj/item/mortar_kit)
+ bypass_w_limit = list(/obj/item/mortar_kit)
+ storage_type_limits = list(/obj/item/mortar_kit = 1)
can_hold = list(
/obj/item/mortal_shell/he,
/obj/item/mortal_shell/incendiary,
@@ -285,9 +283,9 @@
max_storage_space = 16
max_w_class = WEIGHT_CLASS_NORMAL
access_delay = 0
- holsterable_allowed = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer,)
- bypass_w_limit = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer,)
- storage_type_limits = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer = 1,)
+ holsterable_allowed = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer)
+ bypass_w_limit = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer)
+ storage_type_limits = list(/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer = 1)
///The internal fuel tank
var/obj/item/ammo_magazine/flamer_tank/internal/tank
@@ -368,7 +366,7 @@
name = "\improper H5 pattern M2132 machete scabbard"
desc = "A large leather scabbard used to carry a M2132 machete. It can be strapped to the back, waist or armor."
icon_state = "machete_holster"
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_BACK
holsterable_allowed = list(
/obj/item/weapon/claymore/mercsword/machete,
/obj/item/weapon/claymore/harvester,
@@ -397,7 +395,7 @@
icon_state = "katana_holster"
force = 12
attack_verb = list("bludgeoned", "struck", "cracked")
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_BACK
holsterable_allowed = list(/obj/item/weapon/katana)
can_hold = list(/obj/item/weapon/katana)
@@ -410,7 +408,7 @@
name = "\improper officer sword scabbard"
desc = "A large leather scabbard used to carry a sword. Appears to be a reproduction, rather than original. It can be strapped to the waist or armor."
icon_state = "officer_sheath"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
holsterable_allowed = list(/obj/item/weapon/claymore/mercsword/machete/officersword)
can_hold = list(/obj/item/weapon/claymore/mercsword/machete/officersword)
@@ -460,7 +458,7 @@
desc = "The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. This version is designed for the M25 SMG, and features a larger frame to support the gun. Due to its unorthodox design, it isn't a very common sight, and is only specially issued."
icon_state = "m25_holster"
icon = 'icons/obj/clothing/belts.dmi'
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
holsterable_allowed = list(
/obj/item/weapon/gun/smg/m25,
/obj/item/weapon/gun/smg/m25/holstered,
@@ -477,7 +475,7 @@
desc = "The M276 is the standard load-bearing equipment of the TGMC. It consists of a modular belt with various clips. This version is designed for the MP-19 SMG, and features a larger frame to support the gun. Due to its unorthodox design, it isn't a very common sight, and is only specially issued."
icon_state = "t19_holster"
icon = 'icons/obj/clothing/belts.dmi'
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
holsterable_allowed = list(
/obj/item/weapon/gun/smg/standard_machinepistol,
/obj/item/weapon/gun/smg/standard_machinepistol/compact,
@@ -501,7 +499,7 @@
/obj/item/storage/holster/flarepouch
name = "flare pouch"
desc = "A pouch designed to hold flares and a single flaregun. Refillable with a M94 flare pack."
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
storage_slots = 28
max_storage_space = 28
icon = 'icons/Marine/marine-pouches.dmi'
@@ -535,6 +533,32 @@
for(var/i in 1 to (storage_slots-flare_gun.w_class))
new /obj/item/explosive/grenade/flare(src)
+
+/obj/item/storage/holster/icc_mg
+ name = "\improper ML-41 scabbard (10x26mm)"
+ desc = "A backpack holster allowing the storage of any a ML-41 Assault Machinegun, also carries ammo for the other portion of the system."
+ icon_state = "icc_bagmg"
+ storage_slots = 5
+ max_storage_space = 16
+ holsterable_allowed = list(
+ /obj/item/weapon/gun/rifle/icc_mg,
+ )
+ can_hold = list(
+ /obj/item/weapon/gun/rifle/icc_mg,
+ /obj/item/ammo_magazine/icc_mg/packet,
+ )
+
+/obj/item/storage/holster/icc_mg/full/Initialize(mapload)
+ . = ..()
+ var/obj/item/weapon/gun/new_gun = new /obj/item/weapon/gun/rifle/icc_mg(src)
+ new /obj/item/ammo_magazine/icc_mg/packet(src)
+ new /obj/item/ammo_magazine/icc_mg/packet(src)
+ new /obj/item/ammo_magazine/icc_mg/packet(src)
+ new /obj/item/ammo_magazine/icc_mg/packet(src)
+ INVOKE_ASYNC(src, PROC_REF(handle_item_insertion), new_gun)
+
+
+
////////////////////////////// GUN BELTS /////////////////////////////////////
/obj/item/storage/holster/belt
@@ -542,8 +566,8 @@
desc = "A belt-holster assembly that allows one to hold a pistol and two magazines."
icon = 'icons/obj/clothing/belts.dmi'
icon_state = "m4a3_holster"
- flags_equip_slot = ITEM_SLOT_BELT
- flags_item = HAS_UNDERLAY
+ equip_slot_flags = ITEM_SLOT_BELT
+ item_flags = HAS_UNDERLAY
use_sound = null
storage_slots = 7
max_storage_space = 15
@@ -554,6 +578,7 @@
/obj/item/weapon/gun/pistol,
/obj/item/ammo_magazine/pistol,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol,
+ /obj/item/cell/lasgun/plasma,
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta,
/obj/item/cell/lasgun/lasrifle,
/obj/item/cell/lasgun/volkite/small,
@@ -579,6 +604,7 @@
/obj/item/ammo_magazine/pistol,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol,
/obj/item/cell/lasgun/lasrifle,
+ /obj/item/cell/lasgun/plasma,
)
/obj/item/storage/holster/belt/pistol/m4a3/full/Initialize(mapload)
@@ -658,6 +684,7 @@
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta,
/obj/item/cell/lasgun/lasrifle,
/obj/item/cell/lasgun/volkite/small,
+ /obj/item/cell/lasgun/plasma,
)
/obj/item/storage/holster/belt/pistol/m4a3/som/serpenta/Initialize(mapload, ...)
diff --git a/code/game/objects/items/storage/internal.dm b/code/game/objects/items/storage/internal.dm
index 2604e4522a868..5c38e9afe7ba1 100644
--- a/code/game/objects/items/storage/internal.dm
+++ b/code/game/objects/items/storage/internal.dm
@@ -43,9 +43,6 @@
if(user.lying_angle || user.incapacitated()) //Can't use your inventory when lying
return FALSE
- if(istype(user.loc, /obj/vehicle/multitile/root/cm_armored)) //Stops inventory actions in a mech/tank
- return FALSE
-
if(over_object == user && Adjacent(user)) //This must come before the screen objects only block
open(user)
return FALSE
@@ -122,7 +119,7 @@
close(M)
return TRUE
-/obj/item/storage/internal/Adjacent(atom/neighbor)
+/obj/item/storage/internal/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
return master_item.Adjacent(neighbor)
diff --git a/code/game/objects/items/storage/marine_boxes.dm b/code/game/objects/items/storage/marine_boxes.dm
index 08ef5190e7102..7c73e823ffaa5 100644
--- a/code/game/objects/items/storage/marine_boxes.dm
+++ b/code/game/objects/items/storage/marine_boxes.dm
@@ -6,90 +6,8 @@
foldable = /obj/item/stack/sheet/wood
/obj/item/storage/box/crate/update_icon_state()
- icon_state = length(contents) ? initial(icon_state) : "empty_case"
-
-/obj/item/storage/box/crate/heavy_armor
- name = "\improper B-Series defensive armor crate"
- desc = "A large case containing an experiemental suit of B18 armor for the discerning specialist."
- icon_state = "armor_case"
- w_class = WEIGHT_CLASS_HUGE
- storage_slots = 3
- can_hold = list() //Nada. Once you take the stuff out it doesn't fit back in.
-
-/obj/item/storage/box/crate/heavy_armor/Initialize(mapload, ...)
- . = ..()
- new /obj/item/clothing/gloves/marine/specialist(src)
- new /obj/item/clothing/suit/storage/marine/specialist(src)
- new /obj/item/clothing/head/helmet/marine/specialist(src)
-
-/obj/item/storage/box/crate/grenade_system
- name = "\improper M92 grenade launcher case"
- desc = "A large case containing a heavy-duty multi-shot grenade launcher, the Armat Systems M92. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
- icon_state = "grenade_case"
- w_class = WEIGHT_CLASS_HUGE
- storage_slots = 2
- slowdown = 1
- can_hold = list() //Nada. Once you take the stuff out it doesn't fit back in.
-
-/obj/item/storage/box/crate/grenade_system/Initialize(mapload, ...)
- . = ..()
- new /obj/item/weapon/gun/grenade_launcher/multinade_launcher(src)
- new /obj/item/storage/belt/grenade/b17(src)
-
-/obj/item/storage/box/crate/rocket_system
- name = "\improper M5 RPG crate"
- desc = "A large case containing a heavy-caliber antitank missile launcher and missiles. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
- icon_state = "rocket_case"
- w_class = WEIGHT_CLASS_HUGE
- storage_slots = 6
- slowdown = 1
- can_hold = list() //Nada. Once you take the stuff out it doesn't fit back in.
-
-/obj/item/storage/box/crate/rocket_system/Initialize(mapload, ...)
- . = ..()
- new /obj/item/weapon/gun/launcher/rocket/sadar(src)
- new /obj/item/ammo_magazine/rocket/sadar(src)
- new /obj/item/ammo_magazine/rocket/sadar(src)
- new /obj/item/ammo_magazine/rocket/sadar/ap(src)
- new /obj/item/ammo_magazine/rocket/sadar/ap(src)
- new /obj/item/ammo_magazine/rocket/sadar/wp(src)
-
-/obj/item/storage/box/crate/heavy_grenadier
- name = "\improper Heavy Grenadier case"
- desc = "A large case containing B17 Heavy Armor and a heavy-duty multi-shot grenade launcher, the Armat Systems M92. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
- icon_state = "grenade_case"
- w_class = WEIGHT_CLASS_HUGE
- storage_slots = 6
- slowdown = 1
- can_hold = list() //Nada. Once you take the stuff out it doesn't fit back in.
-
-/obj/item/storage/box/crate/heavy_grenadier/Initialize(mapload, ...)
. = ..()
- new /obj/item/weapon/gun/grenade_launcher/multinade_launcher(src)
- new /obj/item/storage/belt/grenade/b17(src)
- new /obj/item/clothing/suit/storage/marine/B17(src)
- new /obj/item/clothing/head/helmet/marine/grenadier(src)
- new /obj/item/storage/box/visual/grenade/frag(src)
- new /obj/item/storage/box/visual/grenade/frag(src)
- new /obj/item/storage/box/visual/grenade/incendiary(src)
-
-/obj/item/storage/box/crate/heavy_gunner
- name = "\improper Heavy Minigunner case"
- desc = "A large case containing B18 armor, munitions, and a goddamn minigun. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
- icon_state = "rocket_case"
- w_class = WEIGHT_CLASS_HUGE
- storage_slots = 16
- slowdown = 1
- can_hold = list() //Nada. Once you take the stuff out it doesn't fit back in.
-
-/obj/item/storage/box/crate/heavy_gunner/Initialize(mapload, ...)
- . = ..()
- new /obj/item/clothing/gloves/marine/specialist(src)
- new /obj/item/clothing/suit/storage/marine/specialist(src)
- new /obj/item/clothing/head/helmet/marine/specialist(src)
- new /obj/item/weapon/gun/minigun(src)
- new /obj/item/belt_harness/marine(src)
- new /obj/item/ammo_magazine/minigun_powerpack(src)
+ icon_state = length(contents) ? initial(icon_state) : "empty_case"
/obj/item/storage/box/crate/m42c_system
name = "\improper antimaterial scoped rifle system (recon set)"
diff --git a/code/game/objects/items/storage/misc.dm b/code/game/objects/items/storage/misc.dm
index 14dfdedafb711..be83920b3bc0b 100644
--- a/code/game/objects/items/storage/misc.dm
+++ b/code/game/objects/items/storage/misc.dm
@@ -36,18 +36,22 @@
if(!length(contents))
return ..()
-
-/obj/item/storage/donut_box/update_icon()
- overlays.Cut()
+/obj/item/storage/donut_box/update_icon_state()
+ . = ..()
if(!open)
icon_state = "donutbox"
return
icon_state = "donutbox_o"
+
+/obj/item/storage/donut_box/update_overlays()
+ . = ..()
+ if(!open)
+ return
var/i = 0
for(var/obj/item/reagent_containers/food/snacks/donut/D in contents)
i++
var/image/img = image('icons/obj/items/food/donuts.dmi', "[D.overlay_state]-[i]")
- overlays += img
+ . += img
/obj/item/storage/donut_box/empty
icon_state = "donutbox_o"
diff --git a/code/game/objects/items/storage/pill_packets.dm b/code/game/objects/items/storage/pill_packets.dm
index 3219bffe488a3..96246b8beac0b 100644
--- a/code/game/objects/items/storage/pill_packets.dm
+++ b/code/game/objects/items/storage/pill_packets.dm
@@ -15,7 +15,7 @@
var/trash_item = /obj/item/trash/pillpacket
refill_types = null
refill_sound = null
- flags_storage = BYPASS_VENDOR_CHECK
+ storage_flags = BYPASS_VENDOR_CHECK
/obj/item/storage/pill_bottle/packet/remove_from_storage(obj/item/item, atom/new_location, mob/user)
. = ..()
diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm
index 31fc63ee706c6..713d452dac886 100644
--- a/code/game/objects/items/storage/pouch.dm
+++ b/code/game/objects/items/storage/pouch.dm
@@ -4,7 +4,7 @@
icon_state = "small_drop"
w_class = WEIGHT_CLASS_BULKY //does not fit in backpack
max_w_class = WEIGHT_CLASS_SMALL
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
storage_slots = 1
draw_mode = 0
allow_drawing_method = TRUE
@@ -395,11 +395,18 @@
/obj/item/storage/pouch/explosive/razorburn/Initialize(mapload)
. = ..()
- new /obj/item/explosive/grenade/chem_grenade/razorburn_smol(src)
- new /obj/item/explosive/grenade/chem_grenade/razorburn_smol(src)
- new /obj/item/explosive/grenade/chem_grenade/razorburn_smol(src)
+ new /obj/item/explosive/grenade/chem_grenade/razorburn_small(src)
+ new /obj/item/explosive/grenade/chem_grenade/razorburn_small(src)
+ new /obj/item/explosive/grenade/chem_grenade/razorburn_small(src)
new /obj/item/explosive/grenade/chem_grenade/razorburn_large(src)
+/obj/item/storage/pouch/explosive/antigas/Initialize(mapload)
+ . = ..()
+ new /obj/item/explosive/grenade/smokebomb/antigas(src)
+ new /obj/item/explosive/grenade/smokebomb/antigas(src)
+ new /obj/item/explosive/grenade/smokebomb/antigas(src)
+ new /obj/item/explosive/grenade/smokebomb/antigas(src)
+
/obj/item/storage/pouch/explosive/upp
fill_type = /obj/item/explosive/grenade/upp
fill_number = 4
@@ -438,6 +445,15 @@
new /obj/item/explosive/grenade/flashbang/stun(src)
new /obj/item/explosive/grenade/flashbang/stun(src)
+/obj/item/storage/pouch/grenade/standard/Initialize(mapload)
+ . = ..()
+ new /obj/item/explosive/grenade(src)
+ new /obj/item/explosive/grenade(src)
+ new /obj/item/explosive/grenade(src)
+ new /obj/item/explosive/grenade/bullet/laser(src)
+ new /obj/item/explosive/grenade/bullet/laser(src)
+ new /obj/item/explosive/grenade/incendiary(src)
+
/obj/item/storage/pouch/grenade/som
desc = "It can contain grenades. This one looks to be made out of traditional SOM leather."
icon_state = "grenade_som"
@@ -461,6 +477,15 @@
new /obj/item/explosive/grenade/som(src)
new /obj/item/explosive/grenade/som(src)
+/obj/item/storage/pouch/grenade/som/standard/Initialize(mapload)
+ . = ..()
+ new /obj/item/explosive/grenade/som(src)
+ new /obj/item/explosive/grenade/som(src)
+ new /obj/item/explosive/grenade/som(src)
+ new /obj/item/explosive/grenade/som(src)
+ new /obj/item/explosive/grenade/incendiary/som(src)
+ new /obj/item/explosive/grenade/incendiary/som(src)
+
/obj/item/storage/pouch/medkit
name = "medkit pouch"
desc = "A standard use medkit pouch that can contain all kinds of medical supplies and equipment."
@@ -521,7 +546,7 @@
/obj/item/storage/pouch/medical_injectors/firstaid
desc = "Standard marine first-aid injector pouch. Specialized to store only auto-injectors. Contains basic injectors, a stabilizing injector, stimulant injector, and an emergency injector."
-/obj/item/storage/pouch/medical_injectors/firstaid/Initialize(mapload)
+/obj/item/storage/pouch/medical_injectors/firstaid/Initialize(mapload) //used in hvh and erts
. = ..()
new /obj/item/reagent_containers/hypospray/autoinjector/bicaridine (src)
new /obj/item/reagent_containers/hypospray/autoinjector/kelotane (src)
@@ -532,6 +557,17 @@
new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine (src)
new /obj/item/reagent_containers/hypospray/autoinjector/russian_red (src)
+/obj/item/storage/pouch/medical_injectors/standard/Initialize(mapload) //normal access variant available by default to marines
+ . = ..()
+ new /obj/item/reagent_containers/hypospray/autoinjector/bicaridine(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/kelotane(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/tramadol(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/tricordrazine(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/dylovene(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/inaprovaline(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine(src)
+ new /obj/item/reagent_containers/hypospray/autoinjector/synaptizine(src)
+
/obj/item/storage/pouch/medical_injectors/medic/Initialize(mapload) //corpsman autoinjector pouch gets upgraded, but more general chems.
. = ..()
new /obj/item/reagent_containers/hypospray/autoinjector/combat_advanced(src)
@@ -594,7 +630,7 @@
sprite_slots = 3
storage_slots = 3
- can_hold = list(/obj/item/storage/box/combat_lolipop,)
+ can_hold = list(/obj/item/storage/box/combat_lolipop)
/obj/item/storage/pouch/med_lolipops/Initialize(mapload)
. = ..()
@@ -673,7 +709,7 @@
/obj/item/flashlight,
/obj/item/whistle,
/obj/item/binoculars,
- /obj/item/beacon/supply_beacon,
+ /obj/item/supply_beacon,
/obj/item/compass,
/obj/item/deployable_camera,
/obj/item/hud_tablet,
@@ -824,13 +860,12 @@
draw_mode = 0
can_hold = list(/obj/item/ammo_magazine/handful)
-
/obj/item/storage/pouch/shotgun/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/M = I
- if(CHECK_BITFIELD(M.flags_magazine, MAGAZINE_HANDFUL))
+ if(CHECK_BITFIELD(M.magazine_flags, MAGAZINE_HANDFUL))
return ..()
- if(M.flags_magazine & MAGAZINE_REFILLABLE)
+ if(M.magazine_flags & MAGAZINE_REFILLABLE)
if(!M.current_rounds)
to_chat(user, span_warning("[M] is empty."))
return
diff --git a/code/game/objects/items/storage/reagent_pouch.dm b/code/game/objects/items/storage/reagent_pouch.dm
index ebd86f3eb62b9..8e1b7834581dc 100644
--- a/code/game/objects/items/storage/reagent_pouch.dm
+++ b/code/game/objects/items/storage/reagent_pouch.dm
@@ -53,7 +53,7 @@
You can Alt-Click to remove the canister in order to refill it."
can_hold = list(/obj/item/reagent_containers/hypospray)
cant_hold = list(/obj/item/reagent_containers/glass/reagent_canister) //To prevent chat spam when you try to put the container in
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
draw_mode = TRUE
///The internal container of the pouch. Holds the reagent that you use to refill the connected injector
var/obj/item/reagent_containers/glass/reagent_canister/inner
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 0ea8c091f11f7..73e995524ebfd 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -165,7 +165,7 @@
icon_opened = "safe0"
icon_locking = "safeb"
icon_sparking = "safespark"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 8
w_class = WEIGHT_CLASS_GIGANTIC
max_w_class = WEIGHT_CLASS_GIGANTIC
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index fde59f2dd7f2c..c09ac3b44cce9 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -77,7 +77,7 @@
///What sound gets played when the item is tactical refilled
var/refill_sound = null
///Flags for specifically storage items
- var/flags_storage = NONE
+ var/storage_flags = NONE
/obj/item/storage/MouseDrop(obj/over_object as obj)
if(!ishuman(usr))
@@ -86,9 +86,6 @@
if(usr.lying_angle)
return
- if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank
- return
-
if(over_object == usr && Adjacent(usr)) // this must come before the screen objects only block
open(usr)
return
@@ -96,6 +93,9 @@
if(!istype(over_object, /atom/movable/screen))
return ..()
+ if(HAS_TRAIT(src, TRAIT_NODROP))
+ return
+
//Makes sure that the storage is equipped, so that we can't drag it into our hand from miles away.
//There's got to be a better way of doing this.
if(loc != usr || (loc && loc.loc == usr))
@@ -304,9 +304,6 @@
if(usr.incapacitated(TRUE))
return
- if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank
- return
-
var/list/PL = params2list(params)
if(!master)
@@ -346,7 +343,7 @@
sample_object = null
return ..()
-///This proc determins the size of the inventory to be displayed. Please touch it only if you know what you're doing.
+///This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
/obj/item/storage/proc/orient2hud()
var/adjusted_contents = length(contents)
@@ -553,6 +550,8 @@
///This proc is called when you want to place an item into the storage item.
/obj/item/storage/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(length(refill_types))
for(var/typepath in refill_types)
@@ -668,7 +667,7 @@
if(!allow_drawing_method)
verbs -= /obj/item/storage/verb/toggle_draw_mode
- boxes = new
+ boxes = new()
boxes.name = "storage"
boxes.master = src
boxes.icon_state = "block"
@@ -676,21 +675,21 @@
boxes.layer = HUD_LAYER
boxes.plane = HUD_PLANE
- storage_start = new /atom/movable/screen/storage( )
+ storage_start = new /atom/movable/screen/storage()
storage_start.name = "storage"
storage_start.master = src
storage_start.icon_state = "storage_start"
storage_start.screen_loc = "7,7 to 10,8"
storage_start.layer = HUD_LAYER
storage_start.plane = HUD_PLANE
- storage_continue = new /atom/movable/screen/storage( )
+ storage_continue = new /atom/movable/screen/storage()
storage_continue.name = "storage"
storage_continue.master = src
storage_continue.icon_state = "storage_continue"
storage_continue.screen_loc = "7,7 to 10,8"
storage_continue.layer = HUD_LAYER
storage_continue.plane = HUD_PLANE
- storage_end = new /atom/movable/screen/storage( )
+ storage_end = new /atom/movable/screen/storage()
storage_end.name = "storage"
storage_end.master = src
storage_end.icon_state = "storage_end"
@@ -698,20 +697,20 @@
storage_end.layer = HUD_LAYER
storage_end.plane = HUD_PLANE
- stored_start = new /obj //we just need these to hold the icon
+ stored_start = new /obj() //we just need these to hold the icon
stored_start.icon_state = "stored_start"
stored_start.layer = HUD_LAYER
stored_start.plane = HUD_PLANE
- stored_continue = new /obj
+ stored_continue = new /obj()
stored_continue.icon_state = "stored_continue"
stored_continue.layer = HUD_LAYER
stored_continue.plane = HUD_PLANE
- stored_end = new /obj
+ stored_end = new /obj()
stored_end.icon_state = "stored_end"
stored_end.layer = HUD_LAYER
stored_end.plane = HUD_PLANE
- closer = new
+ closer = new()
closer.master = src
/obj/item/storage/Destroy()
@@ -745,7 +744,7 @@
///BubbleWrap - A box can be folded up to make card
/obj/item/storage/attack_self(mob/user)
-
+ . = ..()
//Clicking on itself will empty it, if it has the verb to do that.
if(allow_quick_empty)
@@ -876,6 +875,7 @@
return
/obj/item/storage/update_icon_state()
+ . = ..()
if(!sprite_slots)
icon_state = initial(icon_state)
return
diff --git a/code/game/objects/items/storage/surgical_tray.dm b/code/game/objects/items/storage/surgical_tray.dm
index bed8f1703cf2f..479c322944d77 100644
--- a/code/game/objects/items/storage/surgical_tray.dm
+++ b/code/game/objects/items/storage/surgical_tray.dm
@@ -2,7 +2,7 @@
name = "surgical tray"
desc = "A small metallic tray covered in sterile tarp. Intended to store surgical tools in a neat and clean fashion."
icon_state = "surgical_tray"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_BULKY //Should not fit in backpacks
storage_slots = 12
max_storage_space = 24
@@ -27,6 +27,7 @@
new /obj/item/stack/nanopaste(src)
/obj/item/storage/surgical_tray/update_icon_state()
+ . = ..()
if(!length(contents))
icon_state = "surgical_tray_e"
else
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 6c5aed7a864b0..acab4433f9d26 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -7,7 +7,7 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/toolboxes_right.dmi',
)
item_state = "toolbox_red"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 5
throwforce = 10
throw_speed = 1
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 2e6133e9764e1..ddc70217409b6 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -25,7 +25,7 @@
/obj/item/tool/screwdriver,
/obj/item/tool/stamp,
)
- flags_equip_slot = ITEM_SLOT_ID
+ equip_slot_flags = ITEM_SLOT_ID
var/obj/item/card/id/front_id = null
@@ -46,8 +46,8 @@
name = "[name] ([front_id])"
update_icon()
-/obj/item/storage/wallet/update_icon()
-
+/obj/item/storage/wallet/update_icon_state()
+ . = ..()
if(front_id)
switch(front_id.icon_state)
if("id")
diff --git a/code/game/objects/items/suit_cooling.dm b/code/game/objects/items/suit_cooling.dm
index f43f8aa0c7a80..b1d9ec88562f2 100644
--- a/code/game/objects/items/suit_cooling.dm
+++ b/code/game/objects/items/suit_cooling.dm
@@ -4,8 +4,8 @@
icon = 'icons/obj/device.dmi'
w_class = WEIGHT_CLASS_BULKY
icon_state = "suitcooler0"
- flags_equip_slot = ITEM_SLOT_BACK
- flags_atom = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
+ atom_flags = CONDUCT
force = 5
throwforce = 10
throw_speed = 1
diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm
index 0a4db04a31656..c701130c6dff8 100644
--- a/code/game/objects/items/tanks/tank_types.dm
+++ b/code/game/objects/items/tanks/tank_types.dm
@@ -55,8 +55,8 @@
name = "phoron tank"
desc = "Contains dangerous phoron. Do not inhale. Warning: extremely flammable."
icon_state = "phoron"
- flags_atom = CONDUCT
- flags_equip_slot = NONE //they have no straps!
+ atom_flags = CONDUCT
+ equip_slot_flags = NONE //they have no straps!
@@ -67,8 +67,8 @@
name = "emergency oxygen tank"
desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it."
icon_state = "emergency"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_TINY
force = 4
distribute_pressure = ONE_ATMOSPHERE*O2STANDARD
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 695bf1fbb0375..f17d48924fb09 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -8,8 +8,8 @@
slot_l_hand_str = 'icons/mob/inhands/equipment/tanks_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/equipment/tanks_right.dmi',
)
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BACK
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_NORMAL
var/pressure_full = ONE_ATMOSPHERE*4
@@ -54,6 +54,8 @@
/obj/item/tank/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if((istype(I, /obj/item/tool/analyzer)) && get_dist(user, src) <= 1)
visible_message(span_warning("[user] has used [I] on [icon2html(src, user)] [src]"))
diff --git a/code/game/objects/items/taperecorder.dm b/code/game/objects/items/taperecorder.dm
index ec84e411a1080..6233564f0b3e9 100644
--- a/code/game/objects/items/taperecorder.dm
+++ b/code/game/objects/items/taperecorder.dm
@@ -13,7 +13,7 @@
var/list/storedinfo = list()
var/list/timestamp = list()
var/canprint = 1
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
throwforce = 2
throw_speed = 4
throw_range = 20
diff --git a/code/game/objects/items/tools/extinguisher.dm b/code/game/objects/items/tools/extinguisher.dm
index 6c73dc8baf91b..fc67c43282e3e 100644
--- a/code/game/objects/items/tools/extinguisher.dm
+++ b/code/game/objects/items/tools/extinguisher.dm
@@ -9,7 +9,7 @@
)
item_state = "fire_extinguisher"
hitsound = 'sound/weapons/smash.ogg'
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
throwforce = 10
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 2
diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm
index a06edf3ce0d7c..34b0d38584e0b 100644
--- a/code/game/objects/items/tools/flame_tools.dm
+++ b/code/game/objects/items/tools/flame_tools.dm
@@ -34,14 +34,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/wax = 800
/obj/item/tool/candle/update_icon_state()
- var/i
- if(wax>150)
- i = 1
- else if(wax>80)
- i = 2
+ . = ..()
+ if(wax > 150)
+ icon_state = "candle[1][heat ? "_lit" : ""]"
+ else if(wax > 80)
+ icon_state = "candle[2][heat ? "_lit" : ""]"
else
- i = 3
- icon_state = "candle[i][heat ? "_lit" : ""]"
+ icon_state = "candle[3][heat ? "_lit" : ""]"
/obj/item/tool/candle/Destroy()
if(heat)
@@ -161,7 +160,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
throw_speed = 0.5
item_state = "cigoff"
w_class = WEIGHT_CLASS_TINY
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
light_range = 0.1
light_power = 0.1
light_color = LIGHT_COLOR_ORANGE
@@ -412,7 +411,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/cigarette/bica
name = "strawberry flavored cigarette"
- desc = "Red tipped. Has got a single word stamped on the side: \"(BICARDINE)\"."
+ desc = "Red tipped. Has got a single word stamped on the side: \"(BICARIDINE)\"."
icon_state = "bicacigoff"
item_state = "bicacigoff"
icon_on = "bicacigon"
@@ -562,8 +561,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM
light_color = LIGHT_COLOR_FIRE
w_class = WEIGHT_CLASS_TINY
throwforce = 4
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
attack_verb = list("burnt", "singed")
/obj/item/tool/lighter/zippo
diff --git a/code/game/objects/items/tools/hydro_tools.dm b/code/game/objects/items/tools/hydro_tools.dm
index 626b23a4e5c38..865651d370630 100644
--- a/code/game/objects/items/tools/hydro_tools.dm
+++ b/code/game/objects/items/tools/hydro_tools.dm
@@ -6,8 +6,8 @@
/obj/item/tool/plantspray
icon = 'icons/obj/items/spray.dmi'
item_state = "spray"
- flags_item = NOBLUDGEON
- flags_equip_slot = ITEM_SLOT_BELT
+ item_flags = NOBLUDGEON
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 4
w_class = WEIGHT_CLASS_SMALL
throw_speed = 2
@@ -88,8 +88,8 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "hoe"
item_state = "hoe"
- flags_atom = CONDUCT
- flags_item = NOBLUDGEON
+ atom_flags = CONDUCT
+ item_flags = NOBLUDGEON
force = 5
throwforce = 7
w_class = WEIGHT_CLASS_SMALL
@@ -104,7 +104,7 @@
desc = "A sharp hand hatchet, commonly used to cut things apart, be it timber or other objects. Often found in the hands of woodsmen, scouts, and looters."
icon = 'icons/obj/items/weapons.dmi'
icon_state = "hatchet"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 25
w_class = WEIGHT_CLASS_SMALL
throwforce = 20
@@ -129,8 +129,8 @@
throw_speed = 1
throw_range = 3
w_class = WEIGHT_CLASS_BULKY
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BACK
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
attack_verb = list("chopped", "sliced", "cut", "reaped")
/obj/item/tool/scythe/afterattack(atom/A, mob/user as mob, proximity)
diff --git a/code/game/objects/items/tools/kitchen_tools.dm b/code/game/objects/items/tools/kitchen_tools.dm
index d13bfea7b9b59..5a1f5dcb4e2b9 100644
--- a/code/game/objects/items/tools/kitchen_tools.dm
+++ b/code/game/objects/items/tools/kitchen_tools.dm
@@ -26,7 +26,7 @@
throwforce = 5
throw_speed = 3
throw_range = 5
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
attack_verb = list("attacked", "stabbed", "poked")
sharp = 0
var/loaded //Descriptive string for currently loaded food object.
@@ -60,10 +60,10 @@
else
..()
-/obj/item/tool/kitchen/utensil/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/tool/kitchen/utensil/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
/obj/item/tool/kitchen/utensil/fork
name = "fork"
@@ -123,7 +123,7 @@
name = "kitchen knife"
icon_state = "knife"
desc = "A general purpose Chef's Knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come."
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
sharp = IS_SHARP_ITEM_ACCURATE
edge = 1
force = 10
@@ -152,7 +152,7 @@
name = "butcher's cleaver"
icon_state = "butch"
desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown-by-products."
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 15
w_class = WEIGHT_CLASS_SMALL
throwforce = 8
@@ -195,7 +195,7 @@
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_NORMAL
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/* // NOPE
var/food_total= 0
var/burger_amt = 0
@@ -260,7 +260,7 @@
- if(ishuman(M) && ((H.head && (H.head.flags_inventory & COVEREYES) ) || (H.wear_mask && (H.wear_mask.flags_inventory & COVEREYES) ) || (H.glasses && (H.glasses.flags_inventory & COVEREYES) )))
+ if(ishuman(M) && ((H.head && (H.head.inventory_flags & COVEREYES) ) || (H.wear_mask && (H.wear_mask.inventory_flags & COVEREYES) ) || (H.glasses && (H.glasses.inventory_flags & COVEREYES) )))
to_chat(M, span_warning("You get slammed in the face with the tray, against your mask!"))
if(prob(33))
src.add_mob_blood(H)
@@ -317,6 +317,8 @@
/obj/item/tool/kitchen/tray/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/kitchen/rollingpin))
if(cooldown < world.time - 25)
diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm
index 940466d749b25..e522e151cc136 100644
--- a/code/game/objects/items/tools/maintenance_tools.dm
+++ b/code/game/objects/items/tools/maintenance_tools.dm
@@ -2,8 +2,8 @@
name = "wrench"
desc = "A wrench with many common uses. Can be usually found in your hand."
icon_state = "wrench"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 5
throwforce = 7
w_class = WEIGHT_CLASS_SMALL
@@ -16,8 +16,8 @@
name = "screwdriver"
desc = "You can be totally screwwy with this."
icon_state = "screwdriver_map"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 5
w_class = WEIGHT_CLASS_TINY
throwforce = 5
@@ -65,8 +65,8 @@
name = "wirecutters"
desc = "This cuts wires."
icon_state = "cutters"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 6
throw_speed = 2
throw_range = 9
@@ -99,8 +99,8 @@
name = "blowtorch"
desc = "Used for welding and repairing various things."
icon_state = "welder"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
//Amount of OUCH when it's thrown
force = 3
@@ -179,6 +179,8 @@
/obj/item/tool/weldingtool/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/screwdriver))
flamethrower_screwdriver(src, user)
@@ -330,8 +332,8 @@
name = "crowbar"
desc = "Used to remove floors and to pry open doors."
icon_state = "crowbar"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 5
throwforce = 7
item_state = "crowbar"
@@ -351,7 +353,7 @@
/obj/item/tool/weldpack
name = "Welding kit"
desc = "A heavy-duty, portable fuel carrier. Welder and flamer compatible."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/obj/items/tank.dmi'
icon_state = "welderpack"
w_class = WEIGHT_CLASS_BULKY
@@ -366,6 +368,8 @@
/obj/item/tool/weldpack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(reagents.total_volume == 0)
balloon_alert(user, "Out of fuel")
return
@@ -447,7 +451,7 @@
/obj/item/tool/weldpack/marinestandard
name = "M-22 welding kit"
desc = "A heavy-duty, portable fuel carrier. Mainly used in flamethrowers. Welder and flamer compatible."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "marine_flamerpack"
w_class = WEIGHT_CLASS_BULKY
max_fuel = 500 //Because the marine backpack can carry 260, and still allows you to take items, there should be a reason to still use this one.
@@ -456,14 +460,14 @@
name = "handheld charger"
desc = "A hand-held, lightweight cell charger. It isn't going to give you tons of power, but it can help in a pinch."
icon = 'icons/obj/items/tools.dmi'
- icon_state = "handheldcharger_black_empty"
+ icon_state = "handheldcharger_black"
item_state = "handheldcharger_black_empty"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 6
throw_speed = 2
throw_range = 9
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
/// This is the cell we ar charging
var/obj/item/cell/cell
///Are we currently recharging something.
@@ -471,7 +475,14 @@
/obj/item/tool/handheld_charger/Initialize(mapload)
. = ..()
- cell = null
+ update_icon()
+
+/obj/item/tool/handheld_charger/update_icon_state()
+ . = ..()
+ if(cell)
+ icon_state = initial(icon_state)
+ else
+ icon_state = initial(icon_state) + "_empty"
/obj/item/tool/handheld_charger/attack_self(mob/user)
if(!cell)
@@ -499,6 +510,8 @@
/obj/item/tool/handheld_charger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/cell))
return
@@ -528,7 +541,7 @@
cell = null
playsound(user, 'sound/machines/click.ogg', 20, 1, 5)
balloon_alert(user, "Removes the cell")
- icon_state = "handheldcharger_black_empty"
+ update_appearance()
/obj/item/tool/handheld_charger/attack_hand(mob/living/user)
if(user.get_inactive_held_item() != src)
@@ -540,8 +553,12 @@
cell = null
playsound(user, 'sound/machines/click.ogg', 20, 1, 5)
balloon_alert(user, "Removes the cell")
- icon_state = "handheldcharger_black_empty"
+ update_appearance()
/obj/item/tool/handheld_charger/Destroy()
QDEL_NULL(cell)
return ..()
+
+/obj/item/tool/handheld_charger/hicapcell/Initialize(mapload)
+ cell = new /obj/item/cell/high(src)
+ return ..()
diff --git a/code/game/objects/items/tools/mining_tools.dm b/code/game/objects/items/tools/mining_tools.dm
index 8570dabd3d962..25ab6d4f44689 100644
--- a/code/game/objects/items/tools/mining_tools.dm
+++ b/code/game/objects/items/tools/mining_tools.dm
@@ -7,8 +7,8 @@
name = "pickaxe"
icon = 'icons/obj/mining.dmi'
icon_state = "pickaxe"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 15
throwforce = 4
item_state = "pickaxe"
@@ -86,7 +86,7 @@
icon_state = "plasma_cutter_off"
item_state = "plasmacutter"
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_BACK
force = 70
damtype = BURN
digspeed = 20 //Can slice though normal walls, all girders, or be used in reinforced wall deconstruction
@@ -166,7 +166,6 @@
spark_system.attach(source)
spark_system.start(source)
if(!no_string)
- balloon_alert(user, "Cutting...")
if(custom_string)
to_chat(user, span_notice(custom_string))
else
@@ -185,8 +184,6 @@
balloon_alert(user, "Charge Remaining: [cell.charge]/[cell.maxcharge]")
if(custom_string)
to_chat(user, span_notice(custom_string))
- else
- balloon_alert(user, "Cuts apart")
/obj/item/tool/pickaxe/plasmacutter/proc/debris(location, metal = 0, rods = 0, wood = 0, wires = 0, shards = 0, plasteel = 0)
if(metal)
@@ -290,7 +287,8 @@
if(!ST.slayer)
return
ST.slayer = max(0 , ST.slayer - dirt_amt_per_dig)
- ST.update_icon(1,0)
+ ST.update_appearance()
+ ST.update_sides()
cut_apart(user, target.name, target, 0, "You melt the snow with [src]. ") //costs nothing
diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm
index b9b8df77ce62d..aefa38d499ad3 100644
--- a/code/game/objects/items/tools/misc_tools.dm
+++ b/code/game/objects/items/tools/misc_tools.dm
@@ -55,6 +55,8 @@
/obj/item/tool/hand_labeler/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
to_chat(user, span_notice("You insert [I] into [src]."))
qdel(I)
@@ -80,7 +82,7 @@
slot_r_hand_str = 'icons/mob/inhands/items/civilian_right.dmi',
)
item_state = "pen"
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_EARS
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_EARS
w_class = WEIGHT_CLASS_TINY
throw_speed = 7
throw_range = 15
@@ -117,7 +119,7 @@
*/
/obj/item/tool/pen/sleepypen
desc = "It's a black ink pen with a sharp point and a carefully engraved \"Waffle Co.\""
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/tool/pen/sleepypen/Initialize(mapload)
@@ -139,7 +141,7 @@
* Parapens
*/
/obj/item/tool/pen/paralysis
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/tool/pen/paralysis/attack(mob/living/M as mob, mob/user as mob)
diff --git a/code/game/objects/items/tools/policetape.dm b/code/game/objects/items/tools/policetape.dm
index f861a0503532e..1eef67cea2f58 100644
--- a/code/game/objects/items/tools/policetape.dm
+++ b/code/game/objects/items/tools/policetape.dm
@@ -3,7 +3,7 @@
name = "tape roll"
icon = 'icons/obj/policetape.dmi'
icon_state = "rollstart"
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
var/turf/start
var/turf/end
diff --git a/code/game/objects/items/tools/research_tools.dm b/code/game/objects/items/tools/research_tools.dm
index dc485e36c7b49..7d86d8682a41a 100644
--- a/code/game/objects/items/tools/research_tools.dm
+++ b/code/game/objects/items/tools/research_tools.dm
@@ -5,68 +5,11 @@
///Skill level needed to use the tool
var/skill_threshold = SKILL_MEDICAL_EXPERT
-#define RESEARCH_DELAY 2 SECONDS
-
/obj/item/tool/research/xeno_analyzer
- name = "xenomorph analyzer"
- desc = "A tool for analyzing xenomorphs for research material. Just click on a xenomorph. Can be used to befriend Newt."
- icon = 'icons/obj/items/surgery_tools.dmi'
- icon_state = "predator_bonesaw"
- ///List of rewards for each xeno tier
- var/static/list/xeno_tier_rewards = list(
- XENO_TIER_ZERO = list(
- /obj/item/research_resource/xeno/tier_one,
- ),
- XENO_TIER_ONE = list(
- /obj/item/research_resource/xeno/tier_one,
- ),
- XENO_TIER_TWO = list(
- /obj/item/research_resource/xeno/tier_two,
- ),
- XENO_TIER_THREE = list(
- /obj/item/research_resource/xeno/tier_three,
- ),
- XENO_TIER_FOUR = list(
- /obj/item/research_resource/xeno/tier_four,
- ),
- )
-
-/obj/item/tool/research/xeno_analyzer/attack(mob/living/M, mob/living/user)
- if(!isxeno(M))
- return ..()
-
- var/mob/living/carbon/xenomorph/target_xeno = M
-
- var/list/xeno_rewards = xeno_tier_rewards[target_xeno.tier]
- if(!xeno_rewards)
- balloon_alert(user, "Can't research")
- return ..()
-
- if(HAS_TRAIT(target_xeno, TRAIT_RESEARCHED))
- balloon_alert(user, "Already probed")
- return ..()
-
- if(user.skills.getRating(SKILL_MEDICAL) < SKILL_MEDICAL_EXPERT)
- user.balloon_alert_to_viewers("Tries to find weak point on [target_xeno]")
- var/fumbling_time = 15 SECONDS - 2 SECONDS * user.skills.getRating(SKILL_MEDICAL)
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
- return ..()
- user.balloon_alert_to_viewers("Begins cutting [target_xeno]")
- if(!do_after(user, 5 SECONDS, NONE, src, BUSY_ICON_FRIENDLY))
- return ..()
-
- if(HAS_TRAIT(target_xeno, TRAIT_RESEARCHED))
- balloon_alert(user, "Already probed")
- return ..()
-
- var/reward_typepath = pick(xeno_rewards)
- var/obj/reward = new reward_typepath
- reward.forceMove(get_turf(user))
- ADD_TRAIT(target_xeno, TRAIT_RESEARCHED, TRAIT_RESEARCHED)
-
- return ..()
-
-#undef RESEARCH_DELAY
+ name = "xenolinguistic analyzer"
+ desc = "A tool translating communications with some alien species. Can be used to befriend Newt."
+ icon = 'icons/obj/items/implants.dmi'
+ icon_state = "implantcase-b"
/obj/item/tool/research/excavation_tool
name = "subterrain scanner and excavator"
diff --git a/code/game/objects/items/tools/shovel_tools.dm b/code/game/objects/items/tools/shovel_tools.dm
index bb2dd145ca413..e9dddcdfa60c3 100644
--- a/code/game/objects/items/tools/shovel_tools.dm
+++ b/code/game/objects/items/tools/shovel_tools.dm
@@ -6,8 +6,8 @@
icon = 'icons/obj/items/tools.dmi'
icon_state = "shovel"
item_state = "shovel"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 8
throwforce = 4
w_class = WEIGHT_CLASS_NORMAL
@@ -85,7 +85,8 @@
if(!ST.slayer)
return
ST.slayer -= 1
- ST.update_icon(1,0)
+ ST.update_appearance()
+ ST.update_sides()
balloon_alert(user, "Digs up snow")
else
balloon_alert(user, "Digs up dirt")
@@ -151,7 +152,7 @@
else
icon_state = "etool_c"
item_state = "etool_c"
- ..()
+ return ..()
/obj/item/tool/shovel/etool/attack_self(mob/user as mob)
if(sharp)
diff --git a/code/game/objects/items/tools/surgery_tools.dm b/code/game/objects/items/tools/surgery_tools.dm
index cc64c17e62f83..005e5e468e638 100644
--- a/code/game/objects/items/tools/surgery_tools.dm
+++ b/code/game/objects/items/tools/surgery_tools.dm
@@ -11,14 +11,14 @@
name = "retractor"
desc = "Retracts stuff."
icon_state = "retractor"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_SMALL
/obj/item/tool/surgery/hemostat
name = "hemostat"
desc = "You think you have seen this before."
icon_state = "hemostat"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("attacked", "pinched")
@@ -26,7 +26,7 @@
name = "cautery"
desc = "This stops bleeding."
icon_state = "cautery"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_TINY
attack_verb = list("burnt")
@@ -35,7 +35,7 @@
desc = "You can drill using this item. You dig?"
icon_state = "drill"
hitsound = 'sound/weapons/circsawhit.ogg'
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 15
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("drilled")
@@ -48,7 +48,7 @@
name = "scalpel"
desc = "Cut, cut, and once more cut."
icon_state = "scalpel"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 10
sharp = IS_SHARP_ITEM_ACCURATE
edge = 1
@@ -88,7 +88,7 @@
desc = "For heavy duty cutting."
icon_state = "saw"
hitsound = 'sound/weapons/circsawhit.ogg'
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 15
w_class = WEIGHT_CLASS_SMALL
throwforce = 9
diff --git a/code/game/objects/items/toys/cards.dm b/code/game/objects/items/toys/cards.dm
index b4aeeeb525ccc..dfbcd78b4472c 100644
--- a/code/game/objects/items/toys/cards.dm
+++ b/code/game/objects/items/toys/cards.dm
@@ -32,6 +32,8 @@
/obj/item/toy/deck/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/toy/handcard))
var/obj/item/toy/handcard/H = I
@@ -42,6 +44,7 @@
to_chat(user, "You place your cards on the bottom of the deck.")
/obj/item/toy/deck/update_icon_state()
+ . = ..()
switch(length(cards))
if(52)
icon_state = "deck"
@@ -136,14 +139,9 @@
user.visible_message("\The [user] deals a card to \the [target].")
H.throw_at(get_step(target,target.dir),10,1,H)
-/obj/item/toy/deck/attack_self(mob/user as mob)
-
- var/list/newcards = list()
- while(length(cards))
- var/datum/playingcard/P = pick(cards)
- newcards += P
- cards -= P
- cards = newcards
+/obj/item/toy/deck/attack_self(mob/user)
+ . = ..()
+ shuffle_inplace(cards)
user.visible_message("\The [user] shuffles [src].")
/obj/item/toy/deck/MouseDrop(atom/over)
@@ -167,6 +165,8 @@
var/concealed = 0
var/list/cards = list()
+ ///The last direction the person who dropped us was facing
+ var/last_direction = SOUTH
/obj/item/toy/handcard/Initialize(mapload, card_type)
. = ..()
@@ -178,6 +178,8 @@
/obj/item/toy/handcard/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/toy/handcard))
var/obj/item/toy/handcard/H = I
@@ -250,16 +252,22 @@
for(var/datum/playingcard/P in cards)
. += "-[P.name]"
-/obj/item/toy/handcard/update_icon(direction = 0)
+/obj/item/toy/handcard/update_name(updates)
+ . = ..()
if(length(cards) > 1)
name = "hand of cards"
- desc = "Some playing cards."
else
name = "a playing card"
- desc = "A playing card."
- overlays.Cut()
+/obj/item/toy/handcard/update_desc(updates)
+ . = ..()
+ if(length(cards) > 1)
+ desc = "Some playing cards."
+ else
+ desc = "A playing card."
+/obj/item/toy/handcard/update_overlays()
+ . = ..()
if(!length(cards))
return
@@ -268,14 +276,14 @@
var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") )
I.pixel_x += (-5+rand(10))
I.pixel_y += (-5+rand(10))
- overlays += I
+ . += I
return
var/offset = FLOOR(20/length(cards), 1)
var/matrix/M = matrix()
- if(direction)
- switch(direction)
+ if(last_direction)
+ switch(last_direction)
if(NORTH)
M.Translate( 0, 0)
if(SOUTH)
@@ -290,7 +298,7 @@
for(var/datum/playingcard/P in cards)
var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") )
//I.pixel_x = origin+(offset*i)
- switch(direction)
+ switch(last_direction)
if(SOUTH)
I.pixel_x = 8-(offset*i)
if(WEST)
@@ -300,15 +308,14 @@
else
I.pixel_x = -7+(offset*i)
I.transform = M
- overlays += I
+ . += I
i++
/obj/item/toy/handcard/dropped(mob/user as mob)
- ..()
+ . = ..()
if(locate(/obj/structure/table, loc))
- src.update_icon(user.dir)
- else
- update_icon()
+ last_direction = user.dir
+ update_icon()
/obj/item/toy/handcard/pickup(mob/user as mob)
src.update_icon()
@@ -357,12 +364,34 @@
P.card_icon = "Wildcard"
cards += P
for(var/k in 0 to 3)
+ P = new()
P.name= "Draw 4"
P.card_icon = "Draw 4"
cards += P
/obj/item/toy/deck/kotahi/update_icon_state()
+ . = ..()
switch(length(cards))
- if(107 to 108) icon_state = "deck"
- if(37 to 106) icon_state = "deck_open"
- if(0 to 36) icon_state = "deck_empty"
+ if(107 to 108)
+ icon_state = "deck"
+ if(37 to 106)
+ icon_state = "deck_open"
+ if(0 to 36)
+ icon_state = "deck_empty"
+
+// purely cosmetic for helmet stuff, can't be stacked with normal cards
+/obj/item/toy/card/ace/hearts
+ name = "Ancient Ace of Hearts card"
+ desc = "An ancient copy of an Ace of Hearts from a deck of playing cards."
+ icon = 'icons/obj/items/items.dmi'
+ icon_state = "ace_of_hearts"
+ item_state = "ace_of_hearts"
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/toy/card/ace/spades
+ name = "Ancient Ace of Spades card"
+ desc = "An ancient copy of an Ace of Spades from a deck of playing cards."
+ icon = 'icons/obj/items/items.dmi'
+ icon_state = "ace_of_spades"
+ item_state = "ace_of_spades"
+ w_class = WEIGHT_CLASS_TINY
diff --git a/code/game/objects/items/toys/toy_weapons.dm b/code/game/objects/items/toys/toy_weapons.dm
index 27393f6e8f0a7..628a81998a4a7 100644
--- a/code/game/objects/items/toys/toy_weapons.dm
+++ b/code/game/objects/items/toys/toy_weapons.dm
@@ -14,7 +14,7 @@
desc = "Looks almost like the real thing! Ages 8 and up. Please recycle in an autolathe when you're out of caps!"
icon_state = "capgun"
item_state = "gun"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("struck", "pistol whipped", "hit", "bashed")
@@ -66,6 +66,7 @@
var/amount_left = 7
/obj/item/toy/gun_ammo/update_icon_state()
+ . = ..()
if(amount_left)
icon_state = "cap_ammo"
else
@@ -220,8 +221,8 @@
desc = "Woefully underpowered in D20."
icon = 'icons/obj/items/weapons.dmi'
icon_state = "katana"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_BACK
force = 5
throwforce = 5
w_class = WEIGHT_CLASS_NORMAL
diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm
index e25b26fdc7f35..c3685440ed322 100755
--- a/code/game/objects/items/toys/toys.dm
+++ b/code/game/objects/items/toys/toys.dm
@@ -25,10 +25,10 @@
throw_range = 20
force = 0
-/obj/item/toy/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/toy/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
+ attack_hand(xeno_attacker)
/*
@@ -61,6 +61,8 @@
/obj/item/toy/balloon/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/glass))
if(!I.reagents)
@@ -96,6 +98,7 @@
QDEL_IN(src, 5)
/obj/item/toy/balloon/update_icon_state()
+ . = ..()
if(reagents.total_volume)
icon_state = "waterballoon"
item_state = "balloon"
@@ -362,7 +365,7 @@
icon_state = "inflatable"
item_state = "inflatable"
icon = 'icons/obj/clothing/belts.dmi'
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/toy/beach_ball
@@ -773,28 +776,33 @@
var/side = ""
var/id = ""
-
-/obj/structure/hoop/attackby(obj/item/I, mob/user, params)
+/obj/structure/hoop/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
. = ..()
+ if(.)
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(user.a_intent == INTENT_HARM)
+ return
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(user.grab_state <= GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
+ return
- if(istype(I, /obj/item/grab) && get_dist(src, user) <= 1)
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
+ grabbed_mob.forceMove(loc)
+ grabbed_mob.Paralyze(4 SECONDS)
+ for(var/obj/machinery/scoreboard/X in GLOB.machines)
+ if(X.id == id)
+ X.score(side, 3)// 3 points for dunking a mob
+ visible_message(span_danger("[user] dunks [grabbed_mob] into the [src]!"))
- var/mob/living/L = G.grabbed_thing
- if(user.grab_state < GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
- L.forceMove(loc)
- L.Paralyze(10 SECONDS)
- for(var/obj/machinery/scoreboard/X in GLOB.machines)
- if(X.id == id)
- X.score(side, 3)// 3 points for dunking a mob
- // no break, to update multiple scoreboards
- visible_message(span_danger("[user] dunks [L] into the [src]!"))
- else if(get_dist(src, user) < 2)
+/obj/structure/hoop/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if(.)
+ return
+
+ if(get_dist(src, user) < 2)
user.transferItemToLoc(I, loc)
for(var/obj/machinery/scoreboard/X in GLOB.machines)
if(X.id == id)
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index 9d6c8722ff65e..4167ec4a2be05 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -148,9 +148,9 @@
desc = "An empty box from a chunk bar. Significantly less heavy."
icon_state = "chunk_trash"
-/obj/item/trash/barcardine
- name = "barcardine bar wrapper"
- desc = "An empty wrapper from a barcardine bar. You notice the inside has several medical labels. You're not sure if you care or not about that."
+/obj/item/trash/barcaridine
+ name = "barcaridine bar wrapper"
+ desc = "An empty wrapper from a barcaridine bar. You notice the inside has several medical labels. You're not sure if you care or not about that."
icon_state = "barcardine_trash"
/obj/item/trash/berrybar
diff --git a/code/game/objects/items/weapons/blades.dm b/code/game/objects/items/weapons/blades.dm
index 0f8fc8d30706d..4b4ca8a9da8a1 100644
--- a/code/game/objects/items/weapons/blades.dm
+++ b/code/game/objects/items/weapons/blades.dm
@@ -22,23 +22,95 @@
desc = "What are you standing around staring at this for? Get to killing!"
icon_state = "claymore"
item_state = "claymore"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 40
throwforce = 10
sharp = IS_SHARP_ITEM_BIG
edge = 1
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ ///Special attack action granted to users with the right trait
+ var/datum/action/ability/activable/weapon_skill/sword_lunge/special_attack
/obj/item/weapon/claymore/Initialize(mapload)
. = ..()
AddElement(/datum/element/scalping)
+ special_attack = new(src, force, penetration)
+
+/obj/item/weapon/claymore/Destroy()
+ QDEL_NULL(special_attack)
+ return ..()
+
+/obj/item/weapon/claymore/equipped(mob/user, slot)
+ . = ..()
+ if(HAS_TRAIT(user, TRAIT_SWORD_EXPERT))
+ special_attack.give_action(user)
+
+/obj/item/weapon/claymore/dropped(mob/user)
+ . = ..()
+ special_attack.remove_action(user)
/obj/item/weapon/claymore/suicide_act(mob/user)
user.visible_message(span_danger("[user] is falling on the [src.name]! It looks like [user.p_theyre()] trying to commit suicide."))
return(BRUTELOSS)
+//Special attack
+/datum/action/ability/activable/weapon_skill/sword_lunge
+ name = "Lunging strike"
+ action_icon_state = "sword_lunge"
+ desc = "A powerful leaping strike. Cannot stun."
+ ability_cost = 8
+ cooldown_duration = 6 SECONDS
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_WEAPONABILITY_SWORDLUNGE,
+ )
+
+/datum/action/ability/activable/weapon_skill/sword_lunge/use_ability(atom/A)
+ var/mob/living/carbon/carbon_owner = owner
+
+ RegisterSignal(carbon_owner, COMSIG_MOVABLE_MOVED, PROC_REF(movement_fx))
+ RegisterSignal(carbon_owner, COMSIG_MOVABLE_BUMP, PROC_REF(lunge_impact))
+ RegisterSignal(carbon_owner, COMSIG_MOVABLE_POST_THROW, PROC_REF(charge_complete))
+
+ carbon_owner.visible_message(span_danger("[carbon_owner] charges towards \the [A]!"))
+ playsound(owner, "sound/effects/alien_tail_swipe2.ogg", 50, 0, 4)
+ carbon_owner.throw_at(A, 2, 1, carbon_owner)
+ succeed_activate()
+ add_cooldown()
+
+///Create an after image
+/datum/action/ability/activable/weapon_skill/sword_lunge/proc/movement_fx()
+ SIGNAL_HANDLER
+ new /obj/effect/temp_visual/xenomorph/afterimage(get_turf(owner), owner)
+
+///Unregisters signals after lunge complete
+/datum/action/ability/activable/weapon_skill/sword_lunge/proc/charge_complete()
+ SIGNAL_HANDLER
+ UnregisterSignal(owner, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_POST_THROW, COMSIG_MOVABLE_MOVED))
+
+///Sig handler for atom impacts during lunge
+/datum/action/ability/activable/weapon_skill/sword_lunge/proc/lunge_impact(datum/source, obj/target, speed)
+ SIGNAL_HANDLER
+ INVOKE_ASYNC(src, PROC_REF(do_lunge_impact), source, target)
+ charge_complete()
+
+///Actual effects of lunge impact
+/datum/action/ability/activable/weapon_skill/sword_lunge/proc/do_lunge_impact(datum/source, obj/target)
+ var/mob/living/carbon/carbon_owner = source
+ if(!ishuman(target))
+ var/obj/obj_victim = target
+ obj_victim.take_damage(damage, BRUTE, MELEE, TRUE, TRUE, get_dir(obj_victim, carbon_owner), penetration, carbon_owner)
+ if(!obj_victim.anchored && obj_victim.move_resist < MOVE_FORCE_VERY_STRONG)
+ obj_victim.knockback(carbon_owner, 1, 2)
+ else
+ var/mob/living/carbon/human/human_victim = target
+ human_victim.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, MELEE, TRUE, TRUE, TRUE, penetration)
+ human_victim.adjust_stagger(1 SECONDS)
+ playsound(human_victim, "sound/weapons/wristblades_hit.ogg", 25, 0, 5)
+ shake_camera(human_victim, 2, 1)
+
/obj/item/weapon/claymore/mercsword
name = "combat sword"
desc = "A dusty sword commonly seen in historical museums. Where you got this is a mystery, for sure. Only a mercenary would be nuts enough to carry one of these. Sharpened to deal massive damage."
@@ -97,15 +169,11 @@
attack_speed = 10
w_class = WEIGHT_CLASS_BULKY
-/obj/item/weapon/claymore/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
- playsound(loc, 'sound/weapons/bladeslice.ogg', 25, 1)
- return ..()
-
/obj/item/weapon/katana
name = "katana"
desc = "A finely made Japanese sword, with a well sharpened blade. The blade has been filed to a molecular edge, and is extremely deadly. Commonly found in the hands of mercenaries and yakuza."
icon_state = "katana"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 50
throwforce = 10
sharp = IS_SHARP_ITEM_BIG
@@ -164,7 +232,7 @@
icon_state = "combat_knife"
item_state = "combat_knife"
desc = "A standard survival knife of high quality. You can slide this knife into your boots, and can be field-modified to attach to the end of a rifle with cable coil."
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
sharp = IS_SHARP_ITEM_ACCURATE
force = 30
w_class = WEIGHT_CLASS_SMALL
@@ -217,7 +285,7 @@
icon_state = "karambit"
item_state = "karambit"
desc = "A small high quality knife with a curved blade, good for slashing and hooking. This one has a mottled red finish."
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
sharp = IS_SHARP_ITEM_ACCURATE
force = 30
w_class = WEIGHT_CLASS_SMALL
@@ -260,7 +328,7 @@
desc="A military knife designed to be thrown at the enemy. Much quieter than a firearm, but requires a steady hand to be used effectively."
stack_name = "pile"
singular_name = "knife"
- flags_atom = CONDUCT|DIRLOCK
+ atom_flags = CONDUCT|DIRLOCK
sharp = IS_SHARP_ITEM_ACCURATE
force = 20
w_class = WEIGHT_CLASS_TINY
@@ -269,7 +337,7 @@
throw_range = 7
hitsound = 'sound/weapons/slash.ogg'
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
max_amount = 5
amount = 5
@@ -285,13 +353,9 @@
RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, PROC_REF(post_throw))
AddComponent(/datum/component/automatedfire/autofire, throw_delay, _fire_mode = GUN_FIREMODE_AUTOMATIC, _callback_reset_fire = CALLBACK(src, PROC_REF(stop_fire)), _callback_fire = CALLBACK(src, PROC_REF(throw_knife)))
-/obj/item/stack/throwing_knife/update_icon()
+/obj/item/stack/throwing_knife/update_icon_state()
. = ..()
- var/amount_to_show = amount > max_amount ? max_amount : amount
- if(amount_to_show > 8)
- setDir(8)
- return
- setDir(amount_to_show + round(amount_to_show / 3))
+ icon_state = "throwing_knife_[amount]"
/obj/item/stack/throwing_knife/equipped(mob/user, slot)
. = ..()
diff --git a/code/game/objects/items/weapons/energy.dm b/code/game/objects/items/weapons/energy.dm
index a7faf3b092115..0b1dd7cbe2469 100644
--- a/code/game/objects/items/weapons/energy.dm
+++ b/code/game/objects/items/weapons/energy.dm
@@ -1,5 +1,5 @@
/obj/item/weapon/energy
- flags_atom = NOBLOODY
+ atom_flags = NOBLOODY
/obj/item/weapon/energy/suicide_act(mob/user)
user.visible_message(pick(span_danger("[user] is slitting [user.p_their()] stomach open with the [name]! It looks like [user.p_theyre()] trying to commit seppuku."), \
@@ -17,7 +17,7 @@
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_NORMAL
- flags_atom = CONDUCT|NOBLOODY
+ atom_flags = CONDUCT|NOBLOODY
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
sharp = IS_SHARP_ITEM_BIG
edge = 1
@@ -52,23 +52,33 @@
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
- flags_atom = NOBLOODY
+ atom_flags = NOBLOODY
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
sharp = IS_SHARP_ITEM_BIG
edge = 1
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
///Sword color, if applicable
var/sword_color
///Force of the weapon when activated
var/active_force = 40
+ ///Penetration when activated
+ var/active_penetration = 30
+ ///Special attack action granted to users with the right trait
+ var/datum/action/ability/activable/weapon_skill/sword_lunge/special_attack
/obj/item/weapon/energy/sword/Initialize(mapload)
. = ..()
if(!sword_color)
sword_color = pick("red","blue","green","purple")
- AddComponent(/datum/component/shield, SHIELD_TOGGLE|SHIELD_PURE_BLOCKING, shield_cover = list(MELEE = 35, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0))
+ AddComponent(/datum/component/shield, SHIELD_TOGGLE|SHIELD_PURE_BLOCKING, list(MELEE = 35, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0))
AddComponent(/datum/component/stun_mitigation, shield_cover = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 40, BOMB = 40, BIO = 40, FIRE = 40, ACID = 40))
AddElement(/datum/element/strappable)
+ AddElement(/datum/element/scalping)
+ special_attack = new(src, active_force, active_penetration)
+
+/obj/item/weapon/energy/sword/Destroy()
+ QDEL_NULL(special_attack)
+ return ..()
/obj/item/weapon/energy/sword/attack_self(mob/living/user)
switch_state(src, user)
@@ -84,27 +94,30 @@
SIGNAL_HANDLER
toggle_active()
if(active)
+ RegisterSignals(src, list(COMSIG_ITEM_EQUIPPED_TO_SLOT, COMSIG_ITEM_EQUIPPED_NOT_IN_SLOT, COMSIG_ITEM_UNEQUIPPED), PROC_REF(switch_state))
toggle_item_bump_attack(user, TRUE)
hitsound = 'sound/weapons/blade1.ogg'
force = active_force
throwforce = active_force
- penetration = 30
+ penetration = active_penetration
heat = 3500
icon_state = "[initial(icon_state)]_[sword_color]"
w_class = WEIGHT_CLASS_BULKY
playsound(src, 'sound/weapons/saberon.ogg', 25, 1)
- RegisterSignals(src, list(COMSIG_ITEM_EQUIPPED_TO_SLOT, COMSIG_ITEM_EQUIPPED_NOT_IN_SLOT, COMSIG_ITEM_UNEQUIPPED), PROC_REF(switch_state))
+ if(HAS_TRAIT(user, TRAIT_SWORD_EXPERT))
+ special_attack.give_action(user)
else
+ UnregisterSignal(src, list(COMSIG_ITEM_EQUIPPED_TO_SLOT, COMSIG_ITEM_EQUIPPED_NOT_IN_SLOT, COMSIG_ITEM_UNEQUIPPED))
toggle_item_bump_attack(user, FALSE)
hitsound = initial(hitsound)
force = initial(force)
throwforce = initial(throwforce)
- penetration = 0
+ penetration = initial(penetration)
heat = 0
icon_state = "[initial(icon_state)]"
w_class = WEIGHT_CLASS_SMALL
playsound(src, 'sound/weapons/saberoff.ogg', 25, 1)
- UnregisterSignal(src, list(COMSIG_ITEM_EQUIPPED_TO_SLOT, COMSIG_ITEM_EQUIPPED_NOT_IN_SLOT, COMSIG_ITEM_UNEQUIPPED))
+ special_attack.remove_action(user)
/obj/item/weapon/energy/sword/pirate
name = "energy cutlass"
diff --git a/code/game/objects/items/weapons/holo_weapons.dm b/code/game/objects/items/weapons/holo_weapons.dm
index 597c3466a19f5..a1d153935c345 100644
--- a/code/game/objects/items/weapons/holo_weapons.dm
+++ b/code/game/objects/items/weapons/holo_weapons.dm
@@ -11,7 +11,7 @@
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
var/sword_color
diff --git a/code/game/objects/items/weapons/misc.dm b/code/game/objects/items/weapons/misc.dm
index 369b4692e140f..80a298c491957 100644
--- a/code/game/objects/items/weapons/misc.dm
+++ b/code/game/objects/items/weapons/misc.dm
@@ -3,8 +3,8 @@
desc = "A tool used by great men to placate the frothing masses."
icon_state = "chain"
item_state = "chain"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 10
throwforce = 7
w_class = WEIGHT_CLASS_NORMAL
@@ -20,7 +20,7 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "cane"
item_state = "cane"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 5
throwforce = 7
w_class = WEIGHT_CLASS_SMALL
@@ -50,7 +50,7 @@
desc = "A metal gauntlet with a energy-powered fist to throw back enemies. Altclick to clamp it around your hand, use it to change power settings and click with an empty off-hand or right click to pop out the cell."
icon_state = "powerfist"
item_state = "powerfist"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 10
attack_verb = list("smashed", "rammed", "power-fisted")
var/obj/item/cell/cell
@@ -188,5 +188,5 @@
attack_verb = list("smacked", "whacked", "bonked", "pelted", "thwacked", "cracked")
hitsound = 'sound/weapons/heavyhit.ogg'
singular_name = "stone"
- flags_atom = DIRLOCK
+ atom_flags = DIRLOCK
sharp = IS_NOT_SHARP_ITEM
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index e50a9dd5bbd6b..f663ad2b3f060 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -10,7 +10,7 @@
set_shield()
/obj/item/weapon/shield/proc/set_shield()
- AddComponent(/datum/component/shield, SHIELD_PARENT_INTEGRITY, shield_cover = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 80, BIO = 30, FIRE = 50, ACID = 80))
+ AddComponent(/datum/component/shield, SHIELD_PARENT_INTEGRITY, list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 80, BIO = 30, FIRE = 50, ACID = 80))
AddComponent(/datum/component/stun_mitigation)
/obj/item/weapon/shield/riot
@@ -19,8 +19,8 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "riot"
max_integrity = 200
- flags_item = IMPEDE_JETPACK
- flags_equip_slot = ITEM_SLOT_BACK
+ item_flags = IMPEDE_JETPACK
+ equip_slot_flags = ITEM_SLOT_BACK
force = 5
throwforce = 5
throw_speed = 1
@@ -53,6 +53,8 @@
/obj/item/weapon/shield/riot/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/metal_sheets = I
@@ -91,7 +93,7 @@
desc = "A heavy shield adept at blocking blunt or sharp objects from connecting with the shield wielder. Looks very robust. Alt click to tighten the strap."
icon = 'icons/obj/items/weapons.dmi'
icon_state = "marine_shield"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
max_integrity = 400
integrity_failure = 100
soft_armor = list(MELEE = 40, BULLET = 50, LASER = 20, ENERGY = 70, BOMB = 15, BIO = 50, FIRE = 0, ACID = 30)
@@ -104,6 +106,7 @@
AddElement(/datum/element/strappable)
/obj/item/weapon/shield/riot/marine/update_icon_state()
+ . = ..()
if(obj_integrity <= integrity_failure)
icon_state = initial(icon_state) + "_broken"
else
@@ -137,13 +140,13 @@
desc = "A compact shield adept at blocking blunt or sharp objects from connecting with the shield wielder. Can be deployed as a barricade. Alt click to tighten the strap."
icon = 'icons/obj/items/weapons.dmi'
icon_state = "folding_shield"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_NORMAL
max_integrity = 300
integrity_failure = 50
soft_armor = list(MELEE = 35, BULLET = 30, LASER = 20, ENERGY = 40, BOMB = 25, BIO = 50, FIRE = 0, ACID = 30)
slowdown = 0.3
- flags_item = IS_DEPLOYABLE
+ item_flags = IS_DEPLOYABLE
///The item this deploys into
var/deployable_item = /obj/structure/barricade/metal/deployable
///Time to deploy
@@ -158,14 +161,14 @@
AddComponent(/datum/component/deployable_item, deployable_item, deploy_time, undeploy_time)
/obj/item/weapon/shield/riot/marine/deployable/set_shield()
- AddComponent(/datum/component/shield, SHIELD_PARENT_INTEGRITY, shield_cover = list(MELEE = 40, BULLET = 35, LASER = 35, ENERGY = 35, BOMB = 40, BIO = 15, FIRE = 30, ACID = 35))
+ AddComponent(/datum/component/shield, SHIELD_PARENT_INTEGRITY, list(MELEE = 40, BULLET = 35, LASER = 35, ENERGY = 35, BOMB = 40, BIO = 15, FIRE = 30, ACID = 35))
/obj/item/weapon/shield/energy
name = "energy combat shield"
desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere."
icon = 'icons/obj/items/weapons.dmi'
icon_state = "eshield0" // eshield1 for expanded
- flags_atom = CONDUCT|NOBLOODY
+ atom_flags = CONDUCT|NOBLOODY
force = 3
throwforce = 5
throw_speed = 1
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 5c264d6b0966f..62855da1d467a 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -3,7 +3,7 @@
desc = "A stun baton for incapacitating people with."
icon_state = "stunbaton"
item_state = "baton"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 15
sharp = 0
edge = 0
@@ -38,6 +38,7 @@
return 0
/obj/item/weapon/baton/update_icon_state()
+ . = ..()
if(status)
icon_state = "[initial(name)]_active"
else if(!bcell)
@@ -84,6 +85,8 @@
/obj/item/weapon/baton/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/cell))
if(bcell)
@@ -200,7 +203,7 @@
agonyforce = 60 //same force as a stunbaton, but uses way more charge.
hitcost = 2500
attack_verb = list("poked")
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
has_user_lock = FALSE
@@ -209,7 +212,7 @@
desc = "A specialised prod designed for incapacitating xenomorphic lifeforms with."
icon_state = "stunbaton"
item_state = "baton"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 12
throwforce = 7
w_class = WEIGHT_CLASS_NORMAL
@@ -223,6 +226,7 @@
/obj/item/weapon/stunprod/update_icon_state()
+ . = ..()
if(status)
icon_state = "stunbaton_active"
else
diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm
index 3eaa6733a30e4..463d06d476a8e 100644
--- a/code/game/objects/items/weapons/swords_axes_etc.dm
+++ b/code/game/objects/items/weapons/swords_axes_etc.dm
@@ -22,7 +22,7 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "baton"
item_state = "classic_baton"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 10
/obj/item/weapon/classic_baton/attack(mob/living/M, mob/living/user)
@@ -40,7 +40,7 @@
icon = 'icons/obj/items/weapons.dmi'
icon_state = "telebaton_0"
item_state = "telebaton_0"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
force = 3
var/on = 0
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index 89bb9d67d447c..db3090941c70f 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -6,7 +6,7 @@
var/force_wielded = 0
var/wieldsound
var/unwieldsound
- flags_item = TWOHANDED
+ item_flags = TWOHANDED
/obj/item/weapon/twohanded/mob_can_equip(mob/user, slot, warning = TRUE, override_nodrop = FALSE, bitslot = FALSE)
unwield(user)
@@ -24,7 +24,7 @@
/obj/item/proc/wield(mob/user)
- if(!(flags_item & TWOHANDED) || flags_item & WIELDED)
+ if(!(item_flags & TWOHANDED) || item_flags & WIELDED)
return FALSE
var/obj/item/offhand = user.get_inactive_held_item()
@@ -59,7 +59,7 @@
/obj/item/proc/unwield(mob/user)
- if(!CHECK_MULTIPLE_BITFIELDS(flags_item, TWOHANDED|WIELDED))
+ if(!CHECK_MULTIPLE_BITFIELDS(item_flags, TWOHANDED|WIELDED))
return FALSE
toggle_wielded(user, FALSE)
@@ -95,9 +95,9 @@
/obj/item/proc/toggle_wielded(user, wielded)
if(wielded)
- flags_item |= WIELDED
+ item_flags |= WIELDED
else
- flags_item &= ~WIELDED
+ item_flags &= ~WIELDED
/obj/item/weapon/twohanded/wield(mob/user)
. = ..()
@@ -126,7 +126,7 @@
/obj/item/weapon/twohanded/attack_self(mob/user)
. = ..()
- if(flags_item & WIELDED)
+ if(item_flags & WIELDED)
unwield(user)
else
wield(user)
@@ -137,7 +137,7 @@
w_class = WEIGHT_CLASS_HUGE
icon_state = "offhand"
name = "offhand"
- flags_item = DELONDROP|TWOHANDED|WIELDED
+ item_flags = DELONDROP|TWOHANDED|WIELDED
resistance_flags = RESIST_ALL
@@ -178,9 +178,9 @@
sharp = IS_SHARP_ITEM_BIG
edge = TRUE
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK
- flags_atom = CONDUCT
- flags_item = TWOHANDED
+ equip_slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_BACK
+ atom_flags = CONDUCT
+ item_flags = TWOHANDED
force_wielded = 75
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
@@ -213,26 +213,99 @@
force = 40
force_wielded = 80
penetration = 35
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
attack_speed = 15
+ ///Special attack action granted to users with the right trait
+ var/datum/action/ability/activable/weapon_skill/axe_sweep/special_attack
/obj/item/weapon/twohanded/fireaxe/som/Initialize(mapload)
. = ..()
- AddComponent(/datum/component/shield, SHIELD_TOGGLE|SHIELD_PURE_BLOCKING, shield_cover = list(MELEE = 45, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0))
+ AddComponent(/datum/component/shield, SHIELD_TOGGLE|SHIELD_PURE_BLOCKING, list(MELEE = 45, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0))
AddComponent(/datum/component/stun_mitigation, SHIELD_TOGGLE, shield_cover = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 60, BIO = 60, FIRE = 60, ACID = 60))
AddElement(/datum/element/strappable)
+ special_attack = new(src, force_wielded, penetration)
+
+/obj/item/weapon/twohanded/fireaxe/som/Destroy()
+ QDEL_NULL(special_attack)
+ return ..()
/obj/item/weapon/twohanded/fireaxe/som/wield(mob/user)
. = ..()
if(!.)
return
toggle_item_bump_attack(user, TRUE)
+ if(HAS_TRAIT(user, TRAIT_AXE_EXPERT))
+ special_attack.give_action(user)
/obj/item/weapon/twohanded/fireaxe/som/unwield(mob/user)
. = ..()
if(!.)
return
toggle_item_bump_attack(user, FALSE)
+ special_attack.remove_action(user)
+
+//Special attack
+/datum/action/ability/activable/weapon_skill/axe_sweep
+ name = "Sweeping blow"
+ action_icon_state = "axe_sweep"
+ desc = "A powerful sweeping blow that hits foes in the direction you are facing. Cannot stun."
+ ability_cost = 10
+ cooldown_duration = 6 SECONDS
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_WEAPONABILITY_AXESWEEP,
+ )
+ /// Used for particles. Holds the particles instead of the mob. See particle_holder for documentation.
+ var/obj/effect/abstract/particle_holder/particle_holder
+
+/datum/action/ability/activable/weapon_skill/axe_sweep/use_ability(atom/A)
+ succeed_activate()
+ add_cooldown()
+ var/mob/living/carbon/carbon_owner = owner
+ carbon_owner.Move(get_step_towards(carbon_owner, A), get_dir(src, A))
+ carbon_owner.face_atom(A)
+ activate_particles(owner.dir)
+ playsound(owner, "sound/effects/alien_tail_swipe3.ogg", 50, 0, 5)
+ owner.visible_message(span_danger("[owner] Swing their weapon in a deadly arc!"))
+
+ var/list/atom/movable/atoms_to_ravage = get_step(owner, owner.dir).contents.Copy()
+ atoms_to_ravage += get_step(owner, turn(owner.dir, -45)).contents
+ atoms_to_ravage += get_step(owner, turn(owner.dir, 45)).contents
+ for(var/atom/movable/victim AS in atoms_to_ravage)
+ if((victim.resistance_flags & INDESTRUCTIBLE))
+ continue
+ if(!ishuman(victim))
+ var/obj/obj_victim = victim
+ obj_victim.take_damage(damage, BRUTE, MELEE, TRUE, TRUE, get_dir(obj_victim, carbon_owner), penetration, carbon_owner)
+ if(!obj_victim.anchored && obj_victim.move_resist < MOVE_FORCE_VERY_STRONG)
+ obj_victim.knockback(owner, 1, 2)
+ continue
+ var/mob/living/carbon/human/human_victim = victim
+ if(human_victim.lying_angle)
+ continue
+ human_victim.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, MELEE, TRUE, TRUE, TRUE, penetration)
+ human_victim.knockback(owner, 1, 2)
+ human_victim.adjust_stagger(1 SECONDS)
+ playsound(human_victim, "sound/weapons/wristblades_hit.ogg", 25, 0, 5)
+ shake_camera(human_victim, 2, 1)
+
+/// Handles the activation and deactivation of particles, as well as their appearance.
+/datum/action/ability/activable/weapon_skill/axe_sweep/proc/activate_particles(direction)
+ particle_holder = new(get_turf(owner), /particles/ravager_slash)
+ QDEL_NULL_IN(src, particle_holder, 5)
+ particle_holder.particles.rotation += dir2angle(direction)
+ switch(direction) // There's no shared logic here because sprites are magical.
+ if(NORTH) // Gotta define stuff for each angle so it looks good.
+ particle_holder.particles.position = list(8, 4)
+ particle_holder.particles.velocity = list(0, 20)
+ if(EAST)
+ particle_holder.particles.position = list(3, -8)
+ particle_holder.particles.velocity = list(20, 0)
+ if(SOUTH)
+ particle_holder.particles.position = list(-9, -3)
+ particle_holder.particles.velocity = list(0, -20)
+ if(WEST)
+ particle_holder.particles.position = list(-4, 9)
+ particle_holder.particles.velocity = list(-20, 0)
/*
* Double-Bladed Energy Swords - Cheridan
@@ -250,7 +323,7 @@
force_wielded = 150
wieldsound = 'sound/weapons/saberon.ogg'
unwieldsound = 'sound/weapons/saberoff.ogg'
- flags_atom = NOBLOODY
+ atom_flags = NOBLOODY
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
sharp = IS_SHARP_ITEM_BIG
edge = 1
@@ -267,7 +340,7 @@
item_state = "spearglass"
force = 40
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
force_wielded = 75
throwforce = 75
throw_speed = 3
@@ -313,7 +386,7 @@
/obj/item/weapon/twohanded/spear/tactical/tacticool
name = "M-23 TACTICOOL spear"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/Marine/spear.dmi'
desc = "A TACTICOOL spear. Used for TACTICOOLNESS in combat."
/obj/item/weapon/twohanded/spear/tactical/tacticool/Initialize(mapload)
@@ -356,24 +429,26 @@
desc = "A huge, powerful blade on a metallic pole. Mysterious writing is carved into the weapon."
force = 28
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
force_wielded = 90
throwforce = 65
throw_speed = 3
edge = 1
sharp = IS_SHARP_ITEM_BIG
- flags_atom = CONDUCT
- hitsound = 'sound/weapons/bladeslice.ogg'
+ atom_flags = CONDUCT
attack_verb = list("sliced", "slashed", "jabbed", "torn", "gored")
resistance_flags = UNACIDABLE
attack_speed = 12 //Default is 7.
+/obj/item/weapon/twohanded/glaive/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
+ playsound(loc, 'sound/weapons/bladeslice.ogg', 25, 1)
+ return ..()
+
/obj/item/weapon/twohanded/glaive/damaged
name = "war glaive"
desc = "A huge, powerful blade on a metallic pole. Mysterious writing is carved into the weapon. This one is ancient and has suffered serious acid damage, making it near-useless."
force = 18
force_wielded = 28
-
/obj/item/weapon/twohanded/rocketsledge
name = "rocket sledge"
desc = "Fitted with a rocket booster at the head, the rocket sledge would deliver a tremendously powerful impact, easily crushing your enemies. Uses fuel to power itself. Press AltClick to tighten your grip. Press Spacebar to change modes."
@@ -381,13 +456,13 @@
item_state = "rocketsledge"
force = 30
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
force_wielded = 75
throwforce = 50
throw_speed = 2
edge = 1
sharp = IS_SHARP_ITEM_BIG
- flags_atom = CONDUCT | TWOHANDED
+ atom_flags = CONDUCT | TWOHANDED
attack_verb = list("smashed", "hammered")
attack_speed = 20
@@ -444,7 +519,8 @@
update_icon()
/obj/item/weapon/twohanded/rocketsledge/update_icon_state()
- if ((reagents.get_reagent_amount(/datum/reagent/fuel) > fuel_used) && (CHECK_BITFIELD(flags_item, WIELDED)))
+ . = ..()
+ if ((reagents.get_reagent_amount(/datum/reagent/fuel) > fuel_used) && (CHECK_BITFIELD(item_flags, WIELDED)))
icon_state = "rocketsledge_w"
else
icon_state = "rocketsledge"
@@ -482,7 +558,7 @@
playsound(loc, 'sound/machines/switch.ogg', 25)
/obj/item/weapon/twohanded/rocketsledge/attack(mob/living/carbon/M, mob/living/carbon/user as mob)
- if(!CHECK_BITFIELD(flags_item, WIELDED))
+ if(!CHECK_BITFIELD(item_flags, WIELDED))
to_chat(user, span_warning("You need a more secure grip to use [src]!"))
return
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index aeddd6d6a4ded..048e34e7ad78f 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -5,7 +5,7 @@
name = "banhammer"
icon = 'icons/obj/items/items.dmi'
icon_state = "toyhammer"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
throw_speed = 7
throw_range = 15
@@ -20,7 +20,7 @@
desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of paranormal phenomenae."
icon_state = "nullrod"
item_state = "nullrod"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
force = 15
throw_speed = 1
throw_range = 4
@@ -118,7 +118,7 @@
desc = "A rod with some wire wrapped around the top. It'd be easy to attach something to the top bit."
icon_state = "wiredrod"
item_state = "rods"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
force = 8
throwforce = 10
w_class = WEIGHT_CLASS_NORMAL
@@ -127,6 +127,8 @@
/obj/item/weapon/wirerod/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/shard))
var/obj/item/weapon/twohanded/spear/S = new
@@ -135,4 +137,4 @@
to_chat(user, span_notice("You fasten the glass shard to the top of the rod with the cable."))
qdel(I)
qdel(src)
- update_icon(user)
+ update_icon()
diff --git a/code/game/objects/items/whistle.dm b/code/game/objects/items/whistle.dm
index e29e036aca29d..bf26b51a631f8 100644
--- a/code/game/objects/items/whistle.dm
+++ b/code/game/objects/items/whistle.dm
@@ -4,13 +4,13 @@
desc = "A metal pea-whistle. Can be blown while held, or worn in the mouth"
icon_state = "whistle"
w_class = WEIGHT_CLASS_TINY
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_MASK
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_MASK
actions_types = list(/datum/action/item_action) // RUTGMC ADDITION
var/volume = 60
- var/spamcheck = FALSE
-
+ /// The range in tiles which whistle makes people warcry
+ var/warcryrange = 5
/obj/item/whistle/attack_self(mob/user)
. = ..()
@@ -19,6 +19,8 @@
/obj/item/whistle/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(user.wear_mask == src)
whistle_playsound(user)
@@ -33,14 +35,22 @@
/obj/item/whistle/proc/whistle_playsound(mob/user as mob)
- if (spamcheck)
+ if(TIMER_COOLDOWN_CHECK(user, COOLDOWN_WHISTLE_BLOW))
+ user.balloon_alert(user, "Catch your breath!")
return
user.visible_message(span_warning("[user] blows into [src]!"))
playsound(get_turf(src), 'sound/items/whistle.ogg', volume, 1)
- spamcheck = TRUE
- addtimer(VARSET_CALLBACK(src, spamcheck, FALSE), 3 SECONDS)
+ if(TIMER_COOLDOWN_CHECK(user, COOLDOWN_WHISTLE_WARCRY))
+ to_chat(user, span_notice("You have to wait a while to rally your troops..."))
+ else
+ TIMER_COOLDOWN_START(user, COOLDOWN_WHISTLE_WARCRY, 1 MINUTES)
+ for(var/mob/living/carbon/human/human in get_hearers_in_view(warcryrange, user.loc))
+ human.emote("warcry", intentional = TRUE)
+ CHECK_TICK
+
+ TIMER_COOLDOWN_START(user, COOLDOWN_WHISTLE_BLOW, 3 SECONDS)
/obj/item/hailer
@@ -50,7 +60,7 @@
icon_state = "voice"
item_state = "flashbang" //looks exactly like a flash (and nothing like a flashbang)
w_class = WEIGHT_CLASS_TINY
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
var/spamcheck = FALSE
diff --git a/code/game/objects/machinery.dm b/code/game/objects/machinery.dm
index 48d31828ec5b4..128167ac8f5a0 100644
--- a/code/game/objects/machinery.dm
+++ b/code/game/objects/machinery.dm
@@ -30,7 +30,7 @@
component_parts = list()
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
/obj/machinery/Destroy()
@@ -41,7 +41,7 @@
operator = null
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom &= ~ AI_BLOCKED
+ current_turf.atom_flags &= ~ AI_BLOCKED
return ..()
/obj/machinery/proc/is_operational()
@@ -49,7 +49,7 @@
/obj/machinery/proc/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel = 0, custom_deconstruct = FALSE)
- . = !(flags_atom & NODECONSTRUCT) && crowbar.tool_behaviour == TOOL_CROWBAR
+ . = !(atom_flags & NODECONSTRUCT) && crowbar.tool_behaviour == TOOL_CROWBAR
if(!. || custom_deconstruct)
return
crowbar.play_tool_sound(src, 50)
@@ -65,7 +65,7 @@
return TRUE
/obj/machinery/deconstruct(disassembled = TRUE)
- if(!(flags_atom & NODECONSTRUCT))
+ if(!(atom_flags & NODECONSTRUCT))
on_deconstruction()
if(length(component_parts))
spawn_frame(disassembled)
diff --git a/code/game/objects/machinery/OpTable.dm b/code/game/objects/machinery/OpTable.dm
index 025803c3397bd..3920ff5fb5420 100644
--- a/code/game/objects/machinery/OpTable.dm
+++ b/code/game/objects/machinery/OpTable.dm
@@ -188,6 +188,8 @@
/obj/machinery/optable/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tank/anesthetic))
if(anes_tank)
@@ -196,32 +198,33 @@
anes_tank = I
to_chat(user, span_notice("You connect \the [anes_tank] to \the [src]."))
- if(!istype(I, /obj/item/grab))
+/obj/machinery/optable/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
return
-
- var/obj/item/grab/G = I
- if(victim && victim != G.grabbed_thing)
+ if(victim && victim != grab.grabbed_thing)
to_chat(user, span_warning("The table is already occupied!"))
return
- var/mob/living/carbon/M
- if(iscarbon(G.grabbed_thing))
- M = G.grabbed_thing
- if(M.buckled)
+ var/mob/living/carbon/grabbed_mob
+ if(iscarbon(grab.grabbed_thing))
+ grabbed_mob = grab.grabbed_thing
+ if(grabbed_mob.buckled)
to_chat(user, span_warning("Unbuckle first!"))
return
- else if(istype(G.grabbed_thing, /obj/structure/closet/bodybag/cryobag))
- var/obj/structure/closet/bodybag/cryobag/C = G.grabbed_thing
- if(!C.bodybag_occupant)
+ else if(istype(grab.grabbed_thing, /obj/structure/closet/bodybag/cryobag))
+ var/obj/structure/closet/bodybag/cryobag/cryobag = grab.grabbed_thing
+ if(!cryobag.bodybag_occupant)
return
- M = C.bodybag_occupant
- C.open()
+ grabbed_mob = cryobag.bodybag_occupant
+ cryobag.open()
user.stop_pulling()
- user.start_pulling(M)
+ user.start_pulling(grabbed_mob)
- if(!M)
+ if(!grabbed_mob)
return
- take_victim(M, user)
+ take_victim(grabbed_mob, user)
+ return TRUE
/obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob)
if(victim)
diff --git a/code/game/objects/machinery/adv_med.dm b/code/game/objects/machinery/adv_med.dm
index 95063a17355ec..52f96cd5af02b 100644
--- a/code/game/objects/machinery/adv_med.dm
+++ b/code/game/objects/machinery/adv_med.dm
@@ -32,6 +32,7 @@
set_light(initial(light_range))
/obj/machinery/bodyscanner/update_icon_state()
+ . = ..()
if(occupant)
icon_state = "[initial(icon_state)]_occupied"
else
@@ -107,57 +108,59 @@
return
go_out()
-
/obj/machinery/bodyscanner/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/healthanalyzer) && occupant) //Allows us to use the analyzer on the occupant without taking him out; this is here mainly for consistency's sake.
var/obj/item/healthanalyzer/J = I
J.attack(occupant, user)
return
- var/mob/M
- if(!istype(I, /obj/item/grab))
+/obj/machinery/bodyscanner/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
return
-
- else if(occupant)
+ if(occupant)
to_chat(user, span_warning("The scanner is already occupied!"))
return
- var/obj/item/grab/G = I
- if(istype(G.grabbed_thing,/obj/structure/closet/bodybag/cryobag))
- var/obj/structure/closet/bodybag/cryobag/C = G.grabbed_thing
- if(!C.bodybag_occupant)
+ var/mob/grabbed_mob
+ if(ismob(grab.grabbed_thing))
+ grabbed_mob = grab.grabbed_thing
+ else if(istype(grab.grabbed_thing, /obj/structure/closet/bodybag/cryobag))
+ var/obj/structure/closet/bodybag/cryobag/cryobag = grab.grabbed_thing
+ if(!cryobag.bodybag_occupant)
to_chat(user, span_warning("The stasis bag is empty!"))
return
- M = C.bodybag_occupant
- C.open()
- user.start_pulling(M)
- else if(ismob(G.grabbed_thing))
- M = G.grabbed_thing
+ grabbed_mob = cryobag.bodybag_occupant
+ cryobag.open()
+ user.start_pulling(grabbed_mob)
- if(!M)
+ if(!grabbed_mob)
return
- if(M.abiotic())
+ if(grabbed_mob.abiotic())
to_chat(user, span_warning("Subject cannot have abiotic items on."))
return
- M.forceMove(src)
- occupant = M
+ grabbed_mob.forceMove(src)
+ occupant = grabbed_mob
update_icon()
for(var/obj/O in src)
O.forceMove(loc)
+ return TRUE
-/obj/machinery/bodyscanner/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/bodyscanner/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
+ visible_message(span_warning("[xeno_attacker] begins to pry the [src]'s cover!"), 3)
playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(!do_after(xeno_attacker, 2 SECONDS))
return
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
go_out()
diff --git a/code/game/objects/machinery/air_alarm.dm b/code/game/objects/machinery/air_alarm.dm
index e644e46a4e20c..ea737f7f2af5d 100644
--- a/code/game/objects/machinery/air_alarm.dm
+++ b/code/game/objects/machinery/air_alarm.dm
@@ -36,6 +36,7 @@
set_light(initial(light_range))
/obj/machinery/air_alarm/update_icon_state()
+ . = ..()
if(machine_stat & (NOPOWER|BROKEN))
icon_state = "alarm_unpowered"
else
diff --git a/code/game/objects/machinery/autodoc.dm b/code/game/objects/machinery/autodoc.dm
index 5fc73f11f9685..4bd4fc7ab1a1c 100644
--- a/code/game/objects/machinery/autodoc.dm
+++ b/code/game/objects/machinery/autodoc.dm
@@ -105,6 +105,7 @@
set_light(initial(light_range))
/obj/machinery/autodoc/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "autodoc_off"
else if(surgery)
@@ -193,15 +194,15 @@
if(updating_health)
occupant.updatehealth()
-/obj/machinery/autodoc/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/autodoc/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
+ visible_message(span_warning("[xeno_attacker] begins to pry the [src]'s cover!"), 3)
playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(!do_after(xeno_attacker, 2 SECONDS))
return
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
go_out()
@@ -851,6 +852,8 @@
/obj/machinery/autodoc/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!ishuman(user))
return // no
@@ -870,67 +873,63 @@
J.attack(occupant, user)
return
- else if(!istype(I, /obj/item/grab))
+/obj/machinery/autodoc/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ return
+ if(!ishuman(user))
return
-
if(machine_stat & (NOPOWER|BROKEN))
- to_chat(user, span_notice("[src] is non-functional!"))
+ to_chat(user, span_notice("\ [src] is non-functional!"))
return
- else if(occupant)
- to_chat(user, span_notice("[src] is already occupied!"))
+ if(occupant)
+ to_chat(user, span_notice("\ [src] is already occupied!"))
return
- if(!istype(I, /obj/item/grab))
- return
+ var/mob/grabbed_mob
- var/obj/item/grab/G = I
+ if(ismob(grab.grabbed_thing))
+ grabbed_mob = grab.grabbed_thing
- var/mob/M
- if(ismob(G.grabbed_thing))
- M = G.grabbed_thing
- else if(istype(G.grabbed_thing, /obj/structure/closet/bodybag/cryobag))
- var/obj/structure/closet/bodybag/cryobag/C = G.grabbed_thing
- if(!C.bodybag_occupant)
+ else if(istype(grab.grabbed_thing,/obj/structure/closet/bodybag/cryobag))
+ var/obj/structure/closet/bodybag/cryobag/cryobag = grab.grabbed_thing
+ if(!cryobag.bodybag_occupant)
to_chat(user, span_warning("The stasis bag is empty!"))
return
- M = C.bodybag_occupant
- C.open()
- user.start_pulling(M)
+ grabbed_mob = cryobag.bodybag_occupant
+ cryobag.open()
+ user.start_pulling(grabbed_mob)
-
- if(!M)
- return
-
- else if(!ishuman(M)) // stop fucking monkeys and xenos being put in. // MONKEEY IS FREE
- to_chat(user, span_notice("[src] is compatible with humanoid anatomies only!"))
+ if(!ishuman(grabbed_mob))
+ to_chat(user, span_notice("\ [src] is compatible with humanoid anatomies only!"))
return
- else if(M.abiotic())
+ if(grabbed_mob.abiotic())
to_chat(user, span_warning("Subject cannot have abiotic items on."))
return
if(user.skills.getRating(SKILL_SURGERY) < SKILL_SURGERY_TRAINED && !event)
- user.visible_message(span_notice("[user] fumbles around figuring out how to put [M] into [src]."),
- span_notice("You fumble around figuring out how to put [M] into [src]."))
+ user.visible_message(span_notice("[user] fumbles around figuring out how to put [grabbed_mob] into [src]."),
+ span_notice("You fumble around figuring out how to put [grabbed_mob] into [src]."))
var/fumbling_time = max(0 , SKILL_TASK_TOUGH - ( SKILL_TASK_EASY * user.skills.getRating(SKILL_SURGERY) ))// 8 secs non-trained, 5 amateur
- if(!do_after(user, fumbling_time, NONE, M, BUSY_ICON_UNSKILLED) || QDELETED(src))
+ if(!do_after(user, fumbling_time, NONE, grabbed_mob, BUSY_ICON_UNSKILLED) || QDELETED(src))
return
- visible_message("[user] starts putting [M] into [src].", 3)
+ visible_message("[user] starts putting [grabbed_mob] into [src].", 3)
- if(!do_after(user, 10, IGNORE_HELD_ITEM, M, BUSY_ICON_GENERIC) || QDELETED(src))
+ if(!do_after(user, 10, IGNORE_HELD_ITEM, grabbed_mob, BUSY_ICON_GENERIC) || QDELETED(src))
return
if(occupant)
to_chat(user, span_notice("[src] is already occupied!"))
return
- if(!M || !G)
+ if(!grabbed_mob || !grab)
return
- M.forceMove(src)
- occupant = M
+ grabbed_mob.forceMove(src)
+ occupant = grabbed_mob
update_icon()
var/implants = list(/obj/item/implant/neurostim)
var/mob/living/carbon/human/H = occupant
@@ -941,6 +940,7 @@
say("Automatic mode engaged, initialising procedures.")
addtimer(CALLBACK(src, PROC_REF(auto_start)), 5 SECONDS)
+ return TRUE
/////////////////////////////////////////////////////////////
diff --git a/code/game/objects/machinery/bioprinter.dm b/code/game/objects/machinery/bioprinter.dm
index d58009e2896a4..27bd83acc06e4 100644
--- a/code/game/objects/machinery/bioprinter.dm
+++ b/code/game/objects/machinery/bioprinter.dm
@@ -58,6 +58,8 @@
/obj/machinery/bioprinter/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/glass/beaker))
var/obj/item/reagent_containers/glass/beaker/B = I
if(B.reagents.has_reagent(/datum/reagent/medicine/biomass, 30))
@@ -83,6 +85,7 @@
. += "It has [stored_matter] matter and [stored_metal] metal left."
/obj/machinery/bioprinter/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "bioprinter_off"
return
diff --git a/code/game/objects/machinery/buttons.dm b/code/game/objects/machinery/buttons.dm
index 892b33cfe2a4d..183f3bc09e4c9 100644
--- a/code/game/objects/machinery/buttons.dm
+++ b/code/game/objects/machinery/buttons.dm
@@ -27,6 +27,7 @@
/obj/machinery/button/update_icon_state()
+ . = ..()
if(machine_stat & (NOPOWER|BROKEN))
icon_state = "[initial(icon_state)]-p"
else
@@ -123,7 +124,7 @@
/obj/machinery/button/door/open_only/landing_zone/Initialize(mapload)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/obj/machinery/button/door/open_only/landing_zone/attack_hand(mob/living/user)
if((machine_stat & (NOPOWER|BROKEN)))
@@ -249,6 +250,7 @@
update_icon()
/obj/machinery/medical_help_button/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "doorctrl-p"
else
@@ -283,7 +285,7 @@
///The list of outfits we can equip on the humans we're spawning
var/outfit_list = list()
-/obj/machinery/button/valhalla/xeno_button/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/button/valhalla/xeno_button/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
var/list/job_outfits = list()
for(var/type in subtypesof(/datum/outfit/job))
if(istype(type, /datum/outfit))
@@ -301,7 +303,7 @@
QDEL_NULL(linked)
if(!get_turf(GLOB.valhalla_button_spawn_landmark[link]))
- to_chat(X, span_warning("An error occured, yell at the coders."))
+ to_chat(xeno_attacker, span_warning("An error occured, yell at the coders."))
CRASH("Valhalla button linked with an improper landmark: button ID: [link].")
linked = new /mob/living/carbon/human(get_turf(GLOB.valhalla_button_spawn_landmark[link]))
if(selected_outfit == "Naked" || !selected_outfit)
diff --git a/code/game/objects/machinery/camera/camera.dm b/code/game/objects/machinery/camera/camera.dm
index 1d8cd4c61ea98..44133deb5e1d7 100644
--- a/code/game/objects/machinery/camera/camera.dm
+++ b/code/game/objects/machinery/camera/camera.dm
@@ -93,6 +93,8 @@
/obj/machinery/camera/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper) && isliving(user))
var/mob/living/U = user
@@ -164,16 +166,16 @@
return TRUE
-/obj/machinery/camera/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/camera/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(obj_integrity <= 0)
- to_chat(X, span_warning("The camera is already disabled."))
+ to_chat(xeno_attacker, span_warning("The camera is already disabled."))
return
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- X.visible_message(span_danger("[X] slashes \the [src]!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] slashes \the [src]!"), \
span_danger("We slash \the [src]!"))
playsound(loc, "alien_claw_metal", 25, 1)
@@ -218,6 +220,7 @@
to_chat(AI, span_notice("[src] has been deactivated at [myarea]"))
/obj/machinery/camera/update_icon_state()
+ . = ..()
if(obj_integrity <= 0)
icon_state = "camera_assembly"
else
@@ -402,10 +405,6 @@
/obj/machinery/camera/autoname/lz_camera/ex_act()
return
-
-/obj/machinery/camera/autoname/lz_camera/update_icon()
- return
-
//Thunderdome cameras
/obj/machinery/camera/autoname/thunderdome
name = "thunderdome camera"
@@ -415,5 +414,6 @@
//Special invisible cameras, to get even better angles without looking ugly
/obj/machinery/camera/autoname/thunderdome/hidden
-/obj/machinery/camera/autoname/thunderdome/hidden/update_icon()
+/obj/machinery/camera/autoname/thunderdome/hidden/update_icon_state()
+ . = ..()
icon_state = "nothing"
diff --git a/code/game/objects/machinery/camera/camera_assembly.dm b/code/game/objects/machinery/camera/camera_assembly.dm
index d1a4e5005cf07..adb5fa8d7c988 100644
--- a/code/game/objects/machinery/camera/camera_assembly.dm
+++ b/code/game/objects/machinery/camera/camera_assembly.dm
@@ -81,6 +81,8 @@
/obj/structure/camera_assembly/attackby(obj/item/I, mob/living/user, params)
. = ..()
+ if(.)
+ return
switch(state)
if(STATE_WRENCHED)
@@ -173,7 +175,7 @@
/obj/structure/camera_assembly/deconstruct(disassembled = TRUE)
- if(!(flags_atom & NODECONSTRUCT))
+ if(!(atom_flags & NODECONSTRUCT))
new /obj/item/stack/sheet/metal(loc)
return ..()
diff --git a/code/game/objects/machinery/camera/deployable_camera.dm b/code/game/objects/machinery/camera/deployable_camera.dm
index 35e5791b33476..58058623dff2e 100644
--- a/code/game/objects/machinery/camera/deployable_camera.dm
+++ b/code/game/objects/machinery/camera/deployable_camera.dm
@@ -7,7 +7,8 @@ GLOBAL_VAR_INIT(deployed_cameras, 0)
icon_state = "deployable"
layer = ABOVE_ALL_MOB_LAYER//it flies after all
-/obj/machinery/camera/deployable/update_icon()
+/obj/machinery/camera/deployable/update_icon_state()
+ . = ..()
if(obj_integrity <= 0)
icon_state = "deployableoff"
else
diff --git a/code/game/objects/machinery/cell_charger.dm b/code/game/objects/machinery/cell_charger.dm
index 04bd92eb0c891..d7149a4024b3e 100644
--- a/code/game/objects/machinery/cell_charger.dm
+++ b/code/game/objects/machinery/cell_charger.dm
@@ -37,6 +37,8 @@
/obj/machinery/cell_charger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(machine_stat & BROKEN)
return
diff --git a/code/game/objects/machinery/cic_maptable.dm b/code/game/objects/machinery/cic_maptable.dm
index dafadd77d288f..af9ccd28672e9 100644
--- a/code/game/objects/machinery/cic_maptable.dm
+++ b/code/game/objects/machinery/cic_maptable.dm
@@ -145,17 +145,16 @@
. = ..()
if(.)
return
- if(user.skills.getRating(SKILL_LEADERSHIP) < SKILL_LEAD_EXPERT)
- user.balloon_alert(user, "Can't use that!")
- return TRUE
- if(is_banned_from(user.client.ckey, GLOB.roles_allowed_minimap_draw))
- to_chat(user, span_boldwarning("You have been banned from a command role. You may not use [src] until the ban has been lifted."))
- return TRUE
/obj/machinery/cic_maptable/drawable/interact(mob/user)
. = ..()
if(.)
return
+ if(user.skills.getRating(SKILL_LEADERSHIP) < SKILL_LEAD_EXPERT)
+ return
+ if(is_banned_from(user.client.ckey, GLOB.roles_allowed_minimap_draw))
+ to_chat(user, span_boldwarning("You have been banned from a command role. You may not use access draw functions until the ban has been lifted."))
+ return
user.client.screen += drawing_tools
/obj/machinery/cic_maptable/drawable/on_unset_interaction(mob/user)
@@ -179,7 +178,15 @@
pixel_x = -16
pixel_y = -14
coverage = 75
- allow_pass_flags = PASS_LOW_STRUCTURE|PASSABLE
+ allow_pass_flags = PASS_LOW_STRUCTURE|PASSABLE|PASS_WALKOVER
+ bound_width = 64
+
+/obj/machinery/cic_maptable/drawable/big/Initialize(mapload)
+ . = ..()
+ var/static/list/connections = list(
+ COMSIG_OBJ_TRY_ALLOW_THROUGH = PROC_REF(can_climb_over),
+ )
+ AddElement(/datum/element/connect_loc, connections)
/obj/machinery/cic_maptable/drawable/big/som
minimap_flag = MINIMAP_FLAG_MARINE_SOM
diff --git a/code/game/objects/machinery/cloning/cloning.dm b/code/game/objects/machinery/cloning/cloning.dm
index 52d2f5c33563d..6aebe9b342b10 100644
--- a/code/game/objects/machinery/cloning/cloning.dm
+++ b/code/game/objects/machinery/cloning/cloning.dm
@@ -207,6 +207,7 @@ These act as a respawn mechanic growning a body and offering it up to ghosts.
set_light(0)
/obj/machinery/cloning/vats/update_icon_state()
+ . = ..()
if(!beaker)
icon_state = "cell_0"
return
diff --git a/code/game/objects/machinery/computer/HolodeckControl.dm b/code/game/objects/machinery/computer/HolodeckControl.dm
index 0e1cc11d0e497..0c1b155dbf38a 100644
--- a/code/game/objects/machinery/computer/HolodeckControl.dm
+++ b/code/game/objects/machinery/computer/HolodeckControl.dm
@@ -15,23 +15,8 @@
/obj/structure/table/holotable/attackby(obj/item/I, mob/user, params)
if(iswrench(I))
to_chat(user, "It's a holotable! There are no bolts!")
-
- else if(istype(I, /obj/item/grab) && get_dist(src, user) <= 1)
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/L = G.grabbed_thing
- if(user.grab_state < GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
-
- L.forceMove(loc)
- L.Paralyze(10 SECONDS)
- user.visible_message(span_danger("[user] puts [L] on the table."))
-
- else
- return ..()
+ return
+ return ..()
/obj/structure/table/holotable/wood
name = "table"
@@ -49,7 +34,7 @@
density = TRUE
layer = WINDOW_LAYER
anchored = TRUE
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
@@ -63,60 +48,7 @@
desc = "Here's your chance, do your dance at the Space Jam."
w_class = WEIGHT_CLASS_BULKY //Stops people from hiding it in their bags/pockets
-/obj/item/toy/beach_ball/holoball/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/item/toy/beach_ball/holoball/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!CONFIG_GET(flag/fun_allowed))
return FALSE
- attack_hand(X)
-
-/obj/structure/holohoop
- name = "basketball hoop"
- desc = "Boom, Shakalaka!"
- icon = 'icons/obj/structures/misc.dmi'
- icon_state = "hoop"
- anchored = TRUE
- density = TRUE
- var/side = ""
- var/id = ""
-
-/obj/structure/holohoop/attackby(obj/item/I, mob/user, params)
- . = ..()
-
- if(istype(I, /obj/item/grab) && get_dist(src, user) <= 1)
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/L = G.grabbed_thing
- if(user.grab_state < GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
- L.forceMove(loc)
- L.Paralyze(10 SECONDS)
- for(var/obj/machinery/scoreboard/X in GLOB.machines)
- if(X.id == id)
- X.score(side, 3)// 3 points for dunking a mob
- // no break, to update multiple scoreboards
- visible_message(span_danger("[user] dunks [L] into the [src]!"))
-
- else if(get_dist(src, user) < 2)
- user.transferItemToLoc(I, loc)
- for(var/obj/machinery/scoreboard/X in GLOB.machines)
- if(X.id == id)
- X.score(side)
- visible_message(span_notice("[user] dunks [I] into the [src]!"))
-
-/obj/structure/holohoop/CanAllowThrough(atom/movable/mover, turf/target)
- if(istype(mover,/obj/item) && mover.throwing)
- var/obj/item/I = mover
- if(prob(50))
- I.loc = src.loc
- for(var/obj/machinery/scoreboard/X in GLOB.machines)
- if(X.id == id)
- X.score(side)
- // no break, to update multiple scoreboards
- visible_message(span_notice(" Swish! \the [I] lands in \the [src]."), 3)
- else
- visible_message(span_warning(" \the [I] bounces off of \the [src]'s rim!"), 3)
- return FALSE
- else
- return ..()
+ attack_hand(xeno_attacker)
diff --git a/code/game/objects/machinery/computer/Operating.dm b/code/game/objects/machinery/computer/Operating.dm
index 1b448c2727959..00b0cc34210af 100644
--- a/code/game/objects/machinery/computer/Operating.dm
+++ b/code/game/objects/machinery/computer/Operating.dm
@@ -30,7 +30,7 @@
Name: [src.victim.real_name] Age: [src.victim.age]
-Blood Type: [src.victim.b_type]
+Blood Type: [src.victim.blood_type]
Health: [src.victim.health] Brute Damage: [src.victim.getBruteLoss()]
diff --git a/code/game/objects/machinery/computer/buildandrepair.dm b/code/game/objects/machinery/computer/buildandrepair.dm
index f1f77d2fb4e78..857acbbbdf916 100644
--- a/code/game/objects/machinery/computer/buildandrepair.dm
+++ b/code/game/objects/machinery/computer/buildandrepair.dm
@@ -26,7 +26,7 @@
return
playsound(loc, 'sound/items/welder.ogg', 25, 1)
- if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return FALSE
to_chat(user, span_notice("You deconstruct the frame."))
diff --git a/code/game/objects/machinery/computer/camera_advanced.dm b/code/game/objects/machinery/computer/camera_advanced.dm
index 8099fb2f152b1..61abeeb0a785c 100644
--- a/code/game/objects/machinery/computer/camera_advanced.dm
+++ b/code/game/objects/machinery/computer/camera_advanced.dm
@@ -242,7 +242,6 @@
var/visible_icon = 0
var/image/user_image = null
-
/mob/camera/aiEye/remote/update_remote_sight(mob/living/user)
user.see_invisible = SEE_INVISIBLE_LIVING
user.sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS|SEE_BLACKNESS
diff --git a/code/game/objects/machinery/computer/camera_console.dm b/code/game/objects/machinery/computer/camera_console.dm
index a86c34b9a2ad3..b717b0c6e2765 100644
--- a/code/game/objects/machinery/computer/camera_console.dm
+++ b/code/game/objects/machinery/computer/camera_console.dm
@@ -169,6 +169,7 @@
/obj/machinery/computer/security/telescreen/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(machine_stat & (BROKEN|DISABLED))
icon_state += "b"
diff --git a/code/game/objects/machinery/computer/communications.dm b/code/game/objects/machinery/computer/communications.dm
index fdc1537a07a14..c797fe1cc4e12 100644
--- a/code/game/objects/machinery/computer/communications.dm
+++ b/code/game/objects/machinery/computer/communications.dm
@@ -118,7 +118,7 @@
to_chat(usr, span_warning("That announcement contained charachters prohibited in IC chat! Consider reviewing the server rules."))
return FALSE
- priority_announce(input, type = ANNOUNCEMENT_COMMAND)
+ priority_announce(input, subtitle = "Sent by [usr]", type = ANNOUNCEMENT_COMMAND)
message_admins("[ADMIN_TPMONTY(usr)] has just sent a command announcement")
log_game("[key_name(usr)] has just sent a command announcement.")
cooldown_message = world.time
@@ -149,11 +149,11 @@
to_chat(usr, span_warning("The ship must be under red alert in order to enact evacuation procedures."))
return FALSE
- if(SSevacuation.flags_scuttle & FLAGS_SDEVAC_TIMELOCK)
+ if(SSevacuation.scuttle_flags & FLAGS_SDEVAC_TIMELOCK)
to_chat(usr, span_warning("The sensors do not detect a sufficient threat present."))
return FALSE
- if(SSevacuation.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SSevacuation.scuttle_flags & FLAGS_EVACUATION_DENY)
to_chat(usr, span_warning("The TGMC has placed a lock on deploying the evacuation pods."))
return FALSE
@@ -172,7 +172,7 @@
state = STATE_EVACUATION
- if("evacuation_cancel")
+ if("delta_cancel")
if(state == STATE_EVACUATION_CANCEL)
if(!SSevacuation.cancel_evacuation())
to_chat(usr, span_warning("You are unable to cancel the evacuation right now!"))
@@ -356,7 +356,7 @@
dat += " \[ Send Distress Beacon \]"
switch(SSevacuation.evac_status)
if(EVACUATION_STATUS_STANDING_BY) dat += " \[ Initiate emergency evacuation \]"
- if(EVACUATION_STATUS_INITIATING) dat += " \[ Cancel emergency evacuation \]"
+ if(EVACUATION_STATUS_INITIATING) dat += " \[ Cancel Delta Alert \]"
else
dat += " \[ LOG IN \]"
@@ -365,7 +365,7 @@
dat += "Are you sure you want to evacuate the [SSmapping.configs[SHIP_MAP].map_name]? \[ Confirm\]"
if(STATE_EVACUATION_CANCEL)
- dat += "Are you sure you want to cancel the evacuation of the [SSmapping.configs[SHIP_MAP].map_name]? \[ Confirm\]"
+ dat += "Are you sure you want to cancel Delta Alert and prevent the evacuation and/or self destruction of the [SSmapping.configs[SHIP_MAP].map_name]? \[ Confirm\]"
if(STATE_DISTRESS)
if(CONFIG_GET(flag/infestation_ert_allowed))
diff --git a/code/game/objects/machinery/computer/computer.dm b/code/game/objects/machinery/computer/computer.dm
index 85e1b1db479cb..286c5a5279843 100644
--- a/code/game/objects/machinery/computer/computer.dm
+++ b/code/game/objects/machinery/computer/computer.dm
@@ -103,6 +103,7 @@
set_light(initial(light_range))
/obj/machinery/computer/update_icon_state()
+ . = ..()
if(machine_stat & (BROKEN|DISABLED))
icon_state = "[initial(icon_state)]_broken"
else
@@ -140,10 +141,10 @@
if(!welder.tool_use_check(user, 2))
return FALSE
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER)
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_EXPERT)
user.visible_message(span_notice("[user] fumbles around figuring out how to deconstruct [src]."),
span_notice("You fumble around figuring out how to deconstruct [src]."))
- var/fumbling_time = 5 SECONDS * (SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER))
+ var/fumbling_time = 5 SECONDS * (SKILL_ENGINEER_EXPERT - user.skills.getRating(SKILL_ENGINEER))
if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
return
@@ -167,12 +168,14 @@
/obj/machinery/computer/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && circuit)
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER)
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_EXPERT)
user.visible_message(span_notice("[user] fumbles around figuring out how to deconstruct [src]."),
span_notice("You fumble around figuring out how to deconstruct [src]."))
- var/fumbling_time = 50 * ( SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER) )
+ var/fumbling_time = 50 * ( SKILL_ENGINEER_EXPERT - user.skills.getRating(SKILL_ENGINEER) )
if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
return
@@ -217,25 +220,25 @@
pick(playsound(src, 'sound/machines/computer_typing1.ogg', 5, 1), playsound(src, 'sound/machines/computer_typing2.ogg', 5, 1), playsound(src, 'sound/machines/computer_typing3.ogg', 5, 1))
///So Xenos can smash computers out of the way without actually breaking them
-/obj/machinery/computer/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/computer/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(resistance_flags & INDESTRUCTIBLE)
- to_chat(X, span_xenowarning("We're unable to damage this!"))
+ to_chat(xeno_attacker, span_xenowarning("We're unable to damage this!"))
return
if(machine_stat & (BROKEN|DISABLED)) //If we're already broken or disabled, don't bother
- to_chat(X, span_xenowarning("This peculiar thing is already broken!"))
+ to_chat(xeno_attacker, span_xenowarning("This peculiar thing is already broken!"))
return
if(durability <= 0)
set_disabled()
- to_chat(X, span_xenowarning("We smash the annoying device, disabling it!"))
+ to_chat(xeno_attacker, span_xenowarning("We smash the annoying device, disabling it!"))
else
durability--
- to_chat(X, span_xenowarning("We smash the annoying device!"))
+ to_chat(xeno_attacker, span_xenowarning("We smash the annoying device!"))
- X.do_attack_animation(src, ATTACK_EFFECT_DISARM2) //SFX
- playsound(loc, pick('sound/effects/bang.ogg','sound/effects/metal_crash.ogg','sound/effects/meteorimpact.ogg'), 25, 1) //SFX
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_DISARM2) //SFxeno_attacker
+ playsound(loc, pick('sound/effects/bang.ogg','sound/effects/metal_crash.ogg','sound/effects/meteorimpact.ogg'), 25, 1) //SFxeno_attacker
Shake(duration = 0.5 SECONDS)
diff --git a/code/game/objects/machinery/computer/dropship_weapons.dm b/code/game/objects/machinery/computer/dropship_weapons.dm
index 8a67d9eecac0a..463df4e343ac8 100644
--- a/code/game/objects/machinery/computer/dropship_weapons.dm
+++ b/code/game/objects/machinery/computer/dropship_weapons.dm
@@ -7,6 +7,7 @@
icon_state = "consoleright"
screen_overlay = "consoleright_emissive"
circuit = null
+ opacity = FALSE
resistance_flags = RESIST_ALL
interaction_flags = INTERACT_MACHINE_TGUI
var/shuttle_tag // Used to know which shuttle we're linked to.
diff --git a/code/game/objects/machinery/computer/intel_computer.dm b/code/game/objects/machinery/computer/intel_computer.dm
index 99effa1e947a2..38dbdde62acc5 100644
--- a/code/game/objects/machinery/computer/intel_computer.dm
+++ b/code/game/objects/machinery/computer/intel_computer.dm
@@ -53,7 +53,7 @@
printing_complete = TRUE
SSpoints.supply_points[faction] += supply_reward
SSpoints.dropship_points += dropship_reward
- priority_announce("Classified transmission recieved from [get_area(src)]. Bonus delivered as [supply_reward] supply points and [dropship_reward] dropship points.", title = "TGMC Intel Division")
+ minor_announce("Classified transmission recieved from [get_area(src)]. Bonus delivered as [supply_reward] supply points and [dropship_reward] dropship points.", title = "TGMC Intel Division")
SSminimaps.remove_marker(src)
/obj/machinery/computer/intel_computer/Destroy()
diff --git a/code/game/objects/machinery/computer/marines_consoles.dm b/code/game/objects/machinery/computer/marines_consoles.dm
index a8dced845cecd..61840a74f8f78 100644
--- a/code/game/objects/machinery/computer/marines_consoles.dm
+++ b/code/game/objects/machinery/computer/marines_consoles.dm
@@ -15,6 +15,8 @@
/obj/machinery/computer/marine_card/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
var/obj/item/card/id/idcard = I
@@ -352,6 +354,8 @@
/obj/machinery/computer/squad_changer/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
var/obj/item/card/id/idcard = I
diff --git a/code/game/objects/machinery/computer/medical.dm b/code/game/objects/machinery/computer/medical.dm
index 78e6f3fa59f85..397558576d355 100644
--- a/code/game/objects/machinery/computer/medical.dm
+++ b/code/game/objects/machinery/computer/medical.dm
@@ -35,6 +35,8 @@
/obj/machinery/computer/med_data/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id) && !scan)
if(!user.drop_held_item())
diff --git a/code/game/objects/machinery/computer/nt_access.dm b/code/game/objects/machinery/computer/nt_access.dm
index 5e7724d4ff679..028e05a0f174f 100644
--- a/code/game/objects/machinery/computer/nt_access.dm
+++ b/code/game/objects/machinery/computer/nt_access.dm
@@ -1,4 +1,5 @@
// -- generate override code computer
+//TODO: Make a parent computer to remove all the nuke disk copy paste
/obj/item/circuitboard/computer/nt_access
name = "circuit board (nuke disk generator)"
build_path = /obj/machinery/computer/nt_access
@@ -15,11 +16,9 @@
resistance_flags = INDESTRUCTIBLE|UNACIDABLE
layer = ABOVE_MOB_LAYER
///Time needed for the machine to generate the disc
- var/segment_time = 1.5 MINUTES
+ var/segment_time = 1 MINUTES
///Time to start a segment
- var/start_time = 15 SECONDS
- ///Time to print a disk
- var/printing_time = 15 SECONDS
+ var/start_time = 5 SECONDS
///Total number of times the hack is required
var/total_segments = 5
///What segment we are on, (once this hits total, disk is printed)
@@ -71,7 +70,7 @@
visible_message("[src] shuts down as it loses power. Any running programs will now exit")
/obj/machinery/computer/nt_access/update_icon_state()
- icon_state = initial(icon_state)
+ return
/obj/machinery/computer/nt_access/attackby(obj/item/I, mob/living/user, params)
return attack_hand(user)
@@ -128,13 +127,14 @@
busy = TRUE
usr.visible_message("[usr] started a program to send the [code_color] security override command.", "You started a program to send the [code_color] security override command.")
- if(!do_after(usr, printing_time, NONE, src, BUSY_ICON_GENERIC, null, null, CALLBACK(src, TYPE_PROC_REF(/datum, process))))
+ if(!do_after(usr, start_time, NONE, src, BUSY_ICON_GENERIC, null, null, CALLBACK(src, TYPE_PROC_REF(/datum, process))))
busy = FALSE
return
visible_message(span_notice("[src] beeps as it finishes sending the security override command."))
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_CODE, code_color)
busy = FALSE
+ set_disabled() //stops spamming the signal
return
busy = TRUE
@@ -145,7 +145,7 @@
return
busy = FALSE
-
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_RUNNING, src)
current_timer = addtimer(CALLBACK(src, PROC_REF(complete_segment)), segment_time, TIMER_STOPPABLE)
update_minimap_icon()
running = TRUE
@@ -155,6 +155,7 @@
///Completes a stage of program progress
/obj/machinery/computer/nt_access/proc/complete_segment()
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CAMPAIGN_NT_OVERRIDE_STOP_RUNNING, src)
playsound(src, 'sound/machines/ping.ogg', 25, 1)
deltimer(current_timer)
current_timer = null
diff --git a/code/game/objects/machinery/computer/nuke_disk_generator.dm b/code/game/objects/machinery/computer/nuke_disk_generator.dm
index 7d8c9561be29e..6fe47e59f1bdd 100644
--- a/code/game/objects/machinery/computer/nuke_disk_generator.dm
+++ b/code/game/objects/machinery/computer/nuke_disk_generator.dm
@@ -185,7 +185,7 @@
///Change minimap icon if its on or off
/obj/machinery/computer/nuke_disk_generator/proc/update_minimap_icon()
SSminimaps.remove_marker(src)
- SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, "[disk_color]_disk[current_timer ? "_on" : "_off"]", VERY_HIGH_FLOAT_LAYER))
+ SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, "[disk_color]_disk[current_timer ? "_on" : "_off"]", VERY_HIGH_FLOAT_LAYER)) //RUTGMC EDIT
/obj/machinery/computer/nuke_disk_generator/red
name = "red nuke disk generator"
diff --git a/code/game/objects/machinery/computer/security.dm b/code/game/objects/machinery/computer/security.dm
index 23c3764766787..f26895f72f50f 100644
--- a/code/game/objects/machinery/computer/security.dm
+++ b/code/game/objects/machinery/computer/security.dm
@@ -41,6 +41,8 @@
/obj/machinery/computer/secure_data/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id) && !scan)
if(!user.drop_held_item())
diff --git a/code/game/objects/machinery/computer/skills.dm b/code/game/objects/machinery/computer/skills.dm
index 54cc570ee14c2..3e22e802f9d60 100644
--- a/code/game/objects/machinery/computer/skills.dm
+++ b/code/game/objects/machinery/computer/skills.dm
@@ -23,6 +23,8 @@
/obj/machinery/computer/skills/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id) && !scan)
if(!user.drop_held_item())
diff --git a/code/game/objects/machinery/computer/som_computer.dm b/code/game/objects/machinery/computer/som_computer.dm
index c1c60943a836f..2dcd787e872f6 100644
--- a/code/game/objects/machinery/computer/som_computer.dm
+++ b/code/game/objects/machinery/computer/som_computer.dm
@@ -13,6 +13,7 @@
pixel_y = 10
/obj/machinery/computer/som/update_icon_state()
+ . = ..()
if(machine_stat & (BROKEN|DISABLED))
icon_state = "[initial(icon_state)]_broken"
else if(machine_stat & NOPOWER)
diff --git a/code/game/objects/machinery/constructable_frame.dm b/code/game/objects/machinery/constructable_frame.dm
index 22ef9574cdda1..2a6969c75a236 100644
--- a/code/game/objects/machinery/constructable_frame.dm
+++ b/code/game/objects/machinery/constructable_frame.dm
@@ -10,7 +10,8 @@
var/state = 1
-/obj/machinery/constructable_frame/proc/update_desc()
+/obj/machinery/constructable_frame/update_desc(updates)
+ . = ..()
var/D
if(req_components)
D = "Requires "
@@ -32,10 +33,6 @@
/obj/machinery/constructable_frame/machine_frame/attackby(obj/item/I, mob/living/user, params)
- if(I.crit_fail)
- to_chat(user, span_warning("This part is faulty, you cannot add this to the machine!"))
- return
-
switch(state)
if(1)
if(iscablecoil(I))
diff --git a/code/game/objects/machinery/cryopod.dm b/code/game/objects/machinery/cryopod.dm
index ad6153f93d3e8..8345ffa69f90b 100644
--- a/code/game/objects/machinery/cryopod.dm
+++ b/code/game/objects/machinery/cryopod.dm
@@ -1,3 +1,12 @@
+#define STATE_GUN 0
+#define STATE_AMMO 1
+#define STATE_EXPLOSIVE 2
+#define STATE_MELEE 4
+#define STATE_CLOTHING 5
+#define STATE_FOOD 6
+#define STATE_DRUGS 7
+#define STATE_CONTAINERS 8
+#define STATE_OTHER 9
/obj/machinery/computer/cryopod
name = "hypersleep bay console"
@@ -7,6 +16,7 @@
screen_overlay = "cellconsole_screen"
circuit = /obj/item/circuitboard/computer/cryopodcontrol
resistance_flags = RESIST_ALL
+ var/state = STATE_GUN
/obj/machinery/computer/cryopod/interact(mob/user)
. = ..()
@@ -22,11 +32,81 @@
dat +="
"
dat += ""
var/datum/browser/popup = new(user, "cryopod_console", "
Cryogenics
")
@@ -39,20 +119,80 @@
if(.)
return
+ switch(href_list["operation"])
+ if("gun")
+ state = STATE_GUN
+ if("ammo")
+ state = STATE_AMMO
+ if("explosive")
+ state = STATE_EXPLOSIVE
+ if("melee")
+ state = STATE_MELEE
+ if("clothing")
+ state = STATE_CLOTHING
+ if("food")
+ state = STATE_FOOD
+ if("drug")
+ state = STATE_DRUGS
+ if("container")
+ state = STATE_CONTAINERS
+ if("other")
+ state = STATE_OTHER
+ updateUsrDialog()
+
if(href_list["item"])
- var/obj/item/I = locate(href_list["item"]) in GLOB.cryoed_item_list
+ var/obj/item/I
+ switch(state)
+ if(STATE_GUN)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_gun
+ if(STATE_AMMO)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_ammo
+ if(STATE_EXPLOSIVE)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_explosive
+ if(STATE_MELEE)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_melee
+ if(STATE_CLOTHING)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_clothing
+ if(STATE_FOOD)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_food
+ if(STATE_DRUGS)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_drugs
+ if(STATE_CONTAINERS)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_containers
+ if(STATE_OTHER)
+ I = locate(href_list["item"]) in GLOB.cryoed_item_list_other
dispense_item(I, usr)
else if(href_list["allitems"])
- if(!length(GLOB.cryoed_item_list))
+ if(!length(GLOB.cryoed_item_list_gun) && !length(GLOB.cryoed_item_list_ammo) && !length(GLOB.cryoed_item_list_explosive) && !length(GLOB.cryoed_item_list_melee) && !length(GLOB.cryoed_item_list_clothing) && !length(GLOB.cryoed_item_list_food) && !length(GLOB.cryoed_item_list_drugs) && !length(GLOB.cryoed_item_list_containers) && !length(GLOB.cryoed_item_list_other))
to_chat(usr, span_warning("There is nothing to recover from storage."))
updateUsrDialog()
return
visible_message(span_notice("[src] beeps happily as it disgorges the desired objects."))
- for(var/obj/item/I AS in GLOB.cryoed_item_list)
+ var/list/combined_list
+ switch(state)
+ if(STATE_GUN)
+ combined_list = GLOB.cryoed_item_list_gun
+ if(STATE_AMMO)
+ combined_list = GLOB.cryoed_item_list_ammo
+ if(STATE_EXPLOSIVE)
+ combined_list = GLOB.cryoed_item_list_explosive
+ if(STATE_MELEE)
+ combined_list = GLOB.cryoed_item_list_melee
+ if(STATE_CLOTHING)
+ combined_list = GLOB.cryoed_item_list_clothing
+ if(STATE_FOOD)
+ combined_list = GLOB.cryoed_item_list_food
+ if(STATE_DRUGS)
+ combined_list = GLOB.cryoed_item_list_drugs
+ if(STATE_CONTAINERS)
+ combined_list = GLOB.cryoed_item_list_containers
+ if(STATE_OTHER)
+ combined_list = GLOB.cryoed_item_list_other
+ for(var/obj/item/I in combined_list)
dispense_item(I, usr, FALSE)
updateUsrDialog()
@@ -60,16 +200,35 @@
/obj/machinery/computer/cryopod/proc/dispense_item(obj/item/I, mob/user, message = TRUE)
if(!istype(I) || QDELETED(I))
- GLOB.cryoed_item_list -= I
+ GLOB.cryoed_item_list_gun -= I;
+ GLOB.cryoed_item_list_ammo -= I;
+ GLOB.cryoed_item_list_explosive -= I;
+ GLOB.cryoed_item_list_melee -= I;
+ GLOB.cryoed_item_list_clothing -= I;
+ GLOB.cryoed_item_list_food -= I;
+ GLOB.cryoed_item_list_drugs -= I;
+ GLOB.cryoed_item_list_containers -= I;
+ GLOB.cryoed_item_list_other -= I;
CRASH("Deleted or erroneous variable ([I]) called for hypersleep inventory retrivial.")
- if(!(I in GLOB.cryoed_item_list))
+ if((!I) in (GLOB.cryoed_item_list_gun || GLOB.cryoed_item_list_ammo || GLOB.cryoed_item_list_explosive || GLOB.cryoed_item_list_melee || GLOB.cryoed_item_list_clothing || GLOB.cryoed_item_list_food || GLOB.cryoed_item_list_drugs || GLOB.cryoed_item_list_containers || GLOB.cryoed_item_list_other))
if(message)
to_chat(user, span_warning("[I] is no longer in storage."))
return
if(message)
visible_message(span_notice("[src] beeps happily as it disgorges [I]."))
I.forceMove(get_turf(src))
- GLOB.cryoed_item_list -= I
+ // For when we have south and north facing sprites.
+ // I.forceMove(get_step(loc, dir))
+
+ GLOB.cryoed_item_list_gun -= I;
+ GLOB.cryoed_item_list_ammo -= I;
+ GLOB.cryoed_item_list_explosive -= I;
+ GLOB.cryoed_item_list_melee -= I;
+ GLOB.cryoed_item_list_clothing -= I;
+ GLOB.cryoed_item_list_food -= I;
+ GLOB.cryoed_item_list_drugs -= I;
+ GLOB.cryoed_item_list_containers -= I;
+ GLOB.cryoed_item_list_other -= I;
//Decorative structures to go alongside cryopods.
/obj/structure/cryofeed
@@ -129,6 +288,7 @@
set_light(initial(light_range))
/obj/machinery/cryopod/update_icon_state()
+ . = ..()
if(occupant)
icon_state = "[initial(icon_state)]_occupied"
else
@@ -190,53 +350,56 @@
return ..()
/obj/item/proc/store_in_cryo()
- if(is_type_in_typecache(src, GLOB.do_not_preserve) || HAS_TRAIT(src, TRAIT_NODROP) || (flags_item & (ITEM_ABSTRACT|DELONDROP)))
+ if(is_type_in_typecache(src, GLOB.do_not_preserve) || HAS_TRAIT(src, TRAIT_NODROP) || (item_flags & (ITEM_ABSTRACT|DELONDROP)))
if(!QDELETED(src))
qdel(src)
return
moveToNullspace()
- GLOB.cryoed_item_list += src
+ if(istype(src, /obj/item/weapon/gun))
+ GLOB.cryoed_item_list_gun += src
+ else if(istype(src, /obj/item/ammo_magazine))
+ GLOB.cryoed_item_list_ammo += src
+ else if(istype(src, /obj/item/explosive))
+ GLOB.cryoed_item_list_explosive += src
+ else if(istype(src, /obj/item/weapon))
+ GLOB.cryoed_item_list_melee += src
+ else if(istype(src, /obj/item/clothing))
+ GLOB.cryoed_item_list_clothing += src
+ else if(isfood(src))
+ GLOB.cryoed_item_list_food += src
+ else if(istype(src, /obj/item/reagent_containers/hypospray) || istype(src, /obj/item/reagent_containers/syringe) || istype(src, /obj/item/reagent_containers/pill))
+ GLOB.cryoed_item_list_drugs += src
+ else if(istype(src, /obj/item/storage))
+ GLOB.cryoed_item_list_containers += src
+ else
+ GLOB.cryoed_item_list_other += src
/obj/item/storage/store_in_cryo()
for(var/obj/item/I AS in src)
I.store_in_cryo()
return ..()
-/obj/machinery/cryopod/attackby(obj/item/I, mob/user, params)
+/obj/machinery/cryopod/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
. = ..()
-
- if(!istype(I, /obj/item/grab))
- return
-
- else if(isxeno(user))
- return
-
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
+ if(.)
return
-
- if(!QDELETED(occupant))
- to_chat(user, span_warning("[src] is occupied."))
+ if(isxeno(user))
return
-
- var/mob/living/M = G.grabbed_thing
-
- if(M.stat == DEAD) //This mob is dead
- to_chat(user, span_warning("[src] immediately rejects [M]. [M.p_they(TRUE)] passed away!"))
+ var/mob/living/carbon/human/grabbed_mob = grab.grabbed_thing
+ if(!ishuman(grabbed_mob))
+ to_chat(user, span_warning("There is no way [src] will accept [grabbed_mob]!"))
return
- if(!ishuman(M))
- to_chat(user, span_warning("There is no way [src] will accept [M]!"))
- return
-
- if(M.client)
- if(tgui_alert(M, "Would you like to enter cryosleep?", null, list("Yes", "No")) == "Yes")
- if(QDELETED(M) || !(G?.grabbed_thing == M))
+ if(grabbed_mob.client)
+ if(tgui_alert(grabbed_mob, "Would you like to enter cryosleep?", null, list("Yes", "No")) == "Yes")
+ if(QDELETED(grabbed_mob) || !(grab?.grabbed_thing == grabbed_mob))
return
else
return
- climb_in(M, user)
+ climb_in(grabbed_mob, user)
+
+ return TRUE
/obj/machinery/cryopod/verb/eject()
set name = "Eject Pod"
@@ -313,15 +476,25 @@
occupant = null
update_icon()
-/obj/machinery/cryopod/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/cryopod/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
+ visible_message(span_warning("[xeno_attacker] begins to pry the [src]'s cover!"), 3)
playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(!do_after(xeno_attacker, 2 SECONDS))
return
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
go_out()
+
+#undef STATE_GUN
+#undef STATE_AMMO
+#undef STATE_EXPLOSIVE
+#undef STATE_MELEE
+#undef STATE_CLOTHING
+#undef STATE_FOOD
+#undef STATE_DRUGS
+#undef STATE_CONTAINERS
+#undef STATE_OTHER
diff --git a/code/game/objects/machinery/deployable.dm b/code/game/objects/machinery/deployable.dm
index 14465a874d949..4d2b0d0708bad 100644
--- a/code/game/objects/machinery/deployable.dm
+++ b/code/game/objects/machinery/deployable.dm
@@ -1,5 +1,5 @@
/obj/machinery/deployable
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
hud_possible = list(MACHINE_HEALTH_HUD)
obj_flags = CAN_BE_HIT
allow_pass_flags = PASS_AIR
@@ -58,8 +58,8 @@
var/obj/item/item = get_internal_item()
if(!item)
return
- if(CHECK_BITFIELD(item.flags_item, DEPLOYED_NO_PICKUP))
- to_chat(user, span_notice("The [src] is anchored in place and cannot be disassembled."))
+ if(CHECK_BITFIELD(item.item_flags, DEPLOYED_NO_PICKUP))
+ balloon_alert(user, "Cannot disassemble")
return
operator?.unset_interaction()
SEND_SIGNAL(src, COMSIG_ITEM_UNDEPLOY, user)
@@ -77,7 +77,7 @@
var/obj/item/_internal_item = get_internal_item()
if(!_internal_item)
return
- if(CHECK_BITFIELD(_internal_item.flags_item, DEPLOYED_WRENCH_DISASSEMBLE))
+ if(CHECK_BITFIELD(_internal_item.item_flags, DEPLOYED_WRENCH_DISASSEMBLE))
to_chat(user, span_notice("You cannot disassemble [src] without a wrench."))
return
disassemble(user)
@@ -86,7 +86,7 @@
var/obj/item/_internal_item = get_internal_item()
if(!_internal_item)
return
- if(!CHECK_BITFIELD(_internal_item.flags_item, DEPLOYED_WRENCH_DISASSEMBLE))
+ if(!CHECK_BITFIELD(_internal_item.item_flags, DEPLOYED_WRENCH_DISASSEMBLE))
return ..()
disassemble(user)
@@ -99,8 +99,8 @@
if(EXPLODE_DEVASTATE)
qdel(src)
if(EXPLODE_HEAVY)
- take_damage(200, damage_flag = BOMB, effects = TRUE)
+ take_damage(200, armor_type = BOMB, effects = TRUE)
if(EXPLODE_LIGHT)
- take_damage(100, damage_flag = BOMB, effects = TRUE)
+ take_damage(100, armor_type = BOMB, effects = TRUE)
if(EXPLODE_WEAK)
- take_damage(50, damage_flag = BOMB, effects = TRUE)
+ take_damage(50, armor_type = BOMB, effects = TRUE)
diff --git a/code/game/objects/machinery/door_control.dm b/code/game/objects/machinery/door_control.dm
index 4bff08604124c..d7e5c252a920f 100644
--- a/code/game/objects/machinery/door_control.dm
+++ b/code/game/objects/machinery/door_control.dm
@@ -128,6 +128,7 @@
update_icon()
/obj/machinery/door_control/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "doorctrl-p"
else if(pressed)
@@ -141,6 +142,8 @@
/obj/machinery/driver_button/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/detective_scanner))
return
@@ -281,6 +284,7 @@
directional = FALSE
/obj/machinery/door_control/old/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "olddoorctrl-p"
else if(pressed)
diff --git a/code/game/objects/machinery/door_display/door_display.dm b/code/game/objects/machinery/door_display/door_display.dm
index 18d81891c61f8..43b7c871812e0 100644
--- a/code/game/objects/machinery/door_display/door_display.dm
+++ b/code/game/objects/machinery/door_display/door_display.dm
@@ -110,17 +110,17 @@
//icon update function
// if NOPOWER, display blank
// if BROKEN, display blue screen of death icon AI uses
-/obj/machinery/door_display/update_icon()
- cut_overlays()
- if (machine_stat & (NOPOWER))
+/obj/machinery/door_display/update_overlays()
+ . = ..()
+ if(machine_stat & (NOPOWER))
return
- if (machine_stat & (BROKEN))
- add_overlay("ai_bsod")
+ if(machine_stat & (BROKEN))
+ . += "ai_bsod"
return
if(open)
- add_overlay("open")
+ . += "open"
else
- add_overlay("closed")
+ . += "closed"
//************ RESEARCH DOORS ****************\\
// Research cells have flashers and shutters/pod doors.
diff --git a/code/game/objects/machinery/doors/airlock.dm b/code/game/objects/machinery/doors/airlock.dm
old mode 100644
new mode 100755
index a26410a7f22c8..2b8b10b3ab1dc
--- a/code/game/objects/machinery/doors/airlock.dm
+++ b/code/game/objects/machinery/doors/airlock.dm
@@ -7,7 +7,7 @@
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 360
- flags_atom = HTML_USE_INITAL_ICON_1
+ atom_flags = HTML_USE_INITAL_ICON_1
obj_flags = CAN_BE_HIT
var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
@@ -63,6 +63,8 @@
/obj/machinery/door/airlock/LateInitialize()
. = ..()
+ if(cyclelinkeddir)
+ cyclelinkairlock()
if(!abandoned)
return
var/outcome = rand(1,40)
@@ -84,6 +86,28 @@
if(24 to 30)
machine_stat ^= PANEL_OPEN
+///connect potential airlocks to each other for cycling
+/obj/machinery/door/airlock/proc/cyclelinkairlock()
+ if (cycle_linked_airlock)
+ cycle_linked_airlock.cycle_linked_airlock = null
+ cycle_linked_airlock = null
+ if (!cyclelinkeddir)
+ return
+ var/limit = world.view
+ var/turf/T = get_turf(src)
+ var/obj/machinery/door/airlock/FoundDoor
+ do
+ T = get_step(T, cyclelinkeddir)
+ FoundDoor = locate() in T
+ if (FoundDoor && FoundDoor.cyclelinkeddir != get_dir(FoundDoor, src))
+ FoundDoor = null
+ limit--
+ while(!FoundDoor && limit)
+ if (!FoundDoor)
+ return
+ FoundDoor.cycle_linked_airlock = src
+ cycle_linked_airlock = FoundDoor
+
/obj/machinery/door/airlock/proc/isElectrified()
if(secondsElectrified != MACHINE_NOT_ELECTRIFIED)
return TRUE
@@ -91,6 +115,8 @@
/obj/machinery/door/airlock/proc/canAIControl(mob/user)
+ if(hackProof)
+ return
if(z != user.z)
return
return ((aiControlDisabled != 1) && !isAllPowerCut())
@@ -182,25 +208,45 @@
else
return 0
-
-/obj/machinery/door/airlock/update_icon()
- if(overlays) overlays.Cut()
+/obj/machinery/door/airlock/update_icon_state()
+ . = ..()
if(density)
- if(emergency && hasPower())
- overlays += image(icon, "emergency_access_on")
if(locked && lights)
icon_state = "door_locked"
else
icon_state = "door_closed"
- if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) || welded)
- overlays = list()
- if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
- overlays += image(icon, "panel_open")
- if(welded)
- overlays += image(icon, "welded")
else
icon_state = "door_open"
+/obj/machinery/door/airlock/update_overlays()
+ . = ..()
+ if(!density)
+ return
+ if(emergency && hasPower())
+ . += image(icon, "emergency_access_on")
+ if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
+ . += image(icon, "panel_open")
+ if(welded)
+ . += image(icon, "welded")
+ if(hasPower() && unres_sides)
+ for(var/heading in list(NORTH,SOUTH,EAST,WEST))
+ if(!(unres_sides & heading))
+ continue
+ var/image/access_overlay = image('icons/obj/doors/overlays.dmi', "unres_[heading]", layer = DOOR_HELPER_LAYER, pixel_y = -4)
+ switch(heading)
+ if(NORTH)
+ access_overlay.pixel_x = 0
+ access_overlay.pixel_y = 32
+ if(SOUTH)
+ access_overlay.pixel_x = 0
+ access_overlay.pixel_y = -32
+ if(EAST)
+ access_overlay.pixel_x = 32
+ access_overlay.pixel_y = 0
+ if(WEST)
+ access_overlay.pixel_x = -32
+ access_overlay.pixel_y = 0
+ . += access_overlay
/obj/machinery/door/airlock/do_animate(animation)
switch(animation)
@@ -227,46 +273,46 @@
//Prying open doors
-/obj/machinery/door/airlock/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/door/airlock/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- var/turf/cur_loc = X.loc
+ var/turf/cur_loc = xeno_attacker.loc
if(isElectrified())
- if(shock(X, 70))
+ if(shock(xeno_attacker, 70))
return
if(locked)
- to_chat(X, span_warning("\The [src] is bolted down tight."))
+ to_chat(xeno_attacker, span_warning("\The [src] is bolted down tight."))
return FALSE
if(welded)
- to_chat(X, span_warning("\The [src] is welded shut."))
+ to_chat(xeno_attacker, span_warning("\The [src] is welded shut."))
return FALSE
if(!istype(cur_loc))
return FALSE //Some basic logic here
if(!density)
- to_chat(X, span_warning("\The [src] is already open!"))
+ to_chat(xeno_attacker, span_warning("\The [src] is already open!"))
return FALSE
- if(X.do_actions)
+ if(xeno_attacker.do_actions)
return FALSE
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
if(hasPower())
- X.visible_message(span_warning("\The [X] digs into \the [src] and begins to pry it open."), \
+ xeno_attacker.visible_message(span_warning("\The [xeno_attacker] digs into \the [src] and begins to pry it open."), \
span_warning("We dig into \the [src] and begin to pry it open."), null, 5)
- if(!do_after(X, 4 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE) && !X.lying_angle)
+ if(!do_after(xeno_attacker, 4 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE) && !xeno_attacker.lying_angle)
return FALSE
if(locked)
- to_chat(X, span_warning("\The [src] is bolted down tight."))
+ to_chat(xeno_attacker, span_warning("\The [src] is bolted down tight."))
return FALSE
if(welded)
- to_chat(X, span_warning("\The [src] is welded shut."))
+ to_chat(xeno_attacker, span_warning("\The [src] is welded shut."))
return FALSE
if(density) //Make sure it's still closed
open(TRUE)
- X.visible_message(span_danger("\The [X] pries \the [src] open."), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] pries \the [src] open."), \
span_danger("We pry \the [src] open."), null, 5)
/obj/machinery/door/airlock/attack_larva(mob/living/carbon/xenomorph/larva/M)
@@ -307,6 +353,8 @@
/obj/machinery/door/airlock/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/clothing/mask/cigarette) && isElectrified())
var/obj/item/clothing/mask/cigarette/L = I
diff --git a/code/game/objects/machinery/doors/airlock_control.dm b/code/game/objects/machinery/doors/airlock_control.dm
index 60a254001d1b8..76fa2d62910ab 100644
--- a/code/game/objects/machinery/doors/airlock_control.dm
+++ b/code/game/objects/machinery/doors/airlock_control.dm
@@ -149,6 +149,7 @@
/obj/machinery/access_button/update_icon_state()
+ . = ..()
if(on)
icon_state = "access_button_standby"
else
@@ -156,6 +157,8 @@
/obj/machinery/access_button/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
attack_hand(user)
diff --git a/code/game/objects/machinery/doors/door.dm b/code/game/objects/machinery/doors/door.dm
old mode 100644
new mode 100755
index bd76a3b972de1..ba9b41ebde229
--- a/code/game/objects/machinery/doors/door.dm
+++ b/code/game/objects/machinery/doors/door.dm
@@ -21,14 +21,20 @@
var/operating = FALSE
var/autoclose = FALSE
var/glass = FALSE
+ /// Unrestricted sides. A bitflag for which direction (if any) can open the door with no access
+ var/unres_sides = NONE
var/normalspeed = TRUE
var/locked = FALSE
var/welded = FALSE
var/not_weldable = FALSE // stops people welding the door if true
var/openspeed = 10 //How many seconds does it take to open it? Default 1 second. Use only if you have long door opening animations
var/list/fillers
- //used for determining emergency access
+ ///used for determining emergency access
var/emergency = FALSE
+ ///bool for determining linked state
+ var/cyclelinkeddir = FALSE
+ ///what airlock we are linked with
+ var/obj/machinery/door/airlock/cycle_linked_airlock
//Multi-tile doors
dir = EAST
@@ -38,14 +44,14 @@
. = ..()
if(density)
layer = closed_layer
- update_flags_heat_protection(get_turf(src))
+ update_heat_protection_flags(get_turf(src))
else
layer = open_layer
if(width > 1)
handle_multidoor()
var/turf/current_turf = get_turf(src)
- current_turf.flags_atom &= ~ AI_BLOCKED
+ current_turf.atom_flags &= ~ AI_BLOCKED
if(glass)
allow_pass_flags |= PASS_GLASS
@@ -100,11 +106,17 @@
user = null
if(density)
- if(allowed(user) || emergency)
+ if(allowed(user) || emergency || unrestricted_side(user))
+ if(cycle_linked_airlock)
+ if(!emergency && !cycle_linked_airlock.emergency && allowed(user))
+ cycle_linked_airlock.close()
open()
else
flick("door_deny", src)
+///Allows for specific sides of airlocks to be unrestricted (IE, can exit maint freely, but need access to enter)
+/obj/machinery/door/proc/unrestricted_side(mob/opener)
+ return get_dir(src, opener) & unres_sides
/obj/machinery/door/attack_hand(mob/living/user)
. = ..()
@@ -160,7 +172,8 @@
s.start()
-/obj/machinery/door/update_icon()
+/obj/machinery/door/update_icon_state()
+ . = ..()
if(density)
icon_state = "door1"
else
@@ -235,7 +248,7 @@
/obj/machinery/door/proc/hasPower()
return !CHECK_BITFIELD(machine_stat, NOPOWER)
-/obj/machinery/door/proc/update_flags_heat_protection(turf/source)
+/obj/machinery/door/proc/update_heat_protection_flags(turf/source)
/obj/machinery/door/proc/autoclose()
if(!density && !operating && !locked && !welded && autoclose)
diff --git a/code/game/objects/machinery/doors/firedoor.dm b/code/game/objects/machinery/doors/firedoor.dm
index 8dd7ddca4d5e1..a0f1ed4fdb40a 100644
--- a/code/game/objects/machinery/doors/firedoor.dm
+++ b/code/game/objects/machinery/doors/firedoor.dm
@@ -48,7 +48,7 @@
. = ..()
for(var/obj/machinery/door/firedoor/F in loc)
if(F != src)
- flags_atom |= INITIALIZED
+ atom_flags |= INITIALIZED
return INITIALIZE_HINT_QDEL
var/area/A = get_area(src)
ASSERT(istype(A))
@@ -117,32 +117,32 @@
return ..()
return FALSE
-/obj/machinery/door/firedoor/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/door/firedoor/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- var/turf/cur_loc = X.loc
+ var/turf/cur_loc = xeno_attacker.loc
if(blocked)
- to_chat(X, span_warning("\The [src] is welded shut."))
+ to_chat(xeno_attacker, span_warning("\The [src] is welded shut."))
return FALSE
if(!istype(cur_loc))
return FALSE //Some basic logic here
if(!density)
- to_chat(X, span_warning("\The [src] is already open!"))
+ to_chat(xeno_attacker, span_warning("\The [src] is already open!"))
return FALSE
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
- X.visible_message(span_warning("\The [X] digs into \the [src] and begins to pry it open."), \
+ xeno_attacker.visible_message(span_warning("\The [xeno_attacker] digs into \the [src] and begins to pry it open."), \
span_warning("We dig into \the [src] and begin to pry it open."), null, 5)
- if(do_after(X, 30, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
+ if(do_after(xeno_attacker, 30, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
if(blocked)
- to_chat(X, span_warning("\The [src] is welded shut."))
+ to_chat(xeno_attacker, span_warning("\The [src] is welded shut."))
return FALSE
if(density) //Make sure it's still closed
spawn(0)
open(1)
- X.visible_message(span_danger("\The [X] pries \the [src] open."), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] pries \the [src] open."), \
span_danger("We pry \the [src] open."), null, 5)
/obj/machinery/door/firedoor/attack_hand(mob/living/user)
@@ -158,7 +158,7 @@
var/alarmed = lockdown
for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor
- if(A.flags_alarm_state & ALARM_WARNING_FIRE || A.air_doors_activated)
+ if(A.alarm_state_flags & ALARM_WARNING_FIRE || A.air_doors_activated)
alarmed = TRUE
var/answer = tgui_alert(user, "Would you like to [density ? "open" : "close"] this [src.name]?[ alarmed && density ? "\nNote that by doing so, you acknowledge any damages from opening this\n[src.name] as being your own fault, and you will be held accountable under the law." : ""]",\
@@ -194,7 +194,7 @@
spawn(50)
alarmed = FALSE
for(var/area/A in areas_added) //Just in case a fire alarm is turned off while the firedoor is going through an autoclose cycle
- if(A.flags_alarm_state & ALARM_WARNING_FIRE || A.air_doors_activated)
+ if(A.alarm_state_flags & ALARM_WARNING_FIRE || A.air_doors_activated)
alarmed = TRUE
if(alarmed)
nextstate = FIREDOOR_CLOSED
@@ -202,6 +202,8 @@
/obj/machinery/door/firedoor/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(operating)
return
@@ -287,26 +289,29 @@
flick("door_closing", src)
playsound(loc, 'sound/machines/emergency_shutter.ogg', 25)
-
-/obj/machinery/door/firedoor/update_icon()
- overlays.Cut()
+/obj/machinery/door/firedoor/update_icon_state()
+ . = ..()
if(density)
icon_state = "door_closed"
+ else
+ icon_state = "door_open"
+
+/obj/machinery/door/firedoor/update_overlays()
+ . = ..()
+ if(density)
if(blocked)
- overlays += "welded"
+ . += "welded"
if(pdiff_alert)
- overlays += "palert"
+ . += "palert"
if(dir_alerts)
for(var/d=1;d<=4;d++)
var/cdir = GLOB.cardinals[d]
for(var/i=1;i<=length(ALERT_STATES);i++)
if(dir_alerts[d] & (1<<(i-1)))
- overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir)
+ . += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir)
else
- icon_state = "door_open"
if(blocked)
- overlays += "welded_open"
-
+ . += "welded_open"
/obj/machinery/door/firedoor/mainship
name = "\improper Emergency Shutter"
@@ -323,7 +328,7 @@
/obj/machinery/door/firedoor/border_only
icon = 'icons/obj/doors/edge_Doorfire.dmi'
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
allow_pass_flags = PASS_GLASS
/obj/machinery/door/firedoor/border_only/Initialize(mapload)
diff --git a/code/game/objects/machinery/doors/multi_tile.dm b/code/game/objects/machinery/doors/multi_tile.dm
index 69595ac2e6439..9972fa1607245 100644
--- a/code/game/objects/machinery/doors/multi_tile.dm
+++ b/code/game/objects/machinery/doors/multi_tile.dm
@@ -2,10 +2,10 @@
/obj/machinery/door/airlock/multi_tile
width = 2
-/obj/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary
+/obj/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary //honestly probably not, TODO fixme
for(var/turf/T in locs)
- for(var/obj/vehicle/multitile/M in T)
- if(M) return FALSE
+ for(var/obj/hitbox/hit in T)
+ return FALSE
return ..()
@@ -133,12 +133,11 @@
/obj/machinery/door/airlock/multi_tile/mainship/blackgeneric
name = "\improper Airlock"
icon = 'icons/obj/doors/mainship/2x1almayerdoor.dmi'
- opacity = FALSE
- glass = FALSE
/obj/machinery/door/airlock/multi_tile/mainship/blackgeneric/glass
name = "\improper Glass Airlock"
icon = 'icons/obj/doors/mainship/2x1almayerdoor_glass.dmi'
+ opacity = FALSE
glass = TRUE
//PREP DOORS
@@ -314,8 +313,6 @@
/obj/machinery/door/airlock/multi_tile/mainship/engineering
name = "\improper Engineering Airlock"
icon = 'icons/obj/doors/mainship/2x1engidoor.dmi'
- opacity = FALSE
- glass = FALSE
req_one_access = list(ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_ENGINEERING)
/obj/machinery/door/airlock/multi_tile/mainship/engineering/glass
diff --git a/code/game/objects/machinery/doors/poddoor.dm b/code/game/objects/machinery/doors/poddoor.dm
index fecb6742f6045..ecf8149440e58 100644
--- a/code/game/objects/machinery/doors/poddoor.dm
+++ b/code/game/objects/machinery/doors/poddoor.dm
@@ -15,12 +15,12 @@
. = ..()
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
/obj/machinery/door/poddoor/Destroy()
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom &= ~AI_BLOCKED
+ current_turf.atom_flags &= ~AI_BLOCKED
return ..()
/obj/machinery/door/poddoor/bumpopen(mob/user)
@@ -30,13 +30,13 @@
. = ..()
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom &= ~AI_BLOCKED
+ current_turf.atom_flags &= ~AI_BLOCKED
/obj/machinery/door/poddoor/close()
. = ..()
var/turf/current_turf = get_turf(src)
if(anchored && current_turf && density)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
/obj/machinery/door/poddoor/Bumped(atom/AM)
if(!density)
@@ -48,7 +48,8 @@
/obj/machinery/door/poddoor/try_to_activate_door(mob/user)
return
-/obj/machinery/door/poddoor/update_icon()
+/obj/machinery/door/poddoor/update_icon_state()
+ . = ..()
if(density)
icon_state = "pdoor1"
else
@@ -98,7 +99,6 @@
/obj/machinery/door/poddoor/telecomms
name = "Telecomms Emergency Window"
id = "tcomwind"
- opacity = FALSE
/obj/machinery/door/poddoor/two_tile_hor
icon = 'icons/obj/doors/1x2blast_hor.dmi'
@@ -266,14 +266,14 @@
. = ..()
if(mapload)
var/area/ourarea = get_area(src)
- ENABLE_BITFIELD(ourarea.flags_area, DISALLOW_WEEDING)
- ENABLE_BITFIELD(ourarea.flags_area, NEAR_FOB)
+ ENABLE_BITFIELD(ourarea.area_flags, DISALLOW_WEEDING)
+ ENABLE_BITFIELD(ourarea.area_flags, NEAR_FOB)
/obj/machinery/door/poddoor/timed_late/containment/landing_zone/open()
. = ..()
var/area/ourarea = get_area(src)
- DISABLE_BITFIELD(ourarea.flags_area, DISALLOW_WEEDING)
+ DISABLE_BITFIELD(ourarea.area_flags, DISALLOW_WEEDING)
/obj/machinery/door/poddoor/timed_late/containment/landing_zone
id = "landing_zone"
diff --git a/code/game/objects/machinery/doors/railing.dm b/code/game/objects/machinery/doors/railing.dm
index 65fcc85836118..35a2312795acc 100644
--- a/code/game/objects/machinery/doors/railing.dm
+++ b/code/game/objects/machinery/doors/railing.dm
@@ -3,7 +3,7 @@
icon = 'icons/obj/doors/railing.dmi'
icon_state = "railing1"
use_power = 0
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
allow_pass_flags = PASSABLE
opacity = FALSE
open_layer = CATWALK_LAYER
@@ -57,7 +57,8 @@
return TRUE
-/obj/machinery/door/poddoor/railing/update_icon()
+/obj/machinery/door/poddoor/railing/update_icon_state()
+ . = ..()
if(density)
icon_state = "railing1"
else
@@ -68,7 +69,7 @@
operating = FALSE
var/turf/current_turf = get_turf(src)
if(current_turf)
- current_turf.flags_atom &= ~AI_BLOCKED
+ current_turf.atom_flags &= ~AI_BLOCKED
/obj/machinery/door/poddoor/railing/close()
if (!SSticker || operating || density)
@@ -81,7 +82,7 @@
icon_state = "railing1"
var/turf/current_turf = get_turf(src)
if(current_turf)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
addtimer(CALLBACK(src, PROC_REF(do_close)), 12)
return TRUE
diff --git a/code/game/objects/machinery/doors/shutters.dm b/code/game/objects/machinery/doors/shutters.dm
index 3d019311d6513..81cee63954d24 100644
--- a/code/game/objects/machinery/doors/shutters.dm
+++ b/code/game/objects/machinery/doors/shutters.dm
@@ -55,7 +55,8 @@
operating = FALSE
-/obj/machinery/door/poddoor/shutters/update_icon()
+/obj/machinery/door/poddoor/shutters/update_icon_state()
+ . = ..()
if(operating)
return
icon_state = "shutter[density]"
diff --git a/code/game/objects/machinery/doors/windowdoor.dm b/code/game/objects/machinery/doors/windowdoor.dm
index 56389874d968e..ab4c9a7d900d2 100644
--- a/code/game/objects/machinery/doors/windowdoor.dm
+++ b/code/game/objects/machinery/doors/windowdoor.dm
@@ -11,7 +11,7 @@
soft_armor = list(MELEE = 20, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 100, FIRE = 70, ACID = 100)
visible = FALSE
use_power = FALSE
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
allow_pass_flags = PASS_GLASS
opacity = FALSE
var/obj/item/circuitboard/airlock/electronics = null
@@ -44,7 +44,8 @@
return ..()
-/obj/machinery/door/window/update_icon()
+/obj/machinery/door/window/update_icon_state()
+ . = ..()
if(operating)
return
icon_state = density ? base_state : "[base_state]open"
@@ -128,6 +129,8 @@
/obj/machinery/door/window/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(operating)
return TRUE
diff --git a/code/game/objects/machinery/dropship_part_fabricator.dm b/code/game/objects/machinery/dropship_part_fabricator.dm
index d2024fea2e511..0d7ccebc193da 100644
--- a/code/game/objects/machinery/dropship_part_fabricator.dm
+++ b/code/game/objects/machinery/dropship_part_fabricator.dm
@@ -19,6 +19,7 @@
var/busy = FALSE
/obj/machinery/dropship_part_fabricator/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "drone_fab_nopower"
return
diff --git a/code/game/objects/machinery/fax.dm b/code/game/objects/machinery/fax.dm
index f39f5fc0e5158..4291cce94f600 100644
--- a/code/game/objects/machinery/fax.dm
+++ b/code/game/objects/machinery/fax.dm
@@ -144,6 +144,8 @@
/obj/machinery/faxmachine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
if(!message)
user.transferItemToLoc(I, src)
diff --git a/code/game/objects/machinery/fire_alarm.dm b/code/game/objects/machinery/fire_alarm.dm
index 23d03243cb0ae..4c95dc3aed05b 100644
--- a/code/game/objects/machinery/fire_alarm.dm
+++ b/code/game/objects/machinery/fire_alarm.dm
@@ -56,7 +56,7 @@ FIRE ALARM
return
var/area/A = get_area(src)
- if(A.flags_alarm_state & ALARM_WARNING_FIRE)
+ if(A.alarm_state_flags & ALARM_WARNING_FIRE)
set_light_color(LIGHT_COLOR_EMISSIVE_ORANGE)
else
switch(GLOB.marine_main_ship.get_security_level())
@@ -74,7 +74,7 @@ FIRE ALARM
/obj/machinery/firealarm/update_icon_state()
. = ..()
var/area/A = get_area(src)
- icon_state = "fire[!CHECK_BITFIELD(A.flags_alarm_state, ALARM_WARNING_FIRE)]"
+ icon_state = "fire[!CHECK_BITFIELD(A.alarm_state_flags, ALARM_WARNING_FIRE)]"
/obj/machinery/firealarm/update_overlays()
. = ..()
@@ -86,7 +86,7 @@ FIRE ALARM
. += emissive_appearance(icon, "fire_o[(is_mainship_level(z)) ? GLOB.marine_main_ship.get_security_level() : "green"]")
. += mutable_appearance(icon, "fire_o[(is_mainship_level(z)) ? GLOB.marine_main_ship.get_security_level() : "green"]")
var/area/A = get_area(src)
- if(A.flags_alarm_state & ALARM_WARNING_FIRE)
+ if(A.alarm_state_flags & ALARM_WARNING_FIRE)
. += mutable_appearance(icon, "fire_o1")
/obj/machinery/firealarm/fire_act(temperature, volume)
@@ -100,6 +100,8 @@ FIRE ALARM
/obj/machinery/firealarm/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && buildstage == 2)
wiresexposed = !wiresexposed
@@ -176,7 +178,7 @@ FIRE ALARM
var/d1
var/d2
- if (A.flags_alarm_state & ALARM_WARNING_FIRE)
+ if (A.alarm_state_flags & ALARM_WARNING_FIRE)
d1 = "Reset - Lockdown"
else
d1 = "Alarm - Lockdown"
diff --git a/code/game/objects/machinery/flasher.dm b/code/game/objects/machinery/flasher.dm
index f269b918c1ef6..c714e2cfa5e5d 100644
--- a/code/game/objects/machinery/flasher.dm
+++ b/code/game/objects/machinery/flasher.dm
@@ -34,6 +34,7 @@
/obj/machinery/flasher/update_icon_state()
+ . = ..()
if(!(machine_stat & NOPOWER))
icon_state = "[base_state]1"
else
@@ -105,6 +106,8 @@
/obj/machinery/flasher/portable/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
anchored = !anchored
@@ -120,6 +123,8 @@
/obj/machinery/flasher_button/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
return attack_hand(user)
/obj/machinery/flasher_button/attack_hand(mob/living/user)
diff --git a/code/game/objects/machinery/floodlight.dm b/code/game/objects/machinery/floodlight.dm
index f16b5e2addcc9..c981aea68462b 100644
--- a/code/game/objects/machinery/floodlight.dm
+++ b/code/game/objects/machinery/floodlight.dm
@@ -125,6 +125,7 @@
turn_light(user, !light_on)
/obj/machinery/deployable/floodlight/update_icon_state()
+ . = ..()
icon_state = "floodlightcombat_deployed" + (light_on ? "_on" : "_off")
/obj/item/deployable_floodlight
@@ -133,7 +134,7 @@
icon = 'icons/obj/machines/floodlight.dmi'
icon_state = "floodlightcombat"
max_integrity = 200
- flags_item = IS_DEPLOYABLE
+ item_flags = IS_DEPLOYABLE
w_class = WEIGHT_CLASS_NORMAL
var/deployable_item = /obj/machinery/deployable/floodlight
@@ -177,7 +178,7 @@
update_icon()
-/obj/machinery/floodlight/colony/update_icon()
+/obj/machinery/floodlight/colony/update_icon_state()
. = ..()
if(light_on)
icon_state = "floodon"
@@ -199,7 +200,7 @@
resistance_flags = RESIST_ALL
var/turned_on = FALSE //has to be toggled in engineering
-/obj/machinery/colony_floodlight_switch/update_icon()
+/obj/machinery/colony_floodlight_switch/update_icon_state()
. = ..()
if(machine_stat & NOPOWER)
icon_state = "panelnopower"
diff --git a/code/game/objects/machinery/fuelcell_recycler.dm b/code/game/objects/machinery/fuelcell_recycler.dm
index a91363d75284a..8c37b8cb30dff 100644
--- a/code/game/objects/machinery/fuelcell_recycler.dm
+++ b/code/game/objects/machinery/fuelcell_recycler.dm
@@ -15,6 +15,8 @@
/obj/machinery/fuelcell_recycler/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/fuel_cell))
if(!cell_left)
if(user.transferItemToLoc(I, src))
@@ -85,18 +87,22 @@
update_icon()
-/obj/machinery/fuelcell_recycler/update_icon()
- src.overlays.Cut()
-
+/obj/machinery/fuelcell_recycler/update_icon_state()
+ . = ..()
if(machine_stat & (BROKEN|NOPOWER))
icon_state = "recycler0"
+ else
+ icon_state = "recycler"
+
+/obj/machinery/fuelcell_recycler/update_overlays()
+ . = ..()
+
+ if(machine_stat & (BROKEN|NOPOWER))
if(cell_left != null)
src.overlays += "recycler-left-cell"
if(cell_right != null)
src.overlays += "recycler-right-cell"
return
- else
- icon_state = "recycler"
var/overlay_builder = "recycler-"
if(cell_left == null && cell_right == null)
@@ -107,8 +113,8 @@
else
overlay_builder += "left-charging"
- src.overlays += overlay_builder
- src.overlays += "recycler-left-cell"
+ . += overlay_builder
+ . += "recycler-left-cell"
return
else if(cell_left == null)
if(cell_right.is_regenerated())
@@ -116,8 +122,8 @@
else
overlay_builder += "right-charging"
- src.overlays += overlay_builder
- src.overlays += "recycler-right-cell"
+ . += overlay_builder
+ . += "recycler-right-cell"
return
else // both left and right cells are there
if(cell_left.is_regenerated())
@@ -130,7 +136,6 @@
else
overlay_builder += "-right-charging"
- src.overlays += overlay_builder
- src.overlays += "recycler-left-cell"
- src.overlays += "recycler-right-cell"
- return
+ . += overlay_builder
+ . += "recycler-left-cell"
+ . += "recycler-right-cell"
diff --git a/code/game/objects/machinery/hologram.dm b/code/game/objects/machinery/hologram.dm
index 1a6de82d0c063..878e61ba616de 100644
--- a/code/game/objects/machinery/hologram.dm
+++ b/code/game/objects/machinery/hologram.dm
@@ -335,11 +335,6 @@
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
- if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
- for(var/mob/living/silicon/ai/master in masters)
- if(masters[master] && speaker != master)
- master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
-
for(var/datum/holocall/holocall_to_update AS in holo_calls)
if(holocall_to_update.connected_holopad == src && speaker != holocall_to_update.hologram)
holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
@@ -359,6 +354,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
update_icon()
/obj/machinery/holopad/update_icon_state()
+ . = ..()
var/total_users = LAZYLEN(masters) + LAZYLEN(holo_calls)
if(ringing)
icon_state = "holopad_ringing"
diff --git a/code/game/objects/machinery/holosign.dm b/code/game/objects/machinery/holosign.dm
index 4217b4ba818dc..70940add018de 100644
--- a/code/game/objects/machinery/holosign.dm
+++ b/code/game/objects/machinery/holosign.dm
@@ -17,6 +17,7 @@
update_icon()
/obj/machinery/holosign/update_icon_state()
+ . = ..()
if(!lit)
icon_state = "sign_off"
else
@@ -51,6 +52,8 @@
/obj/machinery/holosign_switch/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/detective_scanner))
return
diff --git a/code/game/objects/machinery/igniter.dm b/code/game/objects/machinery/igniter.dm
index fb08154766ea9..016a4c3fd8925 100644
--- a/code/game/objects/machinery/igniter.dm
+++ b/code/game/objects/machinery/igniter.dm
@@ -30,7 +30,8 @@
icon_state = "igniter[on]"
-/obj/machinery/igniter/update_icon()
+/obj/machinery/igniter/update_icon_state()
+ . = ..()
if(is_operational())
icon_state = "igniter[on]"
else
@@ -52,17 +53,17 @@
var/base_state = "migniter"
anchored = TRUE
-/obj/machinery/sparker/update_icon()
- if ( !(machine_stat & NOPOWER) && disable == 0 )
-
+/obj/machinery/sparker/update_icon_state()
+ . = ..()
+ if(!(machine_stat & NOPOWER) && disable == 0)
icon_state = "[base_state]"
-// src.sd_SetLuminosity(2)
else
icon_state = "[base_state]-p"
-// src.sd_SetLuminosity(0)
/obj/machinery/sparker/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/detective_scanner))
return
@@ -109,6 +110,8 @@
/obj/machinery/ignition_switch/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
return attack_hand(user)
/obj/machinery/ignition_switch/attack_hand(mob/living/user)
diff --git a/code/game/objects/machinery/iv_drip.dm b/code/game/objects/machinery/iv_drip.dm
index 7ab2a83e7962b..0c5c2bcacf60f 100644
--- a/code/game/objects/machinery/iv_drip.dm
+++ b/code/game/objects/machinery/iv_drip.dm
@@ -10,37 +10,44 @@
var/obj/item/reagent_containers/beaker = null
var/datum/beam/current_beam //RUTGMC ADDON
-/obj/machinery/iv_drip/update_icon()
- /* СМ КОСТЫЛЬ
- if(src.attached)
+/obj/machinery/iv_drip/update_icon_state()
+ . = ..()
+ if(attached)
icon_state = "hooked"
else
icon_state = ""
- */
- icon_state = "" //КОСТЫЛЬ
- //У нас нет системы которая позволила бы изменить pixel x/y вары у начальной и конечной точек beam'а
- //Поэтому оставляю 1 айкон стейт, чтобы не выглядело всё слишком плохо
+/obj/machinery/iv_drip/update_overlays()
+ . = ..()
- overlays = null
+ if(!beaker)
+ return
- if(beaker)
- var/datum/reagents/reagents = beaker.reagents
- if(reagents.total_volume)
- var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent")
-
- var/percent = round((reagents.total_volume / beaker.volume) * 100)
- switch(percent)
- if(0 to 9) filling.icon_state = "reagent0"
- if(10 to 24) filling.icon_state = "reagent10"
- if(25 to 49) filling.icon_state = "reagent25"
- if(50 to 74) filling.icon_state = "reagent50"
- if(75 to 79) filling.icon_state = "reagent75"
- if(80 to 90) filling.icon_state = "reagent80"
- if(91 to INFINITY) filling.icon_state = "reagent100"
-
- filling.color = mix_color_from_reagents(reagents.reagent_list)
- overlays += filling
+ var/datum/reagents/reagents = beaker.reagents
+ if(!reagents?.total_volume)
+ return
+
+ var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent")
+
+ var/percent = round((reagents.total_volume / beaker.volume) * 100)
+ switch(percent)
+ if(0 to 9)
+ filling.icon_state = "reagent0"
+ if(10 to 24)
+ filling.icon_state = "reagent10"
+ if(25 to 49)
+ filling.icon_state = "reagent25"
+ if(50 to 74)
+ filling.icon_state = "reagent50"
+ if(75 to 79)
+ filling.icon_state = "reagent75"
+ if(80 to 90)
+ filling.icon_state = "reagent80"
+ if(91 to INFINITY)
+ filling.icon_state = "reagent100"
+
+ filling.color = mix_color_from_reagents(reagents.reagent_list)
+ . += filling
/obj/machinery/iv_drip/MouseDrop(over_object, src_location, over_location)
..()
@@ -70,6 +77,8 @@
/obj/machinery/iv_drip/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers))
if(beaker)
diff --git a/code/game/objects/machinery/kitchen/gibber.dm b/code/game/objects/machinery/kitchen/gibber.dm
index 38a85bf7d66f4..09cadb8dc5a8c 100644
--- a/code/game/objects/machinery/kitchen/gibber.dm
+++ b/code/game/objects/machinery/kitchen/gibber.dm
@@ -51,39 +51,32 @@
startgibbing(user)
-/obj/machinery/gibber/attackby(obj/item/grab/I, mob/user, param)
- . = ..()
-
+/obj/machinery/gibber/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!is_operational())
+ return ..()
if(occupant)
to_chat(user, span_warning("The gibber is full, empty it first!"))
return
-
- else if(!(istype(I, /obj/item/grab)) )
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(!iscarbon(grabbed_mob) && !istype(grabbed_mob, /mob/living/simple_animal))
to_chat(user, span_warning("This item is not suitable for the gibber!"))
return
-
- else if(!iscarbon(I.grabbed_thing) && !istype(I.grabbed_thing, /mob/living/simple_animal))
- to_chat(user, span_warning("This item is not suitable for the gibber!"))
- return
-
- var/mob/living/M = I.grabbed_thing
if(user.grab_state < GRAB_AGGRESSIVE)
to_chat(user, span_warning("You need a better grip to do that!"))
return
-
- else if(M.abiotic(TRUE))
+ if(grabbed_mob.abiotic(TRUE))
to_chat(user, span_warning("Subject may not have abiotic items on."))
return
+ user.visible_message(span_danger("[user] starts to put [grabbed_mob] into the gibber!"))
- user.visible_message(span_danger("[user] starts to put [M] into the gibber!"))
-
- if(!do_after(user, 30, NONE, M, BUSY_ICON_DANGER) || QDELETED(src) || occupant)
+ if(!do_after(user, 30, NONE, grabbed_mob, BUSY_ICON_DANGER) || QDELETED(src) || occupant)
return
- user.visible_message(span_danger("[user] stuffs [M] into the gibber!"))
- M.forceMove(src)
- occupant = M
+ user.visible_message(span_danger("[user] stuffs [grabbed_mob] into the gibber!"))
+ grabbed_mob.forceMove(src)
+ occupant = grabbed_mob
update_icon()
+ return TRUE
/obj/machinery/gibber/verb/eject()
set category = "Object"
diff --git a/code/game/objects/machinery/kitchen/microwave.dm b/code/game/objects/machinery/kitchen/microwave.dm
index 3e894ef52ba72..0141c1475b3bf 100644
--- a/code/game/objects/machinery/kitchen/microwave.dm
+++ b/code/game/objects/machinery/kitchen/microwave.dm
@@ -48,6 +48,8 @@
/obj/machinery/microwave/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(broken == 2 && isscrewdriver(I))
balloon_alert_to_viewers("starts to fix the microwave")
@@ -120,14 +122,48 @@
return FALSE
- else if(istype(I, /obj/item/grab))
- return TRUE
-
else
balloon_alert(user, "Can't cook anything with this")
return TRUE
+/obj/machinery/microwave/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!is_operational())
+ return ..()
+ if(isxeno(user))
+ return
+ if(user.do_actions)
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(user.a_intent != INTENT_HARM)
+ return
+ if(user.grab_state <= GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
+ return
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(grabbed_mob.mob_size > MOB_SIZE_HUMAN)
+ to_chat(user, span_warning("They're too big to fit!"))
+ return
+ user.visible_message(span_danger("[user] starts to force [grabbed_mob] into [src]!"), span_notice("You start to force [grabbed_mob] into [src]!"))
+ if(!do_after(user, 3 SECONDS, NONE, src, BUSY_ICON_HOSTILE, extra_checks = CALLBACK(src, PROC_REF(microwave_victim), grabbed_mob)))
+ playsound(src.loc, 'sound/machines/ding.ogg', 25, 1)
+ return
+
+ user.visible_message(span_danger("[user] microwaves [grabbed_mob]!"), span_notice("You microwave [grabbed_mob]!"), "You hear sizzling.")
+ log_combat(user, grabbed_mob, "microwaved")
+ playsound(src.loc, 'sound/machines/ding.ogg', 25, 1)
+ return TRUE
+
+/obj/machinery/microwave/proc/microwave_victim(mob/living/victim)
+ victim.apply_damage(3, BURN, "head", ENERGY, updating_health = TRUE, penetration = 20)
+ victim.jitter(5)
+ if(prob(10))
+ victim.emote("scream")
+ victim.adjustBrainLoss(5)
+ if(victim.stat != DEAD)
+ return TRUE
+
/obj/machinery/microwave/nopower
use_power = NO_POWER_USE
diff --git a/code/game/objects/machinery/kitchen/processor.dm b/code/game/objects/machinery/kitchen/processor.dm
index aa139464bd6d7..79908c9c25081 100644
--- a/code/game/objects/machinery/kitchen/processor.dm
+++ b/code/game/objects/machinery/kitchen/processor.dm
@@ -37,6 +37,8 @@
/obj/machinery/processor/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(processing)
to_chat(user, span_warning("The processor is in the process of processing."))
@@ -48,7 +50,7 @@
var/obj/O = I
- if(istype(I, /obj/item/grab))
+ if(isgrabitem(I))
var/obj/item/grab/G = I
O = G.grabbed_thing
@@ -61,6 +63,29 @@
user.drop_held_item()
O.forceMove(src)
+/obj/machinery/processor/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!is_operational())
+ return ..()
+ if(isxeno(user))
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(user.a_intent != INTENT_HARM)
+ return
+ if(user.grab_state <= GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
+ return
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ user.visible_message(span_danger("[user] starts to force [grabbed_mob] into [src]!"), span_notice("You start to force [grabbed_mob] into [src]!"))
+ if(!do_after(user, 3 SECONDS, NONE, src, BUSY_ICON_HOSTILE))
+ return
+
+ user.visible_message(span_danger("[user] processes [grabbed_mob]!"), span_notice("You process [grabbed_mob]!"), "You hear churning.")
+ log_combat(user, grabbed_mob, "food processed")
+ playsound(loc, 'sound/machines/blender.ogg', 25, 1)
+ grabbed_mob.apply_damage(80, BRUTE, "head", MELEE, TRUE, updating_health = TRUE)
+ return TRUE
+
/obj/machinery/processor/attack_hand(mob/living/user)
. = ..()
if(.)
diff --git a/code/game/objects/machinery/kitchen/smartfridge.dm b/code/game/objects/machinery/kitchen/smartfridge.dm
index 1b8d4713d4a66..f3e1d3b43c143 100644
--- a/code/game/objects/machinery/kitchen/smartfridge.dm
+++ b/code/game/objects/machinery/kitchen/smartfridge.dm
@@ -41,8 +41,9 @@
if(src.shoot_inventory && prob(2))
src.throw_item()
-/obj/machinery/smartfridge/update_icon()
- if( !(machine_stat & NOPOWER) )
+/obj/machinery/smartfridge/update_icon_state()
+ . = ..()
+ if(!(machine_stat & NOPOWER))
icon_state = icon_on
else
icon_state = icon_off
@@ -53,6 +54,8 @@
/obj/machinery/smartfridge/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
TOGGLE_BITFIELD(machine_stat, PANEL_OPEN)
diff --git a/code/game/objects/machinery/lightswitch.dm b/code/game/objects/machinery/lightswitch.dm
index f4762b8f83a35..b810656ae3eaa 100644
--- a/code/game/objects/machinery/lightswitch.dm
+++ b/code/game/objects/machinery/lightswitch.dm
@@ -25,6 +25,7 @@
update_icon()
/obj/machinery/light_switch/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "light-p"
return
diff --git a/code/game/objects/machinery/line_nexter.dm b/code/game/objects/machinery/line_nexter.dm
index add6e694b9203..1e41d9835ec63 100644
--- a/code/game/objects/machinery/line_nexter.dm
+++ b/code/game/objects/machinery/line_nexter.dm
@@ -7,7 +7,7 @@
icon_state = "turnstile"
anchored = TRUE
allow_pass_flags = PASS_DEFENSIVE_STRUCTURE|PASSABLE
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
dir = 8
var/last_use
var/id
diff --git a/code/game/objects/machinery/minelayer.dm b/code/game/objects/machinery/minelayer.dm
index 796b63d617ed9..a13be8935aa52 100644
--- a/code/game/objects/machinery/minelayer.dm
+++ b/code/game/objects/machinery/minelayer.dm
@@ -4,7 +4,7 @@
icon = 'icons/Marine/marine-items.dmi'
icon_state = "minelayer"
max_integrity = 200
- flags_item = IS_DEPLOYABLE
+ item_flags = IS_DEPLOYABLE
w_class = WEIGHT_CLASS_NORMAL
///amount of currently stored mines
var/stored_mines = 0
@@ -65,6 +65,8 @@
/obj/machinery/deployable/minelayer/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/explosive/mine) && stored_amount <= max_amount)
stored_amount++
qdel(I)
diff --git a/code/game/objects/machinery/miner.dm b/code/game/objects/machinery/miner.dm
index 6e09369e27e82..e9c971e301953 100644
--- a/code/game/objects/machinery/miner.dm
+++ b/code/game/objects/machinery/miner.dm
@@ -73,7 +73,8 @@
var/marker_icon = "miner_[mineral_value >= PLATINUM_CRATE_SELL_AMOUNT ? "platinum" : "phoron"]_on"
SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, marker_icon)) //RU TGMC edit
-/obj/machinery/miner/update_icon()
+/obj/machinery/miner/update_icon_state()
+ . = ..()
switch(miner_status)
if(MINER_RUNNING)
icon_state = "mining_drill_active_[miner_upgrade_type]"
@@ -127,6 +128,8 @@
/obj/machinery/miner/attackby(obj/item/I,mob/user,params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/minerupgrade))
var/obj/item/minerupgrade/upgrade = I
if(!(miner_status == MINER_RUNNING))
@@ -173,13 +176,13 @@
user.visible_message(span_notice("[user] fumbles around figuring out [src]'s internals."),
span_notice("You fumble around figuring out [src]'s internals."))
var/fumbling_time = 10 SECONDS - 2 SECONDS * user.skills.getRating(SKILL_ENGINEER)
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(weldingtool, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(weldingtool, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return FALSE
playsound(loc, 'sound/items/weldingtool_weld.ogg', 25)
user.visible_message(span_notice("[user] starts welding [src]'s internal damage."),
span_notice("You start welding [src]'s internal damage."))
add_overlay(GLOB.welding_sparks)
- if(!do_after(user, 200, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(weldingtool, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 200, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(weldingtool, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
cut_overlay(GLOB.welding_sparks)
return FALSE
if(miner_status != MINER_DESTROYED )
@@ -313,26 +316,26 @@
else
add_tick += 1
-/obj/machinery/miner/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL) //Incorporeal xenos cannot attack physically.
+/obj/machinery/miner/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL) //Incorporeal xenos cannot attack physically.
return
- if(miner_upgrade_type == MINER_RESISTANT && !(X.mob_size == MOB_SIZE_BIG || X.xeno_caste.caste_flags & CASTE_IS_STRONG))
- X.visible_message(span_notice("[X]'s claws bounce off of [src]'s reinforced plating."),
+ if(miner_upgrade_type == MINER_RESISTANT && !(xeno_attacker.mob_size == MOB_SIZE_BIG || xeno_attacker.xeno_caste.caste_flags & CASTE_IS_STRONG))
+ xeno_attacker.visible_message(span_notice("[xeno_attacker]'s claws bounce off of [src]'s reinforced plating."),
span_notice("We can't slash through [src]'s reinforced plating!"))
return
while(miner_status != MINER_DESTROYED)
- if(X.do_actions)
- return balloon_alert(X, "busy")
- if(!do_after(X, 1.5 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
+ if(xeno_attacker.do_actions)
+ return balloon_alert(xeno_attacker, "busy")
+ if(!do_after(xeno_attacker, 1.5 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
return
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- X.visible_message(span_danger("[X] slashes \the [src]!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] slashes \the [src]!"), \
span_danger("We slash \the [src]!"), null, 5)
playsound(loc, "alien_claw_metal", 25, TRUE)
miner_integrity -= 25
set_miner_status()
- if(miner_status == MINER_DESTROYED && X.client)
- var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[X.ckey]
+ if(miner_status == MINER_DESTROYED && xeno_attacker.client)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[xeno_attacker.ckey]
personal_statistics.miner_sabotages_performed++
/* RUTGMC DELETION
diff --git a/code/game/objects/machinery/mortar.dm b/code/game/objects/machinery/mortar.dm
index af2ed87f17983..5be0bc9868465 100644
--- a/code/game/objects/machinery/mortar.dm
+++ b/code/game/objects/machinery/mortar.dm
@@ -189,6 +189,8 @@
/obj/machinery/deployable/mortar/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(firing)
user.balloon_alert(user, "The barrel is steaming hot. Wait till it cools off")
@@ -275,8 +277,7 @@
var/datum/ammo/ammo = GLOB.ammo_list[arty_shell.ammo_type]
shell.generate_bullet(ammo)
var/shell_range = min(get_dist_euclidean(src, target), ammo.max_range)
- // shell.fire_at(target, null, src, shell_range, ammo.shell_speed) // FUTURE ORIGINAL, WE DON'T HAVE NEEDED CHANGES YET
- shell.fire_at(target, src, src, shell_range, ammo.shell_speed) // RUTGMC OLD VERSION
+ shell.fire_at(target, null, src, shell_range, ammo.shell_speed)
perform_firing_visuals()
@@ -429,7 +430,7 @@
icon_state = "mortar"
max_integrity = 200
soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 15, BIO = 100, FIRE = 0, ACID = 0)
- flags_item = IS_DEPLOYABLE
+ item_flags = IS_DEPLOYABLE
/// What item is this going to deploy when we put down the mortar?
var/deployable_item = /obj/machinery/deployable/mortar
resistance_flags = RESIST_ALL
@@ -458,7 +459,7 @@
desc = "A manual, crew-operated mortar system intended to rain down 80mm goodness on anything it's aimed at. Needs to be set down first to fire. This one is a double barreled mortar that can hold 4 rounds usually fitted in TAV's."
icon_state = "mortar_db"
max_integrity = 400
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
w_class = WEIGHT_CLASS_HUGE
deployable_item = /obj/machinery/deployable/mortar/double
@@ -479,7 +480,7 @@
icon = 'icons/Marine/howitzer.dmi'
icon_state = "howitzer"
max_integrity = 400
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
w_class = WEIGHT_CLASS_HUGE
deployable_item = /obj/machinery/deployable/mortar/howitzer
@@ -564,7 +565,7 @@
desc = "A manual, crew-operated and towable multiple rocket launcher system piece used by the TerraGov Marine Corps, it is meant to saturate an area with munitions to total up to large amounts of firepower, it thus has high scatter when firing to accomplish such a task. Fires in only bursts of up to 16 rockets, it can hold 32 rockets in total. Uses 60mm Rockets."
icon_state = "mlrs"
max_integrity = 400
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
w_class = WEIGHT_CLASS_HUGE
deployable_item = /obj/machinery/deployable/mortar/howitzer/mlrs
@@ -581,6 +582,8 @@
allowed_shells = list(
/obj/item/mortal_shell/rocket/mlrs,
/obj/item/mortal_shell/rocket/mlrs/gas,
+ /obj/item/mortal_shell/rocket/mlrs/incendiary,
+ /obj/item/mortal_shell/rocket/mlrs/cloak,
)
tally_type = TALLY_ROCKET_ARTY
cool_off_time = 80 SECONDS
@@ -598,7 +601,7 @@
user.balloon_alert(user, "The barrel is steaming hot. Wait till it cools off")
return
- if(!istype(I, /obj/item/storage/box/mlrs_rockets) && !istype(I, /obj/item/storage/box/mlrs_rockets_gas))
+ if(!istype(I, /obj/item/storage/box/mlrs_rockets))
return ..()
var/obj/item/storage/box/rocket_box = I
@@ -660,7 +663,7 @@
)
icon_state = "mortar_ammo_cas"
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
///Ammo datum typepath that the shell uses
var/ammo_type
@@ -745,6 +748,18 @@
icon_state = "mlrs_rocket_gas"
ammo_type = /datum/ammo/mortar/rocket/smoke/mlrs
+/obj/item/mortal_shell/rocket/mlrs/cloak
+ name = "\improper 60mm 'S-2' cloak rocket"
+ desc = "A 60mm rocket loaded with cloak smoke that hides any friendlies inside of it with advanced chemical technology."
+ icon_state = "mlrs_rocket_cloak"
+ ammo_type = /datum/ammo/mortar/rocket/smoke/mlrs/cloak
+
+/obj/item/mortal_shell/rocket/mlrs/incendiary
+ name = "\improper 60mm incendiary rocket"
+ desc = "A 60mm rocket loaded with an incendiary payload with a minor side of explosive."
+ icon_state = "mlrs_rocket_incendiary"
+ ammo_type = /datum/ammo/mortar/rocket/mlrs/incendiary
+
/obj/structure/closet/crate/mortar_ammo
name = "\improper T-50S mortar ammo crate"
desc = "A crate containing live mortar shells with various payloads. DO NOT DROP. KEEP AWAY FROM FIRE SOURCES."
@@ -776,7 +791,7 @@
desc = "A crate containing a basic set of a mortar and some shells, to get an engineer started."
/obj/structure/closet/crate/mortar_ammo/mortar_kit/PopulateContents()
- new /obj/item/mortar_kit(src)
+ new /obj/item/storage/holster/backholster/mortar/full(src)
new /obj/item/mortal_shell/he(src)
new /obj/item/mortal_shell/he(src)
new /obj/item/mortal_shell/he(src)
@@ -880,8 +895,7 @@
desc = "A large case containing rockets in a compressed setting for the TA-40L MLRS. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
storage_slots = 16
-/obj/item/storage/box/mlrs_rockets/Initialize(mapload)
- . = ..()
+/obj/item/storage/box/mlrs_rockets/PopulateContents()
new /obj/item/mortal_shell/rocket/mlrs(src)
new /obj/item/mortal_shell/rocket/mlrs(src)
new /obj/item/mortal_shell/rocket/mlrs(src)
@@ -899,13 +913,10 @@
new /obj/item/mortal_shell/rocket/mlrs(src)
new /obj/item/mortal_shell/rocket/mlrs(src)
-/obj/item/storage/box/mlrs_rockets_gas
+/obj/item/storage/box/mlrs_rockets/gas
name = "\improper TA-40L X-50 rocket crate"
- desc = "A large case containing rockets in a compressed setting for the TA-40L MLRS. Drag this sprite into you to open it up!\nNOTE: You cannot put items back inside this case."
- storage_slots = 16
-/obj/item/storage/box/mlrs_rockets_gas/Initialize(mapload)
- . = ..()
+/obj/item/storage/box/mlrs_rockets/gas/PopulateContents()
new /obj/item/mortal_shell/rocket/mlrs/gas(src)
new /obj/item/mortal_shell/rocket/mlrs/gas(src)
new /obj/item/mortal_shell/rocket/mlrs/gas(src)
@@ -923,5 +934,49 @@
new /obj/item/mortal_shell/rocket/mlrs/gas(src)
new /obj/item/mortal_shell/rocket/mlrs/gas(src)
+/obj/item/storage/box/mlrs_rockets/cloak
+ name = "\improper TA-40L 'S-2' rocket crate"
+
+/obj/item/storage/box/mlrs_rockets/cloak/PopulateContents()
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+ new /obj/item/mortal_shell/rocket/mlrs/cloak(src)
+
+/obj/item/storage/box/mlrs_rockets/incendiary
+ name = "\improper TA-40L incendiary rocket crate"
+
+/obj/item/storage/box/mlrs_rockets/incendiary/PopulateContents()
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+ new /obj/item/mortal_shell/rocket/mlrs/incendiary(src)
+
+
#undef TALLY_MORTAR
#undef TALLY_HOWITZER
+#undef TALLY_ROCKET_ARTY
diff --git a/code/game/objects/machinery/nuclearbomb.dm b/code/game/objects/machinery/nuclearbomb.dm
index 0c124657cf668..2b1b58efd3816 100644
--- a/code/game/objects/machinery/nuclearbomb.dm
+++ b/code/game/objects/machinery/nuclearbomb.dm
@@ -13,10 +13,10 @@
density = TRUE
anchored = TRUE
coverage = 20
- flags_atom = CRITICAL_ATOM
+ atom_flags = CRITICAL_ATOM
resistance_flags = RESIST_ALL
layer = BELOW_MOB_LAYER
- interaction_flags = INTERACT_OBJ_UI
+ interaction_flags = INTERACT_MACHINE_TGUI
var/deployable = TRUE
var/extended = FALSE
var/lighthack = FALSE
@@ -103,6 +103,8 @@
/obj/machinery/nuclearbomb/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!extended)
return
if(!istype(I, /obj/item/disk/nuclear))
@@ -119,23 +121,23 @@
if(r_auth && g_auth && b_auth)
has_auth = TRUE
-/obj/machinery/nuclearbomb/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/nuclearbomb/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(!timer_enabled)
- to_chat(X, span_warning("\The [src] is soundly asleep. We better not disturb it."))
+ to_chat(xeno_attacker, span_warning("\The [src] is soundly asleep. We better not disturb it."))
return
- X.visible_message("[X] begins to slash delicately at the nuke",
+ xeno_attacker.visible_message("[xeno_attacker] begins to slash delicately at the nuke",
"You start slashing delicately at the nuke.")
- if(!do_after(X, 5 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
+ if(!do_after(xeno_attacker, 5 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
return
- X.visible_message("[X] disabled the nuke",
+ xeno_attacker.visible_message("[xeno_attacker] disabled the nuke",
"You disabled the nuke.")
disable()
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NUKE_DIFFUSED, src, X)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NUKE_DIFFUSED, src, xeno_attacker)
/obj/machinery/nuclearbomb/can_interact(mob/user)
. = ..()
@@ -350,7 +352,7 @@
///Change minimap icon if its on or off
/obj/machinery/nuclearbomb/proc/update_minimap_icon()
SSminimaps.remove_marker(src)
- SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, "nuke[timer_enabled ? "_on" : "_off"]", VERY_HIGH_FLOAT_LAYER))
+ SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips_large.dmi', null, "nuke[timer_enabled ? "_on" : "_off"]", VERY_HIGH_FLOAT_LAYER)) //RUTGMC EDIT
#undef NUKE_STAGE_NONE
#undef NUKE_STAGE_COVER_REMOVED
diff --git a/code/game/objects/machinery/overwatch.dm b/code/game/objects/machinery/overwatch.dm
index beabe1afa2baf..81c934bf09eb7 100644
--- a/code/game/objects/machinery/overwatch.dm
+++ b/code/game/objects/machinery/overwatch.dm
@@ -327,30 +327,8 @@ GLOBAL_LIST_EMPTY(active_cas_targets)
state = OW_MAIN
if("monitor")
state = OW_MONITOR
- if("monitoralpha_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(ALPHA_SQUAD)
- if("monitorbravo_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(BRAVO_SQUAD)
- if("monitorcharlie_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(CHARLIE_SQUAD)
- if("monitordelta_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(DELTA_SQUAD)
- if("monitorzulu_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(ZULU_SQUAD)
- if("monitoryankee_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(YANKEE_SQUAD)
- if("monitorxray_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(XRAY_SQUAD)
- if("monitorwhiskey_squad")
- state = OW_MONITOR
- current_squad = get_squad_by_id(WHISKEY_SQUAD)
+ if(href_list["squad_id"])
+ current_squad = get_squad_by_id(href_list["squad_id"])
if("change_operator")
if(operator != usr)
if(current_squad)
@@ -556,7 +534,7 @@ GLOBAL_LIST_EMPTY(active_cas_targets)
dat += "Squad Overwatch: [S.overwatch_officer.name] "
else
dat += "Squad Overwatch: NONE "
- dat += "[S.name] Squad Monitor "
+ dat += "[S.name] Squad Monitor "
dat += "---------------------- "
dat += "Orbital Bombardment Control "
dat += "Current Cannon Status: "
@@ -624,7 +602,7 @@ GLOBAL_LIST_EMPTY(active_cas_targets)
dat += "Squad Overwatch: [S.overwatch_officer.name] "
else
dat += "Squad Overwatch: NONE "
- dat += "[S.name] Squad Monitor "
+ dat += "[S.name] Squad Monitor "
if(OW_MONITOR)//Info screen.
dat += get_squad_info()
diff --git a/code/game/objects/machinery/pipe/construction.dm b/code/game/objects/machinery/pipe/construction.dm
index 18bea1f105ef0..c62cf1eed5397 100644
--- a/code/game/objects/machinery/pipe/construction.dm
+++ b/code/game/objects/machinery/pipe/construction.dm
@@ -130,6 +130,8 @@ Buildable meters
/obj/item/pipe/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(user.incapacitated())
return FALSE
if(iswrench(I))
diff --git a/code/game/objects/machinery/pipe/pipe_dispenser.dm b/code/game/objects/machinery/pipe/pipe_dispenser.dm
index bbacead24a43a..efd04f3c2dc88 100644
--- a/code/game/objects/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/objects/machinery/pipe/pipe_dispenser.dm
@@ -64,6 +64,8 @@
/obj/machinery/pipedispenser/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/pipe) || istype(I, /obj/item/pipe_meter))
to_chat(usr, span_notice("You put [I] back into [src]."))
diff --git a/code/game/objects/machinery/portable_reagent_tank.dm b/code/game/objects/machinery/portable_reagent_tank.dm
index 68a1a1c60f87b..3da26bacf4607 100644
--- a/code/game/objects/machinery/portable_reagent_tank.dm
+++ b/code/game/objects/machinery/portable_reagent_tank.dm
@@ -66,9 +66,9 @@
var/obj/item/storage/internal_bag = get_internal_item()
internal_bag?.open(user)
-/obj/machinery/deployable/reagent_tank/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
- if(X.a_intent != INTENT_HARM)
- return drink_from_nozzle(X, TRUE)
+/obj/machinery/deployable/reagent_tank/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.a_intent != INTENT_HARM)
+ return drink_from_nozzle(xeno_attacker, TRUE)
return ..()
///Process for drinking reagents directly from the dispenser's nozzle
@@ -122,7 +122,7 @@
icon_state = "dispenser"
item_state_worn = TRUE
item_state = "reagent_dispenser"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
max_w_class = WEIGHT_CLASS_SMALL //Beaker size
storage_slots = null
@@ -172,16 +172,16 @@
update_icon()
/obj/item/storage/reagent_tank/attack_hand(mob/living/user)
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYED))
return open(user)
return ..()
/obj/item/storage/reagent_tank/open(mob/user)
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYED))
return ..()
/obj/item/storage/reagent_tank/attempt_draw_object(mob/living/user)
- if(!CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(!CHECK_BITFIELD(item_flags, IS_DEPLOYED))
balloon_alert(user, "Not deployed")
return FALSE
return ..()
@@ -190,7 +190,7 @@
balloon_alert(user, "Not deployed")
/obj/item/storage/reagent_tank/can_be_inserted(obj/item/W, warning)
- if(!CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(!CHECK_BITFIELD(item_flags, IS_DEPLOYED))
balloon_alert(usr, "Not deployed")
return FALSE
return ..()
diff --git a/code/game/objects/machinery/recharger.dm b/code/game/objects/machinery/recharger.dm
index 4c4f48c0fbe9d..41868a9ba86bb 100644
--- a/code/game/objects/machinery/recharger.dm
+++ b/code/game/objects/machinery/recharger.dm
@@ -12,6 +12,8 @@
/obj/machinery/recharger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(issilicon(user))
return
@@ -140,29 +142,29 @@
B.bcell.charge = 0
..(severity)
-/obj/machinery/recharger/update_icon()
- overlays = list()
+/obj/machinery/recharger/update_overlays()
+ . = ..()
if((machine_stat & (NOPOWER|BROKEN)))
return
- else if(!charging)
- overlays += "recharger-power"
+ if(!charging)
+ . += "recharger-power"
return
if(percent_charge_complete < 25)
- overlays += "recharger-10"
+ . += "recharger-10"
else if(percent_charge_complete >= 25 && percent_charge_complete < 50)
- overlays += "recharger-25"
+ . += "recharger-25"
else if(percent_charge_complete >= 50 && percent_charge_complete < 75)
- overlays += "recharger-50"
+ . += "recharger-50"
else if(percent_charge_complete >= 75 && percent_charge_complete < 100)
- overlays += "recharger-75"
+ . += "recharger-75"
else if(percent_charge_complete >= 100)
- overlays += "recharger-100"
+ . += "recharger-100"
if(istype(charging, /obj/item/weapon/gun/energy/taser))
- overlays += "recharger-taser"
+ . += "recharger-taser"
else if(istype(charging, /obj/item/weapon/baton))
- overlays += "recharger-baton"
+ . += "recharger-baton"
/obj/machinery/recharger/nopower
use_power = NO_POWER_USE
diff --git a/code/game/objects/machinery/research.dm b/code/game/objects/machinery/research.dm
index 84e8b8b2b0d8a..097a7cd36a62b 100644
--- a/code/game/objects/machinery/research.dm
+++ b/code/game/objects/machinery/research.dm
@@ -48,7 +48,6 @@
RES_TIER_UNCOMMON = list(
/obj/item/research_product/money/uncommon,
/obj/item/implanter/blade,
- /obj/item/attachable/shoulder_mount,
),
RES_TIER_RARE = list(
/obj/item/research_product/money/rare,
@@ -65,7 +64,6 @@
RES_TIER_UNCOMMON = list(
/obj/item/research_product/money/uncommon,
/obj/item/implanter/chem/blood,
- /obj/item/attachable/shoulder_mount,
),
RES_TIER_RARE = list(
/obj/item/research_product/money/rare,
@@ -90,6 +88,8 @@
/obj/machinery/researchcomp/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(researching || !istype(I, /obj/item/research_resource))
return
@@ -248,16 +248,10 @@
)
/obj/item/research_resource/xeno
+ name = "Xenomorph research material"
research_type = RES_XENO
icon = 'icons/obj/alien_autopsy.dmi'
icon_state = "sample_0"
-
-/obj/item/research_resource/xeno/Initialize(mapload)
- . = ..()
- icon_state = "sample_[rand(0, 11)]"
-
-/obj/item/research_resource/xeno/tier_one
- name = "Xenomorph research material - tier 1"
color = "#f0bee3"
reward_probs = list(
RES_TIER_BASIC = 100,
@@ -266,35 +260,9 @@
RES_TIER_RARE = 1,
)
-/obj/item/research_resource/xeno/tier_two
- name = "Xenomorph research material - tier 2"
- color = "#d6e641"
- reward_probs = list(
- RES_TIER_BASIC = 100,
- RES_TIER_COMMON = 40,
- RES_TIER_UNCOMMON = 20,
- RES_TIER_RARE = 6,
- )
-
-/obj/item/research_resource/xeno/tier_three
- name = "Xenomorph research material - tier 3"
- color = "#e43939"
- reward_probs = list(
- RES_TIER_BASIC = 100,
- RES_TIER_COMMON = 50,
- RES_TIER_UNCOMMON = 40,
- RES_TIER_RARE = 10,
- )
-
-/obj/item/research_resource/xeno/tier_four
- name = "Xenomorph research material - tier 4"
- color = "#a800ad"
- reward_probs = list(
- RES_TIER_BASIC = 100,
- RES_TIER_COMMON = 50,
- RES_TIER_UNCOMMON = 40,
- RES_TIER_RARE = 50,
- )
+/obj/item/research_resource/xeno/Initialize(mapload)
+ . = ..()
+ icon_state = "sample_[rand(0, 11)]"
///
///Items designed to be products of research
diff --git a/code/game/objects/machinery/robotic_cradle.dm b/code/game/objects/machinery/robotic_cradle.dm
index 69bf7b1f3d26f..4567a7d5b87c3 100644
--- a/code/game/objects/machinery/robotic_cradle.dm
+++ b/code/game/objects/machinery/robotic_cradle.dm
@@ -1,62 +1,57 @@
#define CRADLE_NOTICE_SUCCESS 1
#define CRADLE_NOTICE_DEATH 2
-#define CRADLE_NOTICE_NO_RECORD 3
-#define CRADLE_NOTICE_NO_POWER 4
-#define CRADLE_NOTICE_XENO_FUCKERY 5
-#define CRADLE_NOTICE_IDIOT_EJECT 6
-#define CRADLE_NOTICE_FORCE_EJECT 7
+#define CRADLE_NOTICE_NO_POWER 3
+#define CRADLE_NOTICE_XENO_FUCKERY 4
+#define CRADLE_NOTICE_EARLY_EJECT 5
//Cradle
/obj/machinery/robotic_cradle
name = "robotic cradle"
desc = "A highly experimental robotic maintenence machine using a bath of industrial nanomachines to quickly restore any robotic machine inserted."
- icon = 'icons/obj/objects.dmi'
- icon_state = "borgcharger0"
+ icon = 'icons/obj/machines/suit_cycler.dmi'
+ icon_state = "suit_cycler"
density = TRUE
max_integrity = 350
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, FIRE = 30, ACID = 30)
- //This var is used to see if the machine is currently repairing or not.
- var/repairing = FALSE
- //This var is the reference used for the patient
- var/mob/living/carbon/human/occupant
-
//It uses power
use_power = ACTIVE_POWER_USE
idle_power_usage = 15
active_power_usage = 10000 // It rebuilds you from nothing...
- //This var is in reference to the radio the cradle uses to speak to the craw.
+ ///This var is used to see if the machine is currently repairing or not.
+ var/repairing = FALSE
+ ///This var is the reference used for the patient
+ var/mob/living/carbon/human/occupant
+ ///This var is in reference to the radio the cradle uses to speak to the crew
var/obj/item/radio/headset/mainship/doc/radio
+ ///This var is so we can call deltimer() it if we need to abort the operation early
+ var/operation_timer
/obj/machinery/robotic_cradle/Initialize(mapload)
. = ..()
radio = new(src)
/obj/machinery/robotic_cradle/Destroy()
- do_eject(forceeject = TRUE)
+ if(occupant)
+ visible_message("\The [src] malfunctions as it is destroyed mid-repair, ejecting [occupant] with unfinished repair wounds and showering them in debris.")
+ occupant.take_limb_damage(rand(30,50),rand(30,50))
+ remove_occupant()
if(radio)
QDEL_NULL(radio)
return ..()
/obj/machinery/robotic_cradle/update_icon_state()
- if(machine_stat & NOPOWER)
- icon_state = "borgcharger0"
- return
- if(repairing)
- icon_state = "borgcharger1"
- return
- if(occupant)
- icon_state = "borgcharger1"
- return
- icon_state = "borgcharger0"
+ if(occupant && !(machine_stat & NOPOWER))
+ icon_state = "suit_cycler_active"
+ return ..()
+ icon_state = "suit_cycler"
/obj/machinery/robotic_cradle/power_change()
. = ..()
if(is_operational() || !occupant)
return
visible_message("[src] engages the safety override, ejecting the occupant.")
- repairing = FALSE
- go_out(CRADLE_NOTICE_NO_POWER)
+ perform_eject(CRADLE_NOTICE_NO_POWER)
/obj/machinery/robotic_cradle/process()
if(!occupant)
@@ -64,45 +59,22 @@
if(occupant.stat == DEAD)
say("Patient has expired.")
- repairing = FALSE
- go_out(CRADLE_NOTICE_DEATH)
+ perform_eject(CRADLE_NOTICE_DEATH)
return
if(!repairing)
return
-//This proc handles the actual repair once the timer is up, ejection of the healed robot and radio message of ejection.
-/obj/machinery/robotic_cradle/proc/repair_op()
- if(QDELETED(occupant) || occupant.stat == DEAD)
- if(!ishuman(occupant))
- stack_trace("Non-human occupant made its way into the autodoc: [occupant] | [occupant?.type].")
- visible_message("[src] buzzes.")
- go_out(CRADLE_NOTICE_DEATH) //kick them out too.
- return
-
- occupant.revive()
- visible_message("\The [src] clicks and opens up having finished the requested operations.")
- repairing = FALSE
- go_out(CRADLE_NOTICE_SUCCESS)
-
-/obj/machinery/robotic_cradle/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/robotic_cradle/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
- return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
- playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
- go_out()
+ start_emergency_eject(xeno_attacker)
-//This proc acts as a heads up to the doctors/engineers about the patient exiting the cradle for whatever reason. Does not warn if the patient itself exits the cradle. it also wipes the memory of who the patient was and readies the cradle for a new patient.
-/obj/machinery/robotic_cradle/proc/go_out(notice_code = FALSE)
- if(!occupant)
- return
- occupant.forceMove(drop_location())
+///This proc acts as a heads up to the doctors/engineers about the patient exiting the cradle for whatever reason. Takes CRADLE_NOTICE defines as arguments
+/obj/machinery/robotic_cradle/proc/notify_about_eject(notice_code = FALSE)
var/reason = "Reason for discharge: Procedural completion."
switch(notice_code)
if(CRADLE_NOTICE_SUCCESS)
@@ -110,167 +82,169 @@
if(CRADLE_NOTICE_DEATH)
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
reason = "Reason for discharge: Patient has expired."
- if(CRADLE_NOTICE_NO_RECORD)
- playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
- reason = "Reason for discharge: Medical records not detected. Alerting security advised."
if(CRADLE_NOTICE_NO_POWER)
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
reason = "Reason for discharge: Power failure."
if(CRADLE_NOTICE_XENO_FUCKERY)
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
reason = "Reason for discharge: Unauthorized manual release. Alerting security advised."
- if(CRADLE_NOTICE_IDIOT_EJECT)
- playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
- reason = "Reason for discharge: Unauthorized manual release during repair. Alerting security advised."
- if(CRADLE_NOTICE_FORCE_EJECT)
- playsound(src, 'sound/machines/warning-buzzer.ogg', 50, FALSE)
- reason = "Reason for discharge: Destruction of linked CRADLE Engineering System. Alerting security advised."
+ if(CRADLE_NOTICE_EARLY_EJECT)
+ playsound(src,'sound/machines/buzz-two.ogg',50,FALSE)
+ reason = "Reason for discharge: Operation manually terminated by end user."
+ if(!radio)//The radio shouldn't ever be deleted, but this is a sanity check just in case
+ return
radio.talk_into(src, "Patient: [occupant] has been released from [src] at: [get_area(src)]. [reason]", RADIO_CHANNEL_MEDICAL)
+
+///Forces the occupant out of the cradle, leaves it empty for someone else to enter.
+/obj/machinery/robotic_cradle/proc/remove_occupant()
+ if(!occupant)
+ return
+ occupant.forceMove(drop_location())
occupant = null
update_icon()
stop_processing()
-//This proc is what a robot calls when they try to enter a cradle on their own.
-/obj/machinery/robotic_cradle/proc/move_inside_wrapper(mob/living/dropped, mob/dragger)
- if(dragger.incapacitated() || !ishuman(dragger) || !isrobot(dropped))
- return
-
+///Finishes ejecting the patient after the cradle is done. Takes CRADLE_NOTICE defines as arguments, used in notify_about_eject()
+/obj/machinery/robotic_cradle/proc/perform_eject(notice_code = FALSE)
+ repairing = FALSE
+ if(operation_timer)
+ deltimer(operation_timer)
+ notify_about_eject(notice_code)
+ remove_occupant()
+
+///Handles any mob placing themselves or someone else into the cradle. target_mob is the mob being placed in, operating_mob is the person placing the mob in. Returns true if the mob got placed inside, false otherwise
+/obj/machinery/robotic_cradle/proc/place_mob_inside(mob/living/target_mob, mob/operating_mob)
+ if(operating_mob.incapacitated()||!ishuman(operating_mob)||!ishuman(target_mob))
+ return FALSE
if(occupant)
- to_chat(dragger, span_notice("[src] is already occupied!"))
- return
-
+ to_chat(operating_mob, span_notice("[src] is already occupied!"))
+ return FALSE
+ var/mob/living/carbon/human/patient = target_mob
+ if(!(patient.species.species_flags & ROBOTIC_LIMBS))
+ visible_message(span_warning("[src] buzzes. Subject is biological, cannot repair"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 50, FALSE)
+ return FALSE
+ if(patient.abiotic())
+ visible_message(span_warning("[src] buzzes. Subject cannot wear abiotic items."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 50, FALSE)
+ return FALSE
if(machine_stat & (NOPOWER|BROKEN))
- to_chat(dragger, span_notice("[src] is non-functional!"))
+ to_chat(operating_mob, span_notice("[src] is non-functional!"))
+ return FALSE
+
+ if(operating_mob == patient)
+ patient.visible_message(span_notice("[patient] starts climbing into \the [src]."),
+ span_notice("You start climbing into \the [src]."))
+ else
+ operating_mob.visible_message(span_notice("[operating_mob] starts placing [patient] \the [src]."),
+ span_notice("You start placing [patient] into \the [src]."))
+
+ if(!do_after(patient, 1 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_GENERIC))
+ return FALSE
+ if(occupant) //In case someone tried climbing in earlier than us, while the cradle was empty
+ to_chat(operating_mob, span_notice("[src] is already occupied!"))
+ return FALSE
+ patient.stop_pulling()
+ patient.forceMove(src)
+ occupant = patient
+ return TRUE
+///Starts the repair operation of the cradle
+/obj/machinery/robotic_cradle/proc/start_repair_operation()
+ if(!occupant)
return
- if(dragger.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
- dropped.visible_message(span_notice("[dropped] fumbles around figuring out how to get into \the [src]."),
- span_notice("You fumble around figuring out how to get into \the [src]."))
- var/fumbling_time = max(0 , SKILL_TASK_TOUGH - ( SKILL_TASK_EASY * dragger.skills.getRating(SKILL_ENGINEER) ))// 8 secs non-trained, 5 amateur
- if(!do_after(dropped, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
- return
-
- dropped.visible_message(span_notice("[dropped] starts climbing into \the [src]."),
- span_notice("You start climbing into \the [src]."))
- if(!do_after(dropped, 1 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_GENERIC))
+ if(powered())
+ use_power(active_power_usage)
+ playsound(loc, 'sound/machines/ping.ogg', 25, 1)
+ else
+ perform_eject(CRADLE_NOTICE_NO_POWER)
return
- if(occupant)
- to_chat(dragger, span_notice("[src] is already occupied!"))
- return
- dropped.stop_pulling()
- dropped.forceMove(src)
- occupant = dropped
- icon_state = "pod_0"
- var/implants = list(/obj/item/implant/neurostim)
- var/mob/living/carbon/human/H = occupant
- var/doc_dat
- med_scan(H, doc_dat, implants, TRUE)
- start_processing()
- say("Automatic mode engaged, initialising procedure.")
- addtimer(CALLBACK(src, PROC_REF(auto_start)), 20 SECONDS)
-
-///Callback to start auto mode on someone entering
-/obj/machinery/robotic_cradle/proc/auto_start()
- if(repairing)
+ start_processing()
+ update_icon()
+ repairing = TRUE
+ say("Automatic mode engaged, initialising repair procedure.")
+ operation_timer = addtimer(CALLBACK(src, PROC_REF(handle_repair_operation)), 20 SECONDS,TIMER_STOPPABLE)
+
+///Callback to start repair on someone entering the cradle
+/obj/machinery/robotic_cradle/proc/handle_repair_operation()
+ if(!occupant) //sanity check, in case we get teleported outside the cradle midrepair without calling perform_eject()
+ if(operation_timer)
+ deltimer(operation_timer)
+ repairing = FALSE
+ visible_message(span_warning("[src] buzzes. Occupant missing, procedures canceled."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 50, FALSE)
return
+ say("Repair procedure complete.")
+ perform_repair()
+
+///This proc handles the actual repair once the timer is up and ejects the healed robot.
+/obj/machinery/robotic_cradle/proc/perform_repair()
if(!occupant)
- say("Occupant missing, procedures canceled.")
return
- say("Beginning repair procedure.")
- repair_op()
+ if(QDELETED(occupant) || occupant.stat == DEAD)
+ if(!ishuman(occupant))
+ stack_trace("Non-human occupant made its way into the autodoc: [occupant] | [occupant?.type].")
+ visible_message(span_warning("[src] buzzes."))
+ perform_eject(CRADLE_NOTICE_DEATH)
+ return
+ occupant.revive()
+ visible_message("\The [src] clicks and opens up having finished the requested operations.")
+ perform_eject(CRADLE_NOTICE_SUCCESS)
-/obj/machinery/robotic_cradle/MouseDrop_T(mob/M, mob/user)
+/obj/machinery/robotic_cradle/MouseDrop_T(mob/dropping, mob/user)
. = ..()
- move_inside_wrapper(M, user)
+ if(place_mob_inside(dropping, user))
+ start_repair_operation()
/obj/machinery/robotic_cradle/verb/move_inside()
set name = "Enter Cradle"
set category = "Object"
set src in oview(1)
- move_inside_wrapper(usr, usr)
+ if(place_mob_inside(usr, usr))
+ start_repair_operation()
-//This proc is called when someone has a robot grabbed either by hand or in a stasis bag. It is also lets docs/engineers use health analyzers on the cradle if they really want to.
/obj/machinery/robotic_cradle/attackby(obj/item/I, mob/user, params)
. = ..()
-
- if(!ishuman(user))
- return //no
+ if(.)
+ return
if(istype(I, /obj/item/healthanalyzer) && occupant) //Allows us to use the analyzer on the occupant without taking him out.
var/obj/item/healthanalyzer/J = I
J.attack(occupant, user)
return
- if(!istype(I, /obj/item/grab))
+/obj/machinery/robotic_cradle/attack_hand(mob/living/user)
+ . = ..()
+ if(user.do_actions) //stops them from spamming if they're attempting to eject someone or otherwise busy
return
-
- if(machine_stat & (NOPOWER|BROKEN))
- to_chat(user, span_notice("[src] is non-functional!"))
+ if(!occupant)
return
+ start_emergency_eject(user)
- if(occupant)
- to_chat(user, span_notice("[src] is already occupied!"))
+/obj/machinery/robotic_cradle/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
return
+ var/mob/grabbed_mob
- var/obj/item/grab/G = I
+ if(ismob(grab.grabbed_thing))
+ grabbed_mob = grab.grabbed_thing
- var/mob/M
- if(ismob(G.grabbed_thing))
- M = G.grabbed_thing
- else if(istype(G.grabbed_thing, /obj/structure/closet/bodybag/cryobag))
- var/obj/structure/closet/bodybag/cryobag/C = G.grabbed_thing
- if(!C.bodybag_occupant)
+ else if(istype(grab.grabbed_thing,/obj/structure/closet/bodybag/cryobag))
+ var/obj/structure/closet/bodybag/cryobag/cryobag = grab.grabbed_thing
+ if(!cryobag.bodybag_occupant)
to_chat(user, span_warning("The stasis bag is empty!"))
return
- M = C.bodybag_occupant
- C.open()
- user.start_pulling(M)
-
- if(!M)
- return
-
- if(!ishuman(M)) // No monkee or beano
- to_chat(user, span_notice("[src] is compatible with humanoid anatomies only!"))
- return
-
- if(M.abiotic())
- to_chat(user, span_warning("Subject cannot have abiotic items on."))
- return
-
- if(ishumanbasic(M))
- to_chat(user, span_warning("Subject is biological, cannot repair."))
- return
-
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
- user.visible_message(span_notice("[user] fumbles around figuring out how to put [M] into [src]."),
- span_notice("You fumble around figuring out how to put [M] into [src]."))
- var/fumbling_time = max(0 , SKILL_TASK_TOUGH - ( SKILL_TASK_EASY * user.skills.getRating(SKILL_ENGINEER) ))// 8 secs non-trained, 5 amateur
- if(!do_after(user, fumbling_time, NONE, M, BUSY_ICON_UNSKILLED) || QDELETED(src))
- return
-
- visible_message("[user] starts putting [M] into [src].", 3)
-
- if(!do_after(user, 10, IGNORE_HELD_ITEM, M, BUSY_ICON_GENERIC) || QDELETED(src))
- return
-
- if(occupant)
- to_chat(user, span_notice("[src] is already occupied!"))
- return
+ grabbed_mob = cryobag.bodybag_occupant
+ cryobag.open()
+ user.start_pulling(grabbed_mob)
- if(!M || !G)
- return
+ if(place_mob_inside(grabbed_mob,user))
+ start_repair_operation()
- M.forceMove(src)
- occupant = M
- icon_state = "pod_1"
- var/implants = list(/obj/item/implant/neurostim)
- var/mob/living/carbon/human/H = occupant
- med_scan(H, null, implants, TRUE)
- start_processing()
- say("Automatic mode engaged, initialising procedure.")
- addtimer(CALLBACK(src, PROC_REF(auto_start)), 20 SECONDS)
+ return TRUE
/obj/machinery/robotic_cradle/verb/eject()
set name = "Eject cradle"
@@ -278,45 +252,34 @@
set src in oview(1)
if(usr.incapacitated())
return
- do_eject()
+ start_emergency_eject(usr)
-//This proc ejects whomever is inside the cradle, by force if needed depending if the cradle is destroyed or not.
-/obj/machinery/robotic_cradle/proc/do_eject(forceeject)
+///This proc ejects whomever is inside the cradle while it is presumably operating. mob_ejecting is the mob triggering the eject
+/obj/machinery/robotic_cradle/proc/start_emergency_eject(mob/mob_ejecting)
if(!occupant)
return
- if(forceeject)
- if(!repairing)
- visible_message("\The [src] is destroyed, ejecting [occupant] and showering them in debris.")
- occupant.take_limb_damage(rand(10,20),rand(10,20))
- else
- visible_message("\The [src] malfunctions as it is destroyed mid-repair, ejecting [occupant] with unfinished repair wounds and showering them in debris.")
- occupant.take_limb_damage(rand(30,50),rand(30,50))
- go_out(CRADLE_NOTICE_FORCE_EJECT)
- return
- if(isxeno(usr) && !repairing) // let xenos eject people hiding inside; a xeno ejecting someone during repair does so like someone untrained
- go_out(CRADLE_NOTICE_XENO_FUCKERY)
+ if(!repairing)//this shouldn't be possible unless you get var edited inside without triggering start_repair_operation(), in that case just get them out
+ remove_occupant()
return
- if(!ishuman(usr))
+ if(!mob_ejecting)
+ perform_eject(CRADLE_NOTICE_EARLY_EJECT)
return
- if(usr == occupant)
- if(repairing)
- to_chat(usr, span_warning("There's no way you're getting out while this thing is operating on you!"))
- return
- else
- visible_message("[usr] engages the internal release mechanism, and climbs out of \the [src].")
- if(usr.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
- usr.visible_message(span_notice("[usr] fumbles around figuring out how to use [src]."),
- span_notice("You fumble around figuring out how to use [src]."))
- var/fumbling_time = max(0 , SKILL_TASK_TOUGH - ( SKILL_TASK_EASY * usr.skills.getRating(SKILL_ENGINEER) ))// 8 secs non-trained, 5 amateur
- if(!do_after(usr, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED) || !occupant)
+ if(isxeno(mob_ejecting))
+ mob_ejecting.visible_message(span_notice("[mob_ejecting] pries the cover of [src]"),
+ span_notice("You begin to pry at the cover of [src]."))
+ playsound(mob_ejecting,'sound/effects/metal_creaking.ogg', 25, 1)
+ if(!do_after(mob_ejecting, 2 SECONDS, NONE, src, BUSY_ICON_DANGER) || !occupant)
return
- if(repairing)
- repairing = 0
- if(usr.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) //Untrained people will fail to terminate the repair properly.
- visible_message("\The [src] malfunctions as [usr] aborts the rapair in progress.")
- occupant.take_limb_damage(rand(30,50),rand(30,50))
- log_game("[key_name(usr)] ejected [key_name(occupant)] from the cradle during repair causing damage.")
- message_admins("[ADMIN_TPMONTY(usr)] ejected [ADMIN_TPMONTY(occupant)] from the cradle during repair causing damage.")
- go_out(CRADLE_NOTICE_IDIOT_EJECT)
- return
- go_out()
+ perform_eject(CRADLE_NOTICE_XENO_FUCKERY)
+ return
+ if(!ishuman(mob_ejecting))
+ return
+ if(mob_ejecting == occupant)
+ to_chat(usr, span_warning("There's no way you're getting out while this thing is operating on you!"))
+ return
+ perform_eject(CRADLE_NOTICE_EARLY_EJECT)
+
+#undef CRADLE_NOTICE_SUCCESS
+#undef CRADLE_NOTICE_DEATH
+#undef CRADLE_NOTICE_NO_POWER
+#undef CRADLE_NOTICE_EARLY_EJECT
diff --git a/code/game/objects/machinery/seed_extractor.dm b/code/game/objects/machinery/seed_extractor.dm
index f7641018c92e5..14ce66e941761 100644
--- a/code/game/objects/machinery/seed_extractor.dm
+++ b/code/game/objects/machinery/seed_extractor.dm
@@ -9,6 +9,8 @@
/obj/machinery/seed_extractor/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
// Fruits and vegetables.
if(istype(I, /obj/item/reagent_containers/food/snacks/grown) || istype(I, /obj/item/grown))
if(!user.temporarilyRemoveItemFromInventory(I))
diff --git a/code/game/objects/machinery/self_destruct.dm b/code/game/objects/machinery/self_destruct.dm
index c31edda08bd86..95f89676ce6dd 100644
--- a/code/game/objects/machinery/self_destruct.dm
+++ b/code/game/objects/machinery/self_destruct.dm
@@ -81,7 +81,7 @@
if("dest_start")
to_chat(usr, span_notice("You press a few keys on the panel."))
to_chat(usr, span_notice("The system must be booting up the self-destruct sequence now."))
- priority_announce("Danger. The emergency destruct system is now activated. The ship will detonate in T-minus 20 minutes. Automatic detonation is unavailable. Manual detonation is required.", "Priority Alert", sound = 'sound/AI/selfdestruct.ogg')
+ priority_announce("Danger. The emergency destruct system is now activated. The ship will detonate in T-minus 20 minutes. Automatic detonation is unavailable. Manual detonation is required.", title = "Self Destruct System", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/selfdestruct.ogg', color_override = "purple")
active_state = SELF_DESTRUCT_MACHINE_ARMED
var/obj/machinery/self_destruct/rod/I = SSevacuation.dest_rods[SSevacuation.dest_index]
I.activate_time = world.time
diff --git a/code/game/objects/machinery/sleeper.dm b/code/game/objects/machinery/sleeper.dm
index 32cceba5f64ec..de45bf9a75985 100644
--- a/code/game/objects/machinery/sleeper.dm
+++ b/code/game/objects/machinery/sleeper.dm
@@ -261,6 +261,7 @@
set_light(initial(light_range))
/obj/machinery/sleeper/update_icon_state()
+ . = ..()
if(occupant)
icon_state = "[initial(icon_state)]_occupied"
else
@@ -277,36 +278,50 @@
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/healthanalyzer) && occupant) //Allows us to use the analyzer on the occupant without taking him out.
var/obj/item/healthanalyzer/J = I
J.attack(occupant, user)
return
+/obj/machinery/sleeper/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ return
if(isxeno(user))
return
-
+ if(machine_stat & (NOPOWER|BROKEN))
+ to_chat(user, span_notice("\ [src] is non-functional!"))
+ return
if(occupant)
- to_chat(user, span_notice("The sleeper is already occupied!"))
+ to_chat(user, span_notice("\ [src] is already occupied!"))
return
+ var/mob/grabbed_mob
- if(!istype(I, /obj/item/grab))
- return
-
- var/obj/item/grab/G = I
- if(!ismob(G.grabbed_thing))
+ if(ismob(grab.grabbed_thing))
+ grabbed_mob = grab.grabbed_thing
+ else if(istype(grab.grabbed_thing,/obj/structure/closet/bodybag/cryobag))
+ var/obj/structure/closet/bodybag/cryobag/cryobag = grab.grabbed_thing
+ if(!cryobag.bodybag_occupant)
+ to_chat(user, span_warning("The stasis bag is empty!"))
+ return
+ grabbed_mob = cryobag.bodybag_occupant
+ cryobag.open()
+ user.start_pulling(grabbed_mob)
+ if(!grabbed_mob)
return
- var/mob/M = G.grabbed_thing
- if(!M.forceMove(src))
+ if(!grabbed_mob.forceMove(src))
return
-
- visible_message("[user] puts [M] into the sleeper.", 3)
- occupant = M
+ visible_message("[user] puts [grabbed_mob] into the sleeper.", 3)
+ occupant = grabbed_mob
start_processing()
connected.start_processing()
update_icon()
+ return TRUE
/obj/machinery/sleeper/ex_act(severity)
if(filtering)
@@ -406,15 +421,15 @@
else
to_chat(user, span_notice("There is no one inside!"))
-/obj/machinery/sleeper/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/sleeper/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
+ visible_message(span_warning("[xeno_attacker] begins to pry the [src]'s cover!"), 3)
playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(!do_after(xeno_attacker, 2 SECONDS))
return
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
go_out()
diff --git a/code/game/objects/machinery/spaceheater.dm b/code/game/objects/machinery/spaceheater.dm
index 2fa3048c05004..56aea6421dc30 100644
--- a/code/game/objects/machinery/spaceheater.dm
+++ b/code/game/objects/machinery/spaceheater.dm
@@ -72,6 +72,8 @@
/obj/machinery/space_heater/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/cell))
return
if(!open)
diff --git a/code/game/objects/machinery/squad_manager.dm b/code/game/objects/machinery/squad_manager.dm
index a0621b2cda5b5..ecdf7489c4371 100644
--- a/code/game/objects/machinery/squad_manager.dm
+++ b/code/game/objects/machinery/squad_manager.dm
@@ -1,5 +1,7 @@
#define MAX_SQUAD_NAME_LEN 15
+GLOBAL_DATUM_INIT(squad_manager, /datum/squad_manager, new)
+
/obj/machinery/computer/squad_manager
name = "squad managment console"
desc = "A console for squad management. Allows squad leaders to manage their squad."
@@ -8,12 +10,21 @@
interaction_flags = INTERACT_OBJ_UI
/obj/machinery/computer/squad_manager/ui_interact(mob/user, datum/tgui/ui)
+ return GLOB.squad_manager.ui_interact(arglist(args))
+
+/datum/squad_manager
+ interaction_flags = INTERACT_UI_INTERACT
+
+/datum/squad_manager/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "SquadManager", name)
+ ui = new(user, src, "SquadManager", "Squad Management")
ui.open()
-/obj/machinery/computer/squad_manager/ui_data(mob/user)
+/datum/squad_manager/ui_state(mob/user)
+ return GLOB.conscious_state
+
+/datum/squad_manager/ui_data(mob/user)
var/list/data = list()
data["active_squads"] = list()
for(var/datum/squad/squad AS in SSjob.active_squads[user.faction])
@@ -22,7 +33,7 @@
data["valid_colors"] = GLOB.custom_squad_colors
return data
-/obj/machinery/computer/squad_manager/ui_act(action, list/params)
+/datum/squad_manager/ui_act(action, list/params)
. = ..()
if(.)
return
@@ -77,5 +88,5 @@
log_game(log_msg)
message_admins(log_msg)
new_squad.desc = new_desc
- ui_close(user)
- balloon_alert(user, "\"[new_name]\" created")
+ SStgui.close_user_uis(usr, src)
+ user.balloon_alert(user, "\"[new_name]\" created")
diff --git a/code/game/objects/machinery/squad_selector.dm b/code/game/objects/machinery/squad_selector.dm
index 9c12e733c5a8c..e7f0df80ba42f 100644
--- a/code/game/objects/machinery/squad_selector.dm
+++ b/code/game/objects/machinery/squad_selector.dm
@@ -1,3 +1,5 @@
+GLOBAL_DATUM_INIT(squad_selector, /datum/squad_selector, new)
+
/obj/machinery/computer/squad_selector
name = "squad selection console"
desc = "A console for squad management. Allows users to join a squad."
@@ -8,12 +10,21 @@
interaction_flags = INTERACT_OBJ_UI
/obj/machinery/computer/squad_selector/ui_interact(mob/user, datum/tgui/ui)
+ return GLOB.squad_selector.ui_interact(arglist(args))
+
+/datum/squad_selector
+ interaction_flags = INTERACT_UI_INTERACT
+
+/datum/squad_selector/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "SquadSelector", name)
+ ui = new(user, src, "SquadSelector", "Squad Selection")
ui.open()
-/obj/machinery/computer/squad_selector/ui_data(mob/user)
+/datum/squad_selector/ui_state(mob/user)
+ return GLOB.conscious_state
+
+/datum/squad_selector/ui_data(mob/user)
var/list/data = list()
if(!SSjob.active_squads[user.faction])
return data
@@ -24,7 +35,7 @@
data["active_squads"] = squad_data
return data
-/obj/machinery/computer/squad_selector/ui_act(action, list/params)
+/datum/squad_selector/ui_act(action, list/params)
. = ..()
if(.)
return
@@ -37,3 +48,4 @@
if(new_squad == user.assigned_squad)
return
user.change_squad(new_squad_id)
+ SStgui.close_user_uis(usr, src)
diff --git a/code/game/objects/machinery/squad_supply/supply_beacon.dm b/code/game/objects/machinery/squad_supply/supply_beacon.dm
index f4df56df68bf8..0ffc3da886c45 100644
--- a/code/game/objects/machinery/squad_supply/supply_beacon.dm
+++ b/code/game/objects/machinery/squad_supply/supply_beacon.dm
@@ -1,160 +1,10 @@
-/obj/item/beacon
- w_class = WEIGHT_CLASS_SMALL
- /// If this beacon is activated
- var/activated = FALSE
- /// How long to activate this beacon
- var/activation_time = 80
- /// The icon when acticated
- var/icon_activated = ""
- /// The camera attached to the beacon
- var/obj/machinery/camera/beacon_cam = null
- ///Can work underground
- var/underground_signal = FALSE
-
-/obj/item/beacon/update_icon_state()
- icon_state = activated ? icon_activated : initial(icon_state)
-
-/obj/item/beacon/attack_self(mob/living/carbon/human/H)
- if(!istype(H))
- return
- activate(H)
-
-/obj/item/beacon/attack_hand(mob/living/carbon/human/H)
- if(!ishuman(H))
- return ..()
- if(activated)
- deactivate(H)
- return
- return ..()
-
-/// Set this beacon on the ground and activate it
-/obj/item/beacon/proc/activate(mob/living/carbon/human/H)
- if(!is_ground_level(H.z))
- to_chat(H, span_warning("You have to be on the planet to use this or it won't transmit."))
- return FALSE
- var/area/A = get_area(H)
- if(A && istype(A) && A.ceiling >= CEILING_DEEP_UNDERGROUND && !underground_signal)
- to_chat(H, span_warning("This won't work if you're standing deep underground."))
- return FALSE
- if(istype(A, /area/shuttle/dropship))
- to_chat(H, span_warning("You have to be outside the dropship to use this or it won't transmit."))
- return FALSE
- var/delay = max(1.5 SECONDS, activation_time - 2 SECONDS * H.skills.getRating(SKILL_LEADERSHIP))
- H.visible_message(span_notice("[H] starts setting up [src] on the ground."),
- span_notice("You start setting up [src] on the ground and inputting all the data it needs."))
- if(!do_after(H, delay, NONE, src, BUSY_ICON_GENERIC))
- return FALSE
- var/obj/machinery/camera/beacon_cam/BC = new(src, "[H.get_paygrade()] [H.name] [src]")
- H.transferItemToLoc(src, H.loc)
- beacon_cam = BC
- message_admins("[ADMIN_TPMONTY(usr)] set up a supply beacon.")
- name = "transmitting orbital beacon - [get_area(src)] - [H]"
- activated = TRUE
- anchored = TRUE
- w_class = WEIGHT_CLASS_GIGANTIC
- layer = ABOVE_FLY_LAYER
- set_light(2, 1)
- playsound(src, 'sound/machines/twobeep.ogg', 15, 1)
- H.visible_message("[H] activates [src].",
- "You activate [src].")
-
- var/marker_flags = GLOB.faction_to_minimap_flag[H.faction]
- if(!marker_flags)
- marker_flags = MINIMAP_FLAG_MARINE
- //RUTGMC EDIT CHANGE BEGIN - ORBITAL_BEACON
- //SSminimaps.add_marker(src, marker_flags, image('icons/UI_icons/map_blips.dmi', null, "supply")) RUTGMC EDIT - ORIGINAL
- SSminimaps.add_marker(src, marker_flags, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, beacon_mini_icon, ABOVE_FLOAT_LAYER))
- //RUTGMC EDIT CHANGE END
- update_icon()
- return TRUE
-
-/// Deactivate this beacon and put it in the hand of the human
-/obj/item/beacon/proc/deactivate(mob/living/carbon/human/H)
- var/delay = max(1 SECONDS, activation_time * 0.5 - 2 SECONDS * H.skills.getRating(SKILL_LEADERSHIP)) //Half as long as setting it up.
- H.visible_message(span_notice("[H] starts removing [src] from the ground."),
- span_notice("You start removing [src] from the ground, deactivating it."))
- if(!do_after(H, delay, NONE, src, BUSY_ICON_GENERIC))
- return FALSE
- QDEL_NULL(beacon_cam)
- activated = FALSE
- anchored = FALSE
- w_class = initial(w_class)
- layer = initial(layer)
- name = initial(name)
- set_light(0)
- playsound(src, 'sound/machines/twobeep.ogg', 15, 1)
- H.visible_message("[H] deactivates [src].",
- "You deactivate [src].")
- H.put_in_active_hand(src)
- SSminimaps.remove_marker(src)
- update_icon()
- return TRUE
-
-/obj/item/beacon/Destroy()
- if(beacon_cam)
- qdel(beacon_cam)
- beacon_cam = null
- return ..()
-
-/obj/item/beacon/supply_beacon
+/obj/item/supply_beacon
name = "supply beacon"
desc = "A rugged, glorified laser pointer capable of sending a beam into space. Activate and throw this to call for a supply drop."
icon = 'icons/Marine/marine-navigation.dmi'
icon_state = "motion0"
- icon_activated = "motion2"
- activation_time = 60
- /// Reference to the datum used by the supply drop console
- var/datum/supply_beacon/beacon_datum
-
-/obj/item/beacon/supply_beacon/Destroy()
- if(beacon_datum)
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
- return ..()
-
-/// Signal handler to nullify beacon datum
-/obj/item/beacon/supply_beacon/proc/clean_beacon_datum()
- SIGNAL_HANDLER
- beacon_datum = null
-
-/obj/item/beacon/supply_beacon/onTransitZ(old_z,new_z)
- . = ..()
- //Assumes doMove sets loc before onTransitZ
- if(beacon_datum) // RUTGMC ADDITION, supply beacon runtime fix
- beacon_datum.drop_location = loc
-
-/obj/item/beacon/supply_beacon/activate(mob/living/carbon/human/H)
- var/area/A = get_area(H)
- . = ..()
- if(!.)
- return
- beacon_datum = new /datum/supply_beacon("[H.name] + [A]", loc, H.faction)
- RegisterSignal(beacon_datum, COMSIG_QDELETING, PROC_REF(clean_beacon_datum))
+ w_class = WEIGHT_CLASS_SMALL
-/obj/item/beacon/supply_beacon/deactivate(mob/living/carbon/human/H)
+/obj/item/supply_beacon/Initialize(mapload)
. = ..()
- if(!.)
- return
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
-
-/datum/supply_beacon
- /// Name printed on the supply console
- var/name = ""
- /// Where the supply drops will land
- var/turf/drop_location
- /// The faction of the beacon
- var/faction = ""
-
-/datum/supply_beacon/New(_name, turf/_drop_location, _faction, life_time = 0 SECONDS)
- name = _name
- drop_location = _drop_location
- faction = _faction
- GLOB.supply_beacon[name] = src
- if(life_time)
- QDEL_IN(src, life_time)
-
-/// Remove that beacon from the list of glob supply beacon
-/datum/supply_beacon/Destroy()
- GLOB.supply_beacon -= name
- return ..()
+ AddComponent(/datum/component/beacon, TRUE, 60, "motion2")
diff --git a/code/game/objects/machinery/squad_supply/supply_console.dm b/code/game/objects/machinery/squad_supply/supply_console.dm
index 18c246a5ea5fd..285b54ab0bc9e 100644
--- a/code/game/objects/machinery/squad_supply/supply_console.dm
+++ b/code/game/objects/machinery/squad_supply/supply_console.dm
@@ -25,6 +25,7 @@
/obj/machinery/computer/supplydrop_console/Initialize(mapload)
. = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_SUPPLY_BEACON_CREATED, PROC_REF(ping_beacon))
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/supplydrop_console/LateInitialize()
@@ -34,6 +35,11 @@
supply_pad = _supply_pad
return
+/// Used to notify of a new beacon target
+/obj/machinery/computer/supplydrop_console/proc/ping_beacon()
+ SIGNAL_HANDLER
+ playsound(src,'sound/machines/terminal_prompt_confirm.ogg', 50, TRUE)
+
/obj/machinery/computer/supplydrop_console/Destroy()
supply_beacon = null
supply_pad = null
@@ -68,8 +74,14 @@
switch(action)
if("select_beacon")
- var/datum/supply_beacon/supply_beacon_choice = GLOB.supply_beacon[tgui_input_list(ui.user, "Select the beacon to send supplies", "Beacon choice", GLOB.supply_beacon)]
- if(!istype(supply_beacon_choice))
+ var/list/beacon_list = GLOB.supply_beacon.Copy()
+ for(var/beacon_name in beacon_list)
+ var/datum/supply_beacon/beacon = beacon_list[beacon_name]
+ if(!is_ground_level(beacon.drop_location.z))
+ beacon_list -= beacon_name
+ continue
+ var/datum/supply_beacon/supply_beacon_choice = beacon_list[tgui_input_list(ui.user, "Select the beacon to send supplies", "Beacon choice", beacon_list)]
+ if(!istype(supply_beacon_choice) && is_ground_level(supply_beacon.drop_location.z))
return
supply_beacon = supply_beacon_choice
RegisterSignal(supply_beacon, COMSIG_QDELETING, PROC_REF(clean_supply_beacon), override = TRUE)
diff --git a/code/game/objects/machinery/suit_storage_unit.dm b/code/game/objects/machinery/suit_storage_unit.dm
index 3d4a67b897e4f..1a8a884f7b5cf 100644
--- a/code/game/objects/machinery/suit_storage_unit.dm
+++ b/code/game/objects/machinery/suit_storage_unit.dm
@@ -35,31 +35,32 @@
inserted_tank = new starting_tank_type(src)
update_icon()
-
-/obj/machinery/suit_storage_unit/update_icon()
- overlays.Cut()
- if(isUV)
- icon_state = "disinfecting"
+/obj/machinery/suit_storage_unit/update_overlays()
+ . = ..()
+ if(isUV || !isopen)
return
- else if(isopen)
- if(inserted_helmet)
- overlays += image("helmet")
- if(inserted_suit)
- overlays += image("suit")
- if(inserted_mask)
- overlays += image("mask")
- if(inserted_tank)
- overlays += image("tank")
+ if(inserted_helmet)
+ . += image("helmet")
+ if(inserted_suit)
+ . += image("suit")
+ if(inserted_mask)
+ . += image("mask")
+ if(inserted_tank)
+ . += image("tank")
- icon_state = "open"
+/obj/machinery/suit_storage_unit/update_icon_state()
+ . = ..()
+ if(isUV)
+ return
+ if(isopen)
+ icon_state = "open"
else
icon_state = "closed"
if(machine_stat & NOPOWER)
icon_state += "_off"
-
/obj/machinery/suit_storage_unit/power_change()
..()
if(machine_stat & NOPOWER)
@@ -228,6 +229,8 @@
/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(machine_stat & NOPOWER)
return
diff --git a/code/game/objects/machinery/telecomms/broadcasting.dm b/code/game/objects/machinery/telecomms/broadcasting.dm
index 54fd59fbc57e3..e87c0718dc798 100644
--- a/code/game/objects/machinery/telecomms/broadcasting.dm
+++ b/code/game/objects/machinery/telecomms/broadcasting.dm
@@ -186,7 +186,7 @@
// Add observers who have ghost radio enabled.
for(var/mob/dead/observer/ghost in GLOB.player_list)
- if(ghost.client.prefs.toggles_chat & CHAT_GHOSTRADIO)
+ if(ghost?.client?.prefs?.toggles_chat & CHAT_GHOSTRADIO)
receive |= ghost
// Render the message and have everybody hear it.
diff --git a/code/game/objects/machinery/telecomms/telecomunications.dm b/code/game/objects/machinery/telecomms/telecomunications.dm
index 37eee7febe775..523f07c031a19 100644
--- a/code/game/objects/machinery/telecomms/telecomunications.dm
+++ b/code/game/objects/machinery/telecomms/telecomunications.dm
@@ -144,7 +144,8 @@ GLOBAL_LIST_EMPTY(telecomms_freq_listening_list)
return
-/obj/machinery/telecomms/update_icon()
+/obj/machinery/telecomms/update_icon_state()
+ . = ..()
if(on)
if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
icon_state = "[initial(icon_state)]_o"
diff --git a/code/game/objects/machinery/vending/beginner_vendor.dm b/code/game/objects/machinery/vending/beginner_vendor.dm
new file mode 100644
index 0000000000000..3824ab4aad171
--- /dev/null
+++ b/code/game/objects/machinery/vending/beginner_vendor.dm
@@ -0,0 +1,39 @@
+//Beginner Vendor
+
+GLOBAL_LIST_INIT(beginner_loadouts, init_beginner_loadouts())
+
+/proc/init_beginner_loadouts() //List of all loadouts in quick_load_beginners.dm
+ . = list()
+ var/list/loadout_list = list(
+ /datum/outfit/quick/beginner/marine/rifleman,
+ /datum/outfit/quick/beginner/marine/machinegunner,
+ /datum/outfit/quick/beginner/marine/marksman,
+ /datum/outfit/quick/beginner/marine/shotgunner,
+ /datum/outfit/quick/beginner/marine/shocktrooper,
+ /datum/outfit/quick/beginner/marine/hazmat,
+ /datum/outfit/quick/beginner/marine/cqc,
+ /datum/outfit/quick/beginner/marine/chad,
+ /datum/outfit/quick/beginner/engineer/builder,
+ /datum/outfit/quick/beginner/engineer/burnitall,
+ /datum/outfit/quick/beginner/engineer/pcenjoyer,
+ /datum/outfit/quick/beginner/corpsman/lifesaver,
+ /datum/outfit/quick/beginner/corpsman/hypobelt,
+ /datum/outfit/quick/beginner/smartgunner/sg29,
+ /datum/outfit/quick/beginner/smartgunner/sg85,
+ )
+
+ for(var/X in loadout_list)
+ .[X] = new X
+
+/obj/machinery/quick_vendor/beginner //Loadout vendor that shits out basic pre-made loadouts so new players can get something usable
+ icon_state = "loadoutvendor"
+ categories = list(
+ "Squad Marine",
+ "Squad Engineer",
+ "Squad Corpsman",
+ "Squad Smartgunner",
+ )
+ drop_worn_items = TRUE
+
+/obj/machinery/quick_vendor/beginner/set_stock_list()
+ global_list_to_use = GLOB.beginner_loadouts
diff --git a/code/game/objects/machinery/vending/loadout_vendor.dm b/code/game/objects/machinery/vending/loadout_vendor.dm
index ba5fd54604b59..42539a1bc0d42 100644
--- a/code/game/objects/machinery/vending/loadout_vendor.dm
+++ b/code/game/objects/machinery/vending/loadout_vendor.dm
@@ -26,6 +26,7 @@
set_light(0)
/obj/machinery/loadout_vendor/update_icon_state()
+ . = ..()
if(is_operational())
icon_state = initial(icon_state)
else
diff --git a/code/game/objects/machinery/vending/marine_vending.dm b/code/game/objects/machinery/vending/marine_vending.dm
index 0c65676120a03..ce3dfdcdca327 100644
--- a/code/game/objects/machinery/vending/marine_vending.dm
+++ b/code/game/objects/machinery/vending/marine_vending.dm
@@ -23,18 +23,23 @@
),
"Energy Weapons" = list(
/obj/item/cell/lasgun/lasrifle = -1,
+ /obj/item/cell/lasgun/volkite/powerpack/marine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_sniper = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/tesla = 2,
+ /obj/item/cell/lasgun/plasma = -1,
),
"SMGs" = list(
/obj/item/weapon/gun/smg/standard_smg = -1,
/obj/item/ammo_magazine/smg/standard_smg = -1,
/obj/item/weapon/gun/smg/standard_machinepistol = -1,
/obj/item/ammo_magazine/smg/standard_machinepistol = -1,
+ /obj/item/weapon/gun/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg/squashhead = -1,
),
"Marksman" = list(
/obj/item/weapon/gun/rifle/standard_dmr = -1,
@@ -80,7 +85,6 @@
/obj/item/weapon/twohanded/spear/tactical = -1,
/obj/item/weapon/twohanded/glaive/harvester = -1,
/obj/item/weapon/powerfist = -1,
- /obj/item/weapon/shield/riot/marine = 6,
/obj/item/weapon/shield/riot/marine/deployable = 6,
/obj/item/weapon/combat_knife/harvester = 12,
),
@@ -116,9 +120,11 @@
/obj/item/explosive/grenade/incendiary = 50,
/obj/item/explosive/grenade/smokebomb = 25,
/obj/item/explosive/grenade/smokebomb/cloak = 25,
+ /obj/item/explosive/grenade/smokebomb/antigas = 20,
/obj/item/explosive/grenade/sticky/cloaker = 10,
- /obj/item/explosive/grenade/smokebomb/drain = 10,
/obj/item/explosive/grenade/mirage = 100,
+ /obj/item/explosive/grenade/bullet/laser = 30,
+ /obj/item/explosive/grenade/bullet/hefa = 10,
/obj/item/storage/box/m94 = 200,
/obj/item/storage/box/m94/cas = 30,
),
@@ -136,7 +142,7 @@
/obj/structure/closet/crate/mortar_ammo/mortar_kit = 1,
/obj/structure/closet/crate/mortar_ammo/howitzer_kit = 1,
/obj/item/storage/box/crate/sentry = 4,
- /obj/item/storage/box/tl102 = 1,
+ /obj/item/storage/box/hsg_102 = 1,
/obj/item/weapon/gun/heavymachinegun = 1,
/obj/item/ammo_magazine/heavymachinegun = 5,
/obj/item/ammo_magazine/heavymachinegun/small = 10,
@@ -169,8 +175,6 @@
/obj/item/ammo_magazine/rifle/pepperball/pepperball_mini = -1,
/obj/item/attachable/stock/t76 = -1,
/obj/item/attachable/flamer_nozzle = -1,
- /obj/item/attachable/flamer_nozzle/wide = -1,
- /obj/item/attachable/flamer_nozzle/long = -1,
),
"Boxes" = list(
/obj/item/ammo_magazine/packet/p9mm = -1,
@@ -239,18 +243,23 @@
),
"Energy Weapons" = list(
/obj/item/cell/lasgun/lasrifle = -1,
+ /obj/item/cell/lasgun/volkite/powerpack/marine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_sniper = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/tesla = 2,
+ /obj/item/cell/lasgun/plasma = -1,
),
"SMGs" = list(
/obj/item/weapon/gun/smg/standard_smg = -1,
/obj/item/ammo_magazine/smg/standard_smg = -1,
/obj/item/weapon/gun/smg/standard_machinepistol = -1,
/obj/item/ammo_magazine/smg/standard_machinepistol = -1,
+ /obj/item/weapon/gun/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg/squashhead = -1,
),
"Marksman" = list(
/obj/item/weapon/gun/rifle/standard_dmr = -1,
@@ -295,7 +304,6 @@
/obj/item/weapon/twohanded/spear/tactical = -1,
/obj/item/weapon/twohanded/glaive/harvester = -1,
/obj/item/weapon/powerfist = -1,
- /obj/item/weapon/shield/riot/marine = 6,
/obj/item/weapon/shield/riot/marine/deployable = 6,
/obj/item/weapon/combat_knife/harvester = 12,
),
@@ -306,7 +314,6 @@
/obj/item/ammo_magazine/pistol/standard_heavypistol = -1,
/obj/item/weapon/gun/revolver/standard_revolver = -1,
/obj/item/ammo_magazine/revolver/standard_revolver = -1,
- /obj/item/weapon/gun/revolver/standard_magnum = -1,
/obj/item/ammo_magazine/revolver/standard_magnum = -1,
/obj/item/weapon/gun/pistol/standard_pocketpistol = -1,
/obj/item/ammo_magazine/pistol/standard_pocketpistol = -1,
@@ -325,8 +332,9 @@
/obj/item/explosive/grenade/sticky = 125,
/obj/item/explosive/grenade/incendiary = 50,
/obj/item/explosive/grenade/smokebomb/cloak = 25,
- /obj/item/explosive/grenade/smokebomb/drain = 10,
+ /obj/item/explosive/grenade/smokebomb/antigas = 20,
/obj/item/explosive/grenade/mirage = 100,
+ /obj/item/explosive/grenade/bullet/laser = 30,
/obj/item/storage/box/m94 = 200,
/obj/item/storage/box/m94/cas = 50,
),
@@ -367,8 +375,6 @@
/obj/item/ammo_magazine/rifle/pepperball/pepperball_mini = -1,
/obj/item/attachable/stock/t76 = -1,
/obj/item/attachable/flamer_nozzle = -1,
- /obj/item/attachable/flamer_nozzle/wide = -1,
- /obj/item/attachable/flamer_nozzle/long = -1,
),
"Boxes" = list(
/obj/item/ammo_magazine/packet/p9mm = -1,
@@ -437,18 +443,25 @@
),
"Energy Weapons" = list(
/obj/item/cell/lasgun/lasrifle = -1,
+ /obj/item/cell/lasgun/volkite/powerpack/marine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_rifle = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_sniper = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_mlaser = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_pistol = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/tesla = -1,
+ /obj/item/cell/lasgun/plasma = -1,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle = -1,
+ /obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/cannon = -1,
),
"SMGs" = list(
/obj/item/weapon/gun/smg/standard_smg = -1,
/obj/item/ammo_magazine/smg/standard_smg = -1,
/obj/item/weapon/gun/smg/standard_machinepistol = -1,
/obj/item/ammo_magazine/smg/standard_machinepistol = -1,
+ /obj/item/weapon/gun/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg = -1,
+ /obj/item/ammo_magazine/smg/standard_heavysmg/squashhead = -1,
),
"Marksman" = list(
/obj/item/weapon/gun/rifle/standard_dmr = -1,
@@ -457,6 +470,7 @@
/obj/item/ammo_magazine/rifle/standard_br = -1,
/obj/item/weapon/gun/rifle/chambered = -1,
/obj/item/ammo_magazine/rifle/chamberedrifle = -1,
+ /obj/item/ammo_magazine/rifle/chamberedrifle/flak = -1,
/obj/item/weapon/gun/shotgun/pump/bolt = -1,
/obj/item/ammo_magazine/rifle/bolt = -1,
/obj/item/weapon/gun/shotgun/double/martini = -1,
@@ -525,14 +539,18 @@
/obj/item/ammo_magazine/rifle/tx54/smoke = -1,
/obj/item/ammo_magazine/rifle/tx54/smoke/dense = -1,
/obj/item/ammo_magazine/rifle/tx54/smoke/tangle = -1,
+ /obj/item/ammo_magazine/rifle/tx54/smoke/acid = -1,
+ /obj/item/ammo_magazine/rifle/tx54/razor = -1,
/obj/item/explosive/grenade = -1,
/obj/item/explosive/grenade/m15 = -1,
/obj/item/explosive/grenade/sticky = -1,
/obj/item/explosive/grenade/sticky/trailblazer = -1,
/obj/item/explosive/grenade/incendiary = -1,
/obj/item/explosive/grenade/smokebomb/cloak = -1,
- /obj/item/explosive/grenade/smokebomb/drain = -1,
+ /obj/item/explosive/grenade/smokebomb/antigas = -1,
/obj/item/explosive/grenade/mirage = -1,
+ /obj/item/explosive/grenade/bullet/laser = -1,
+ /obj/item/explosive/grenade/bullet/hefa = -1,
/obj/item/storage/box/m94 = -1,
/obj/item/storage/box/m94/cas = -1,
),
@@ -547,23 +565,11 @@
"Heavy Weapons" = list(
/obj/structure/closet/crate/mortar_ammo/mortar_kit = -1,
/obj/structure/closet/crate/mortar_ammo/howitzer_kit = -1,
- /obj/structure/largecrate/supply/weapons/standard_atgun = -1,
- /obj/item/ammo_magazine/standard_atgun = -1,
- /obj/item/ammo_magazine/standard_atgun/apcr = -1,
- /obj/item/ammo_magazine/standard_atgun/he = -1,
- /obj/item/ammo_magazine/standard_atgun/beehive = -1,
- /obj/item/ammo_magazine/standard_atgun/incend = -1,
/obj/item/storage/box/crate/sentry = -1,
- /obj/item/storage/box/tl102 = -1,
+ /obj/item/storage/box/hsg_102 = -1,
/obj/item/weapon/gun/heavymachinegun = -1,
/obj/item/ammo_magazine/heavymachinegun = -1,
- /obj/item/storage/holster/backholster/rpg/full = -1,
- /obj/item/ammo_magazine/rocket/recoilless = -1,
- /obj/item/ammo_magazine/rocket/recoilless/light = -1,
- /obj/item/ammo_magazine/rocket/recoilless/heat = -1,
- /obj/item/ammo_magazine/rocket/recoilless/cloak = -1,
- /obj/item/ammo_magazine/rocket/recoilless/smoke = -1,
- /obj/item/ammo_magazine/rocket/recoilless/plasmaloss = -1,
+ /obj/item/ammo_magazine/heavymachinegun/small = -1,
),
"Attachments" = list(
/obj/item/attachable/bayonet = -1,
@@ -712,7 +718,7 @@
products = list(
"Surplus Special Equipment" = list(
/obj/item/pinpointer = 1,
- /obj/item/beacon/supply_beacon = 1,
+ /obj/item/supply_beacon = 1,
/obj/item/ammo_magazine/rifle/autosniper = 3,
/obj/item/ammo_magazine/rifle/tx8 = 3,
/obj/item/ammo_magazine/rocket/sadar = 3,
@@ -747,6 +753,7 @@
/obj/item/storage/box/visual/grenade/incendiary = 2,
/obj/item/storage/box/visual/grenade/M15 = 2,
/obj/item/storage/box/visual/grenade/cloak = 1,
+ /obj/item/storage/box/visual/grenade/lasburster = 1,
),
"Ammo Boxes" = list(
/obj/item/big_ammo_box = -1,
@@ -821,7 +828,8 @@
. = ..()
update_icon()
-/obj/machinery/vending/lasgun/update_icon()
+/obj/machinery/vending/lasgun/update_icon_state()
+ . = ..()
if(machine_max_charge)
switch(machine_current_charge / max(1,machine_max_charge))
if(0.7 to 1)
@@ -915,7 +923,6 @@
/obj/item/reagent_containers/hypospray/autoinjector/imidazoline = 20,
/obj/item/reagent_containers/hypospray/autoinjector/quickclot = 10,
/obj/item/reagent_containers/hypospray/autoinjector/medicalnanites = 20,
- /obj/item/reagent_containers/hypospray/autoinjector/russian_red = 10,
),
"Heal Pack" = list(
/obj/item/stack/medical/heal_pack/gauze = -1,
@@ -1069,7 +1076,7 @@
"General" = list(
/obj/item/clothing/suit/modular = -1,
/obj/item/clothing/suit/modular/rownin = -1,
- /obj/item/clothing/suit/modular/xenonauten/pilot = -1,
+ /obj/item/clothing/suit/storage/marine/ballistic = -1,
/obj/item/facepaint/green = -1,
),
"Armor modules" = list(
@@ -1097,19 +1104,6 @@
/obj/item/armor_module/module/style/light_armor = -1,
/obj/item/armor_module/module/style/medium_armor = -1,
/obj/item/armor_module/module/style/heavy_armor = -1,
- /obj/item/clothing/head/modular/marine/kabuto = -1,
- /obj/item/armor_module/armor/chest/marine/kabuto = -1,
- /obj/item/armor_module/armor/legs/marine/kabuto = -1,
- /obj/item/armor_module/armor/arms/marine/kabuto = -1,
- /obj/item/clothing/head/modular/marine/hotaru = -1,
- /obj/item/clothing/suit/modular/jaeger/hotaru = -1,
- /obj/item/armor_module/armor/chest/marine/hotaru = -1,
- /obj/item/armor_module/armor/legs/marine/hotaru = -1,
- /obj/item/armor_module/armor/arms/marine/hotaru = -1,
- /obj/item/clothing/head/modular/marine/dashe = -1,
- /obj/item/armor_module/armor/chest/marine/dashe = -1,
- /obj/item/armor_module/armor/arms/marine/dashe = -1,
- /obj/item/armor_module/armor/legs/marine/dashe = -1,
),
"Jaeger Mk.I chestpieces" = list(
/obj/item/armor_module/armor/chest/marine/skirmisher = -1,
@@ -1417,12 +1411,15 @@
/obj/item/ammo_magazine/railgun = -1,
/obj/item/ammo_magazine/railgun/smart = -1,
/obj/item/ammo_magazine/railgun/hvap = -1,
- /obj/item/weapon/gun/rifle/tx8 = -1,
- /obj/item/ammo_magazine/rifle/tx8 = -1,
- /obj/item/ammo_magazine/rifle/tx8/impact = -1,
- /obj/item/ammo_magazine/rifle/tx8/incendiary = -1,
/obj/item/ammo_magazine/packet/scout_rifle = -1,
/obj/item/weapon/gun/energy/lasgun/lasrifle/xray = -1,
+ /obj/item/weapon/gun/launcher/rocket/recoillessrifle = -1,
+ /obj/item/ammo_magazine/rocket/recoilless = -1,
+ /obj/item/ammo_magazine/rocket/recoilless/light = -1,
+ /obj/item/ammo_magazine/rocket/recoilless/heat = -1,
+ /obj/item/ammo_magazine/rocket/recoilless/cloak = -1,
+ /obj/item/ammo_magazine/rocket/recoilless/smoke = -1,
+ /obj/item/ammo_magazine/rocket/recoilless/plasmaloss = -1,
/obj/item/weapon/gun/launcher/rocket/m57a4/t57 = -1,
/obj/item/ammo_magazine/rocket/m57a4 = -1,
/obj/item/weapon/gun/launcher/rocket/sadar/valhalla = -1,
@@ -1433,18 +1430,8 @@
/obj/item/ammo_magazine/rocket/sadar/wp/unguided = -1,
/obj/item/weapon/gun/shotgun/zx76 = -1,
/obj/item/ammo_magazine/shotgun/incendiary = -1,
- /obj/item/weapon/gun/rifle/standard_autosniper = -1,
- /obj/item/ammo_magazine/rifle/autosniper = -1,
- /obj/item/weapon/gun/rifle/sniper/antimaterial = -1,
- /obj/item/ammo_magazine/sniper = -1,
- /obj/item/ammo_magazine/rifle/autosniper = -1,
/obj/item/weapon/gun/minigun/valhalla = -1,
/obj/item/ammo_magazine/minigun_powerpack = -1,
- /obj/item/weapon/gun/rifle/standard_smartmachinegun = -1,
- /obj/item/ammo_magazine/standard_smartmachinegun = -1,
- /obj/item/weapon/gun/minigun/smart_minigun = -1,
- /obj/item/ammo_magazine/minigun_powerpack/smartgun = -1,
- /obj/item/ammo_magazine/packet/smart_minigun = -1,
/obj/item/weapon/gun/launcher/rocket/oneuse = -1,
/obj/item/storage/holster/belt/mateba/full = -1,
/obj/item/ammo_magazine/revolver/mateba = -1,
@@ -1459,13 +1446,50 @@
/obj/item/explosive/grenade/smokebomb/neuro = -1,
/obj/item/explosive/grenade/smokebomb/acid = -1,
/obj/item/explosive/grenade/smokebomb/satrapine = -1,
+ /obj/item/explosive/grenade/smokebomb/drain = -1,
+ /obj/item/explosive/grenade/chem_grenade/cleaner = -1,
/obj/item/weapon/gun/rifle/m412l1_hpr = -1,
/obj/item/ammo_magazine/m412l1_hpr = -1,
/obj/item/weapon/gun/rifle/famas = -1,
/obj/item/ammo_magazine/rifle/famas = -1,
),
+ "Smartguns/IFF" = list(
+ /obj/item/weapon/gun/rifle/standard_smartmachinegun = -1,
+ /obj/item/ammo_magazine/standard_smartmachinegun = -1,
+ /obj/item/weapon/gun/minigun/smart_minigun = -1,
+ /obj/item/ammo_magazine/minigun_powerpack/smartgun = -1,
+ /obj/item/ammo_magazine/packet/smart_minigun = -1,
+ /obj/item/weapon/gun/rifle/standard_smarttargetrifle = -1,
+ /obj/item/ammo_magazine/rifle/standard_smarttargetrifle = -1,
+ /obj/item/ammo_magazine/packet/smart_targetrifle = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/highimpact = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/heavyrubber = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/tungsten = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/flak = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/plasmaloss = -1,
+ /obj/item/ammo_magazine/rifle/standard_spottingrifle/incendiary = -1,
+ /obj/item/weapon/gun/pistol/smart_pistol = -1,
+ /obj/item/ammo_magazine/pistol/standard_pistol/smart_pistol = -1,
+ /obj/item/weapon/gun/rifle/tx8 = -1,
+ /obj/item/ammo_magazine/rifle/tx8 = -1,
+ /obj/item/ammo_magazine/rifle/tx8/impact = -1,
+ /obj/item/ammo_magazine/rifle/tx8/incendiary = -1,
+ /obj/item/weapon/gun/rifle/standard_autosniper = -1,
+ /obj/item/ammo_magazine/rifle/autosniper = -1,
+ /obj/item/weapon/gun/rifle/sniper/antimaterial = -1,
+ /obj/item/ammo_magazine/sniper = -1,
+ /obj/item/ammo_magazine/sniper/incendiary = -1,
+ /obj/item/ammo_magazine/sniper/flak = -1,
+ ),
"Mounted" = list(
- /obj/item/weapon/gun/standard_auto_cannon = -1,
+ /obj/item/weapon/gun/standard_atgun = -1,
+ /obj/item/ammo_magazine/standard_atgun = -1,
+ /obj/item/ammo_magazine/standard_atgun/apcr = -1,
+ /obj/item/ammo_magazine/standard_atgun/he = -1,
+ /obj/item/ammo_magazine/standard_atgun/beehive = -1,
+ /obj/item/ammo_magazine/standard_atgun/incend = -1,
+ /obj/structure/largecrate/supply/weapons/standard_flakgun = -1,
/obj/item/ammo_magazine/auto_cannon = -1,
/obj/item/ammo_magazine/auto_cannon/flak = -1,
/obj/item/weapon/gun/standard_minigun = -1,
@@ -1477,7 +1501,7 @@
/obj/item/ammo_magazine/standard_agls/flare = -1,
/obj/item/ammo_magazine/standard_agls/cloak = -1,
/obj/item/ammo_magazine/standard_agls/tanglefoot = -1,
- /obj/item/weapon/gun/heavy_isg = -1,
+ /obj/structure/largecrate/supply/weapons/heavy_flakgun = -1,
/obj/item/ammo_magazine/heavy_isg/he = -1,
/obj/item/ammo_magazine/heavy_isg/sabot = -1,
),
@@ -1490,15 +1514,15 @@
/obj/item/clothing/gloves/marine/specialist = -1,
/obj/item/clothing/suit/storage/marine/B17/valhalla = -1,
/obj/item/clothing/head/helmet/marine/grenadier = -1,
- /obj/item/storage/backpack/marine/satchel/scout_cloak/scout = -1,
+ /obj/item/storage/backpack/marine/satchel/scout_cloak = -1,
/obj/item/storage/backpack/marine/satchel/scout_cloak/sniper = -1,
/obj/item/storage/belt/grenade/b17 = -1,
+ /obj/item/storage/holster/m25 = -1,
/obj/item/armor_module/module/valkyrie_autodoc = -1,
/obj/item/armor_module/module/fire_proof = -1,
/obj/item/armor_module/module/fire_proof_helmet = -1,
/obj/item/armor_module/module/tyr_extra_armor = -1,
/obj/item/armor_module/module/tyr_head = -1,
- /obj/item/attachable/shoulder_mount = -1,
/* RU TGMC EDIT
/obj/item/armor_module/module/mimir_environment_protection = -1,
/obj/item/armor_module/module/mimir_environment_protection/mimir_helmet = -1,
@@ -1601,6 +1625,12 @@ RU TGMC EDIT*/
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/culverin = -1,
/obj/item/cell/lasgun/volkite = -1,
/obj/item/cell/lasgun/volkite/powerpack = -1,
+ /obj/item/weapon/gun/launcher/rocket/som = -1,
+ /obj/item/ammo_magazine/rocket/som = -1,
+ /obj/item/ammo_magazine/rocket/som/incendiary = -1,
+ /obj/item/ammo_magazine/rocket/som/heat = -1,
+ /obj/item/weapon/gun/flamer/som = -1,
+ /obj/item/ammo_magazine/flamer_tank/large/som = -1,
),
"ICC" = list(
/obj/item/weapon/gun/rifle/icc_battlecarbine = -1,
@@ -1630,6 +1660,15 @@ RU TGMC EDIT*/
/obj/item/ammo_magazine/rifle/dpm = -1,
/obj/item/weapon/gun/clf_heavyrifle = -1,
/obj/item/shotgunbox/clf_heavyrifle = -1,
+ /obj/item/weapon/gun/launcher/rocket/icc = -1,
+ /obj/item/ammo_magazine/rocket/icc = -1,
+ /obj/item/ammo_magazine/rocket/icc/heat = -1,
+ /obj/item/ammo_magazine/rocket/icc/thermobaric = -1,
+ /obj/item/weapon/gun/rifle/icc_mg = -1,
+ /obj/item/ammo_magazine/icc_mg = -1,
+ /obj/item/ammo_magazine/icc_mg/belt = -1,
+ /obj/item/weapon/gun/icc_hmg = -1,
+ /obj/item/ammo_magazine/icc_hmg = -1,
),
"PMC" = list(
/obj/item/weapon/gun/rifle/sniper/elite = -1,
diff --git a/code/game/objects/machinery/vending/new_marine_vendors.dm b/code/game/objects/machinery/vending/new_marine_vendors.dm
index ad6063b329bff..973f64ae6bae3 100644
--- a/code/game/objects/machinery/vending/new_marine_vendors.dm
+++ b/code/game/objects/machinery/vending/new_marine_vendors.dm
@@ -41,6 +41,7 @@
set_light(0)
/obj/machinery/marine_selector/update_icon_state()
+ . = ..()
if(is_operational())
icon_state = initial(icon_state)
else
@@ -63,11 +64,11 @@
to_chat(user, span_warning("Access denied. Your assigned role doesn't have access to this machinery."))
return FALSE
- var/obj/item/card/id/I = H.get_idcard()
- if(!istype(I)) //not wearing an ID
+ var/obj/item/card/id/user_id = H.get_idcard()
+ if(!istype(user_id)) //not wearing an ID
return FALSE
- if(I.registered_name != H.real_name)
+ if(user_id.registered_name != H.real_name)
return FALSE
if(lock_flags & JOB_LOCK && vendor_role && !istype(H.job, vendor_role))
@@ -144,13 +145,16 @@
return
var/idx = text2path(params["vend"])
- var/obj/item/card/id/I = usr.get_idcard()
+ var/obj/item/card/id/user_id = usr.get_idcard()
var/list/L = listed_products[idx]
var/item_category = L[1]
var/cost = L[3]
- if(use_points && (item_category in I.marine_points) && I.marine_points[item_category] < cost)
+ if(!(user_id.id_flags & CAN_BUY_LOADOUT)) //If you use the quick-e-quip, you cannot also use the GHMMEs
+ to_chat(usr, span_warning("Access denied. You have already vended a loadout."))
+ return FALSE
+ if(use_points && (item_category in user_id.marine_points) && user_id.marine_points[item_category] < cost)
to_chat(usr, span_warning("Not enough points."))
if(icon_deny)
flick(icon_deny, src)
@@ -163,9 +167,9 @@
flick(icon_deny, src)
return
- if(item_category in I.marine_buy_choices)
- if(I.marine_buy_choices[item_category] && GLOB.marine_selector_cats[item_category])
- I.marine_buy_choices[item_category] -= 1
+ if(item_category in user_id.marine_buy_choices)
+ if(user_id.marine_buy_choices[item_category] && GLOB.marine_selector_cats[item_category])
+ user_id.marine_buy_choices[item_category] -= 1
else
if(cost == 0)
to_chat(usr, span_warning("You can't buy things from this category anymore."))
@@ -198,9 +202,10 @@
for (var/obj/item/vended_item in vended_items)
vended_item.on_vend(usr, faction, auto_equip = TRUE)
- if(use_points && (item_category in I.marine_points))
- I.marine_points[item_category] -= cost
+ if(use_points && (item_category in user_id.marine_points))
+ user_id.marine_points[item_category] -= cost
. = TRUE
+ user_id.id_flags |= USED_GHMME
/obj/machinery/marine_selector/clothes
name = "GHMME Automated Closet"
@@ -382,6 +387,11 @@
lock_flags = JOB_LOCK
gives_webbing = FALSE
+/obj/machinery/marine_selector/clothes/commander/valhalla
+ vendor_role = /datum/job/fallen/marine/fieldcommander
+ resistance_flags = INDESTRUCTIBLE
+ lock_flags = JOB_LOCK
+
/* RUTGMC DELETION
/obj/machinery/marine_selector/clothes/commander/Initialize(mapload)
. = ..()
@@ -701,6 +711,7 @@
)
/obj/effect/vendor_bundle/stretcher
+ desc = "A standard-issue TerraGov Marine Corps corpsman medivac stretcher. Comes with an extra beacon, but multiple beds can be linked to one beacon."
gear_to_spawn = list(
/obj/item/roller/medevac,
/obj/item/medevac_beacon,
@@ -709,7 +720,7 @@
/obj/effect/vendor_bundle/engi
gear_to_spawn = list(
/obj/item/explosive/plastique,
- /obj/item/explosive/grenade/chem_grenade/razorburn_smol,
+ /obj/item/explosive/grenade/chem_grenade/razorburn_small,
/obj/item/clothing/gloves/marine/insulated,
/obj/item/cell/high,
/obj/item/lightreplacer,
@@ -728,8 +739,8 @@
/obj/effect/vendor_bundle/leader
gear_to_spawn = list(
/obj/item/explosive/plastique,
- /obj/item/beacon/supply_beacon,
- /obj/item/beacon/supply_beacon,
+ /obj/item/supply_beacon,
+ /obj/item/supply_beacon,
//RUTGMC EDIT ADDITION BEGIN - ORBITAL_BEACON
/obj/item/beacon/orbital_bombardment_beacon,
//RUTGMC EDIT ADDITION END
@@ -743,7 +754,7 @@
/obj/effect/vendor_bundle/commander
gear_to_spawn = list(
/obj/item/explosive/plastique,
- /obj/item/beacon/supply_beacon,
+ /obj/item/supply_beacon,
//RUTGMC EDIT ADDITION BEGIN - ORBITAL_BEACON
/obj/item/beacon/orbital_bombardment_beacon,
//RUTGMC EDIT ADDITION END
diff --git a/code/game/objects/machinery/vending/quick_vendor.dm b/code/game/objects/machinery/vending/quick_vendor.dm
index db2e6553aaa73..2a68fe84ceb67 100644
--- a/code/game/objects/machinery/vending/quick_vendor.dm
+++ b/code/game/objects/machinery/vending/quick_vendor.dm
@@ -81,10 +81,10 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
for(var/X in loadout_list)
.[X] = new X
-
/obj/machinery/quick_vendor
name = "Kwik-E-Quip vendor"
- desc = "An advanced vendor to instantly arm soldiers with specific sets of equipment, allowing for immediate combat deployment."
+ desc = "An advanced vendor to instantly arm soldiers with specific sets of equipment, allowing for immediate combat deployment. \
+ Mutually exclusive with the GHMME."
icon = 'icons/obj/machines/vending.dmi'
icon_state = "specialist"
density = TRUE
@@ -106,6 +106,18 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
"Squad Smartgunner",
"Squad Leader",
)
+ ///Whichever global loadout is used to build the vendor stock
+ var/list/global_list_to_use
+ ///If the vendor drops your items, or deletes them when you vend a loadout
+ var/drop_worn_items = FALSE
+
+/obj/machinery/quick_vendor/Initialize(mapload)
+ . = ..()
+ set_stock_list()
+
+///Chooses which global list the vendor will build stock from, gets run on Initialize()
+/obj/machinery/quick_vendor/proc/set_stock_list()
+ global_list_to_use = GLOB.quick_loadouts
/obj/machinery/quick_vendor/Initialize(mapload)
. = ..()
@@ -119,6 +131,7 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
set_light(0)
/obj/machinery/quick_vendor/update_icon_state()
+ . = ..()
if(is_operational())
icon_state = initial(icon_state)
else
@@ -148,6 +161,7 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
var/obj/item/card/id/user_id = human_user.get_idcard()
if(user_id.registered_name != human_user.real_name)
return FALSE
+
return TRUE
/obj/machinery/quick_vendor/ui_interact(mob/living/user, datum/tgui/ui)
@@ -164,9 +178,9 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
. = ..()
var/list/data = list()
var/list/loadouts_data_tgui = list()
- for(var/loadout_data in GLOB.quick_loadouts)
+ for(var/loadout_data in global_list_to_use)
var/list/next_loadout_data = list() //makes a list item with the below lines, for each loadout entry in the list
- var/datum/outfit/quick/current_loadout = GLOB.quick_loadouts[loadout_data]
+ var/datum/outfit/quick/current_loadout = global_list_to_use[loadout_data]
next_loadout_data["job"] = current_loadout.jobtype
next_loadout_data["name"] = current_loadout.name
next_loadout_data["desc"] = current_loadout.desc
@@ -191,7 +205,7 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
return
switch(action)
if("selectLoadout")
- var/datum/outfit/quick/selected_loadout = GLOB.quick_loadouts[text2path(params["loadout_outfit"])]
+ var/datum/outfit/quick/selected_loadout = global_list_to_use[text2path(params["loadout_outfit"])]
if(!selected_loadout)
to_chat(ui.user, span_warning("Error when loading this loadout"))
CRASH("Fail to load loadouts")
@@ -199,13 +213,28 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts())
to_chat(usr, span_warning("This loadout has been depleted, you'll need to pick another."))
return
var/obj/item/card/id/user_id = usr.get_idcard() //ui.user better?
- if(selected_loadout.jobtype != user_id.rank)
+ var/user_job = user_id.rank
+ user_job = replacetext(user_job, "Fallen ", "") //So that jobs in valhalla can vend a loadout too
+ if(selected_loadout.jobtype != user_job)
to_chat(usr, span_warning("You are not in the right job for this loadout!"))
return
- if(user_id.can_buy_loadout)
- user_id.can_buy_loadout = FALSE
+ if(user_id.id_flags & USED_GHMME) //Same check here, in case they opened the UI before vending a loadout somehow
+ to_chat(ui.user, span_warning("Access denied, continue using the GHHME."))
+ return FALSE
+ if(user_id.id_flags & CAN_BUY_LOADOUT)
+ user_id.id_flags &= ~CAN_BUY_LOADOUT
selected_loadout.quantity --
+ if(drop_worn_items)
+ for(var/obj/item/inventory_items in ui.user)
+ if(inventory_items.equip_slot_flags == ITEM_SLOT_ID)
+ continue
+ ui.user.dropItemToGround(inventory_items)
selected_loadout.equip(ui.user) //actually equips the loadout
+ //After vending a quick loadout, remove points and GHMME options so that you can't vend them via loadout vendor
+ for(var/points in user_id.marine_points)
+ user_id.marine_points[points] = 0
+ for(var/option in user_id.marine_buy_choices)
+ user_id.marine_buy_choices[option] = 0
else
to_chat(usr, span_warning("You can't buy things from this category anymore."))
diff --git a/code/game/objects/machinery/vending/vending.dm b/code/game/objects/machinery/vending/vending.dm
index 74acae91a45a5..77e7981cb0f13 100644
--- a/code/game/objects/machinery/vending/vending.dm
+++ b/code/game/objects/machinery/vending/vending.dm
@@ -279,38 +279,38 @@
for(var/season in seasonal_items)
products[seasonal_items[season]] += SSpersistence.season_items[season]
-/obj/machinery/vending/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/vending/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- if(X.a_intent == INTENT_HARM)
- X.do_attack_animation(src, ATTACK_EFFECT_SMASH)
- if(prob(X.xeno_caste.melee_damage))
+ if(xeno_attacker.a_intent == INTENT_HARM)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ if(prob(damage_amount))
playsound(loc, 'sound/effects/metalhit.ogg', 25, 1)
- X.visible_message(span_danger("\The [X] smashes \the [src] beyond recognition!"), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] smashes \the [src] beyond recognition!"), \
span_danger("We enter a frenzy and smash \the [src] apart!"), null, 5)
malfunction()
return TRUE
else
- X.visible_message(span_danger("[X] slashes \the [src]!"), \
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] slashes \the [src]!"), \
span_danger("We slash \the [src]!"), null, 5)
playsound(loc, 'sound/effects/metalhit.ogg', 25, 1)
return TRUE
if(tipped_level)
- to_chat(X, span_warning("There's no reason to bother with that old piece of trash."))
+ to_chat(xeno_attacker, span_warning("There's no reason to bother with that old piece of trash."))
return FALSE
- X.visible_message(span_warning("\The [X] begins to lean against \the [src]."), \
+ xeno_attacker.visible_message(span_warning("\The [xeno_attacker] begins to lean against \the [src]."), \
span_warning("You begin to lean against \the [src]."), null, 5)
tipped_level = 1
var/shove_time = 1 SECONDS
- if(X.mob_size == MOB_SIZE_BIG)
+ if(xeno_attacker.mob_size == MOB_SIZE_BIG)
shove_time = 5 SECONDS
- if(istype(X,/mob/living/carbon/xenomorph/crusher))
+ if(istype(xeno_attacker,/mob/living/carbon/xenomorph/crusher))
shove_time = 1.5 SECONDS
- if(do_after(X, shove_time, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
- X.visible_message(span_danger("\The [X] knocks \the [src] down!"), \
+ if(do_after(xeno_attacker, shove_time, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] knocks \the [src] down!"), \
span_danger("You knock \the [src] down!"), null, 5)
tip_over()
else
@@ -337,6 +337,8 @@
/obj/machinery/vending/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(tipped_level)
to_chat(user, "Tip it back upright first!")
@@ -378,12 +380,12 @@
user.visible_message("[user] tightens the bolts securing \the [src] to the floor.", "You tighten the bolts securing \the [src] to the floor.")
var/turf/current_turf = get_turf(src)
if(current_turf && density)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
else
user.visible_message("[user] unfastens the bolts securing \the [src] to the floor.", "You unfasten the bolts securing \the [src] to the floor.")
var/turf/current_turf = get_turf(src)
if(current_turf && density)
- current_turf.flags_atom &= ~AI_BLOCKED
+ current_turf.atom_flags &= ~AI_BLOCKED
else if(isitem(I))
var/obj/item/to_stock = I
stock(to_stock, user)
@@ -658,6 +660,34 @@
return do_stock(item_to_stock, user, show_feedback, record)
+/obj/machinery/vending/lasgun/do_stock(obj/item/item_to_stock, mob/user, show_feedback = TRUE, datum/vending_product/record)
+ //Special snowflake handling of cells
+ if(!iscell(item_to_stock))
+ return ..()
+
+ var/recharge_amount = 0 //the amount of charge required to fully charge our cell
+ var/obj/item/cell/cell = item_to_stock
+ if(cell.charge < cell.maxcharge)
+ // Item is not full. Time to try to recharge
+ recharge_amount = cell.maxcharge - cell.charge
+ if(machine_current_charge == 0)
+ display_message_and_visuals(user, show_feedback, "No power!", VENDING_RESTOCK_DENY)
+ return FALSE
+ else if(machine_current_charge < recharge_amount) // Not enough but some charge remaining so partially recharge cell and move on
+ cell.give(machine_current_charge)
+ machine_current_charge = 0
+ cell.update_icon()
+ display_message_and_visuals(user, show_feedback, "Cell charged partially! [round(cell.percent())]%.", VENDING_RESTOCK_RECHARGE)
+ playsound(loc, 'sound/machines/hydraulics_1.ogg', 25, 0, 1)
+ return FALSE
+ else
+ machine_current_charge -= recharge_amount
+ cell.give(recharge_amount)
+ if(!record.attempt_restock(item_to_stock, user, show_feedback))
+ return FALSE
+ display_message_and_visuals(user, show_feedback, "Restocked and recharged", VENDING_RESTOCK_ACCEPT_RECHARGE)
+ return TRUE
+
///Actually does the restock. Overridden by lasgun vendor for snowflake behaviour
/obj/machinery/vending/proc/do_stock(obj/item/item_to_stock, mob/user, show_feedback = TRUE, datum/vending_product/record)
if(!record.attempt_restock(item_to_stock, user, show_feedback))
@@ -703,7 +733,7 @@
//More accurate comparison between absolute paths.
if(isstorage(item_to_stock)) //Nice try, specialists/engis
var/obj/item/storage/storage_to_stock = item_to_stock
- if(!(storage_to_stock.flags_storage & BYPASS_VENDOR_CHECK)) //If your storage has this flag, it can be restocked
+ if(!(storage_to_stock.storage_flags & BYPASS_VENDOR_CHECK)) //If your storage has this flag, it can be restocked
user?.balloon_alert(user, "Can't restock containers!")
return FALSE
@@ -742,7 +772,7 @@
//Actually restocks the item after our checks
if(user)
if(item_to_stock.loc == user) //Inside the mob's inventory
- if(item_to_stock.flags_item & WIELDED)
+ if(item_to_stock.item_flags & WIELDED)
item_to_stock.unwield(user)
user.temporarilyRemoveItemFromInventory(item_to_stock)
@@ -830,6 +860,7 @@
set_light(initial(light_range))
/obj/machinery/vending/update_icon_state()
+ . = ..()
if(machine_stat & BROKEN)
icon_state = "[initial(icon_state)]-broken"
else if(machine_stat & NOPOWER)
@@ -885,7 +916,7 @@
. = TRUE
-/obj/machinery/vending/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", effects = TRUE, attack_dir, armour_penetration = 0)
+/obj/machinery/vending/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
if(density && damage_amount >= knockdown_threshold)
tip_over()
return ..()
diff --git a/code/game/objects/machinery/vending/vending_types.dm b/code/game/objects/machinery/vending/vending_types.dm
index 373d0cb011c67..1c3197b03efc5 100644
--- a/code/game/objects/machinery/vending/vending_types.dm
+++ b/code/game/objects/machinery/vending/vending_types.dm
@@ -112,11 +112,15 @@
/obj/item/reagent_containers/food/snacks/enrg_bar = -1,
/obj/item/reagent_containers/food/snacks/wrapped/booniebars = -1,
/obj/item/reagent_containers/food/snacks/wrapped/chunk = -1,
- /obj/item/reagent_containers/food/snacks/wrapped/barcardine = -1,
+ /obj/item/reagent_containers/food/snacks/wrapped/barcaridine = -1,
/obj/item/reagent_containers/food/snacks/lollipop = -1,
/obj/item/reagent_containers/food/snacks/wrapped/berrybar = -1,
)
+/obj/machinery/vending/snack/alamo
+ product_slogans = "" //silent for no spam
+ wrenchable = FALSE
+
/obj/machinery/vending/cola
name = "Souto Softdrinks"
desc = "A softdrink vendor provided by Souto Soda Company, Havana."
@@ -137,19 +141,9 @@
/obj/item/reagent_containers/food/drinks/cans/cola = -1,
)
- prices = list(
- /obj/item/reagent_containers/food/drinks/cans/souto = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/diet = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/cherry = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/cherry/diet = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/lime = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/lime/diet = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/grape = 5,
- /obj/item/reagent_containers/food/drinks/cans/souto/grape/diet = 5,
- /obj/item/reagent_containers/food/drinks/cans/waterbottle = 2,
- /obj/item/reagent_containers/food/drinks/cans/cola = 10,
- )
- idle_power_usage = 200
+/obj/machinery/vending/cola/alamo
+ product_slogans = "" //silent for no spam
+ wrenchable = FALSE
/obj/machinery/vending/medical
name = "NanotrasenMed Plus"
@@ -216,7 +210,7 @@
/obj/item/storage/reagent_tank/bktt = 1,
),
"Misc" = list(
- /obj/item/tool/research/xeno_analyzer = -1,
+ /obj/item/tool/research/xeno_analyzer = 2,
/obj/item/tool/research/excavation_tool = -1,
/obj/item/storage/pouch/surgery = -1,
/obj/item/armor_module/storage/uniform/surgery_webbing = -1,
@@ -264,7 +258,6 @@
/obj/item/reagent_containers/glass/bottle/adminordrazine = -1,
/obj/item/reagent_containers/glass/bottle/lemoline = -1,
/obj/item/reagent_containers/glass/bottle/nanoblood = -1,
- /obj/item/reagent_containers/glass/bottle/doctor_delight = -1,
),
"Pill Bottle" = list(
/obj/item/storage/pill_bottle/bicaridine = -1,
@@ -321,6 +314,8 @@
/obj/item/reagent_containers/hypospray/autoinjector/virilyth = -1,
/obj/item/reagent_containers/hypospray/autoinjector/roulettium = -1,
/obj/item/reagent_containers/glass/bottle/toxin = -1,
+ /obj/item/reagent_containers/glass/bottle/doctor_delight = -1,
+ /obj/item/alien_embryo = -1,
),
)
@@ -380,6 +375,7 @@
/obj/machinery/vending/nanomed/tadpolemed
name = "Flight surgeon medical equipment dispenser"
desc = "Dedicated for the surgeon with wings, this humble box contains a lot for its size."
+ layer = ABOVE_OBJ_LAYER
products = list(
"Autoinjectors" = list(
/obj/item/reagent_containers/hypospray/autoinjector/sleeptoxin = 2,
@@ -534,7 +530,7 @@
/obj/item/tool/kitchen/utensil/fork = 6,
/obj/item/tool/kitchen/knife = 3,
/obj/item/reagent_containers/food/drinks/drinkingglass = 8,
- /obj/item/clothing/suit/chef/classic = 2,
+ /obj/item/clothing/suit/storage/chef/classic = 2,
/obj/item/tool/kitchen/utensil/spoon = 2,
/obj/item/tool/kitchen/utensil/knife = 2,
/obj/item/tool/kitchen/rollingpin = 2,
diff --git a/code/game/objects/machinery/washing_machine.dm b/code/game/objects/machinery/washing_machine.dm
index 30f1aa74230cf..0c69863af5b92 100644
--- a/code/game/objects/machinery/washing_machine.dm
+++ b/code/game/objects/machinery/washing_machine.dm
@@ -67,12 +67,15 @@
usr.loc = src.loc
-/obj/machinery/washing_machine/update_icon()
+/obj/machinery/washing_machine/update_icon_state()
+ . = ..()
icon_state = "wm_[state][panel]"
/obj/machinery/washing_machine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/toy/crayon) || istype(I, /obj/item/tool/stamp))
if(!(state in list(1, 3, 6)))
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 50c9357423a17..c43d9446cad18 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -1,15 +1,15 @@
-/obj/proc/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", effects = TRUE, attack_dir, armour_penetration = 0)
+/obj/proc/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
if(QDELETED(src))
CRASH("[src] taking damage after deletion")
if(!damage_amount)
return
if(effects)
- play_attack_sound(damage_amount, damage_type, damage_flag)
+ play_attack_sound(damage_amount, damage_type, armor_type)
if((resistance_flags & INDESTRUCTIBLE) || obj_integrity <= 0)
return
- if(damage_flag)
- damage_amount = round(modify_by_armor(damage_amount, damage_flag, armour_penetration), DAMAGE_PRECISION)
+ if(armor_type)
+ damage_amount = round(modify_by_armor(damage_amount, armor_type, armour_penetration, null, attack_dir), DAMAGE_PRECISION)
if(damage_amount < DAMAGE_PRECISION)
return
. = damage_amount
@@ -18,11 +18,11 @@
//BREAKING FIRST
if(integrity_failure && obj_integrity <= integrity_failure)
- obj_break(damage_flag)
+ obj_break(armor_type)
//DESTROYING SECOND
if(obj_integrity <= 0)
- obj_destruction(damage_amount, damage_type, damage_flag)
+ obj_destruction(damage_amount, damage_type, armor_type, blame_mob)
///Increase obj_integrity and record it to the repairer's stats
/obj/proc/repair_damage(repair_amount, mob/user)
@@ -67,6 +67,15 @@
take_damage(rand(5, 45), BRUTE, BOMB, 0)
*/
+/obj/lava_act()
+ if(resistance_flags & INDESTRUCTIBLE)
+ return FALSE
+ if(!take_damage(50, BURN, FIRE))
+ return FALSE
+ if(QDELETED(src))
+ return FALSE
+ fire_act()
+ return TRUE
/obj/hitby(atom/movable/AM, speed = 5)
. = ..()
@@ -92,13 +101,13 @@
return
playsound(loc, P.hitsound, 50, 1)
visible_message(span_warning("\the [src] is damaged by \the [P]!"), visible_message_flags = COMBAT_MESSAGE)
- take_damage(P.damage, P.ammo.damage_type, P.ammo.armor_type, 0, REVERSE_DIR(P.dir), P.ammo.penetration)
+ take_damage(P.damage, P.ammo.damage_type, P.ammo.armor_type, 0, REVERSE_DIR(P.dir), P.ammo.penetration, isliving(P.firer) ? P.firer : null)
-/obj/proc/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0) //used by attack_alien, attack_animal, and attack_slime
+/obj/proc/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = 0) //used by attack_alien, attack_animal, and attack_slime
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
user.changeNext_move(CLICK_CD_MELEE)
- return take_damage(damage_amount, damage_type, damage_flag, effects, get_dir(src, user), armor_penetration)
+ return take_damage(damage_amount, damage_type, armor_type, effects, get_dir(src, user), armor_penetration, user)
/obj/attack_animal(mob/living/simple_animal/M)
@@ -115,22 +124,22 @@
playsound(loc, 'sound/effects/meteorimpact.ogg', 100, 1)
-/obj/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
// SHOULD_CALL_PARENT(TRUE) // TODO: fix this
- if(X.status_flags & INCORPOREAL) //Ghosts can't attack machines
+ if(xeno_attacker.status_flags & INCORPOREAL) //Ghosts can't attack machines
return FALSE
- SEND_SIGNAL(X, COMSIG_XENOMORPH_ATTACK_OBJ, src)
- if(SEND_SIGNAL(src, COMSIG_OBJ_ATTACK_ALIEN, X) & COMPONENT_NO_ATTACK_ALIEN)
+ SEND_SIGNAL(xeno_attacker, COMSIG_XENOMORPH_ATTACK_OBJ, src)
+ if(SEND_SIGNAL(src, COMSIG_OBJ_ATTACK_ALIEN, xeno_attacker) & COMPONENT_NO_ATTACK_ALIEN)
return FALSE
if(!(resistance_flags & XENO_DAMAGEABLE))
- to_chat(X, span_warning("We stare at \the [src] cluelessly."))
+ to_chat(xeno_attacker, span_warning("We stare at \the [src] cluelessly."))
return FALSE
if(effects)
- X.visible_message(span_danger("[X] has slashed [src]!"),
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] has slashed [src]!"),
span_danger("We slash [src]!"))
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
playsound(loc, "alien_claw_metal", 25)
- attack_generic(X, damage_amount, damage_type, damage_flag, effects, armor_penetration)
+ attack_generic(xeno_attacker, damage_amount, damage_type, armor_type, effects, armor_penetration)
return TRUE
/obj/attack_larva(mob/living/carbon/xenomorph/larva/L)
@@ -151,7 +160,7 @@
///what happens when the obj's integrity reaches zero.
-/obj/proc/obj_destruction(damage_amount, damage_type, damage_flag)
+/obj/proc/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
SHOULD_CALL_PARENT(TRUE)
if(destroy_sound)
playsound(loc, destroy_sound, 35, 1)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 127984fb8dc93..aa96df4e841c5 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -13,30 +13,26 @@
/// %-reduction-based armor.
var/datum/armor/soft_armor
- /// Flat-damage-reduction-based armor.
+ ///Modifies the AP of incoming attacks
var/datum/armor/hard_armor
-
- var/obj_integrity //defaults to max_integrity
+ ///Object HP
+ var/obj_integrity
+ ///Max object HP
var/max_integrity = 500
- var/integrity_failure = 0 //0 if we have no special broken behavior
- var/reliability = 100 //Used by SOME devices to determine how reliable they are.
- var/crit_fail = 0
-
- ///throwforce needs to be at least 1 else it causes runtimes with shields
+ ///Integrety below this number causes special behavior
+ var/integrity_failure = 0
+ ///Base throw damage. Throwforce needs to be at least 1 else it causes runtimes with shields
var/throwforce = 1
-
+ ///Object behavior flags
var/obj_flags = NONE
- var/hit_sound //Sound this object makes when hit, overrides specific item hit sound.
- var/destroy_sound //Sound this object makes when destroyed.
-
- var/item_fire_stacks = 0 //How many fire stacks it applies
-
+ ///Sound when hit
+ var/hit_sound
+ ///Sound this object makes when destroyed
+ var/destroy_sound
+ ///ID access where all are required to access this object
var/list/req_access = null
+ ///ID access where any one is required to access this object
var/list/req_one_access = null
-
- ///Optimization for dynamic explosion block values, for things whose explosion block is dependent on certain conditions.
- var/real_explosion_block
-
///Odds of a projectile hitting the object, if the object is dense
var/coverage = 50
@@ -108,7 +104,7 @@
. = ..()
if(.)
return
- if((flags_atom & ON_BORDER) && !(get_dir(loc, target) & dir))
+ if((atom_flags & ON_BORDER) && !(get_dir(loc, target) & dir))
return TRUE
if((allow_pass_flags & PASS_DEFENSIVE_STRUCTURE) && (mover.pass_flags & PASS_DEFENSIVE_STRUCTURE))
return TRUE
@@ -124,7 +120,7 @@
return FALSE
if((allow_pass_flags & PASS_MOB))
return TRUE
- if((allow_pass_flags & PASS_WALKOVER) && SEND_SIGNAL(target, COMSIG_OBJ_TRY_ALLOW_THROUGH))
+ if((allow_pass_flags & PASS_WALKOVER) && SEND_SIGNAL(target, COMSIG_OBJ_TRY_ALLOW_THROUGH, mover))
return TRUE
///Handles extra checks for things trying to exit this objects turf
@@ -140,16 +136,16 @@
return TRUE
if((allow_pass_flags & PASS_GLASS) && (mover.pass_flags & PASS_GLASS))
return NONE
- if(!density || !(flags_atom & ON_BORDER) || !(direction & dir) || (mover.status_flags & INCORPOREAL))
+ if(!density || !(atom_flags & ON_BORDER) || !(direction & dir) || (mover.status_flags & INCORPOREAL))
return NONE
knownblockers += src
return COMPONENT_ATOM_BLOCK_EXIT
///Signal handler to check if you can move from one low object to another
-/obj/proc/can_climb_over(datum/source)
+/obj/proc/can_climb_over(datum/source, atom/mover)
SIGNAL_HANDLER
- if(!(flags_atom & ON_BORDER) && density)
+ if(!(atom_flags & ON_BORDER) && density)
return TRUE
/obj/proc/updateUsrDialog()
@@ -230,6 +226,62 @@
return TRUE
return ..()
+/obj/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_MASS_DEL_TYPE, "Delete all of type")
+ VV_DROPDOWN_OPTION(VV_HK_OSAY, "Object Say")
+
+/obj/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_OSAY])
+ if(check_rights(R_FUN, FALSE))
+ usr.client.object_say(src)
+
+ if(href_list[VV_HK_MASS_DEL_TYPE])
+ if(!check_rights(R_DEBUG|R_SERVER))
+ return
+ var/action_type = tgui_alert(usr, "Strict type ([type]) or type and all subtypes?",,list("Strict type","Type and subtypes","Cancel"))
+ if(action_type == "Cancel" || !action_type)
+ return
+
+ if(tgui_alert(usr, "Are you really sure you want to delete all objects of type [type]?",,list("Yes","No")) != "Yes")
+ return
+
+ if(tgui_alert(usr, "Second confirmation required. Delete?",,list("Yes","No")) != "Yes")
+ return
+
+ var/O_type = type
+ switch(action_type)
+ if("Strict type")
+ var/i = 0
+ for(var/obj/Obj in world)
+ if(Obj.type == O_type)
+ i++
+ qdel(Obj)
+ CHECK_TICK
+ if(!i)
+ to_chat(usr, "No objects of this type exist")
+ return
+ log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ")
+ message_admins(span_notice("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) "))
+ if("Type and subtypes")
+ var/i = 0
+ for(var/obj/Obj in world)
+ if(istype(Obj,O_type))
+ i++
+ qdel(Obj)
+ CHECK_TICK
+ if(!i)
+ to_chat(usr, "No objects of this type exist")
+ return
+ log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ")
+ message_admins(span_notice("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) "))
+
///Called to return an internally stored item, currently for the deployable element
/obj/proc/get_internal_item()
return
@@ -270,6 +322,9 @@
if(!do_after(user, (fumble_time ? fumble_time : repair_time) * (skill_required - user.skills.getRating(SKILL_ENGINEER)), NONE, src, BUSY_ICON_BUILD))
return TRUE
+ if(user.skills.getRating(SKILL_ENGINEER) > skill_required)
+ repair_amount *= (1+(0.1*(user.skills.getRating(SKILL_ENGINEER) - (skill_required + 1))))
+
repair_time *= welder.toolspeed
balloon_alert_to_viewers("starting repair...")
handle_weldingtool_overlay()
@@ -297,3 +352,27 @@
playsound(loc, 'sound/items/welder2.ogg', 25, TRUE)
handle_weldingtool_overlay(TRUE)
return TRUE
+
+/obj/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(isxeno(user))
+ return
+ if(user.a_intent != INTENT_HARM)
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(user.grab_state <= GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(prob(15))
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.drop_held_item()
+ step_towards(grabbed_mob, src)
+ var/damage = base_damage + (user.skills.getRating(SKILL_CQC) * CQC_SKILL_DAMAGE_MOD)
+ grabbed_mob.apply_damage(damage, BRUTE, "head", MELEE, is_sharp, updating_health = TRUE)
+ user.visible_message(span_danger("[user] slams [grabbed_mob]'s face against [src]!"),
+ span_danger("You slam [grabbed_mob]'s face against [src]!"))
+ log_combat(user, grabbed_mob, "slammed", "", "against \the [src]")
+ take_damage(damage, BRUTE, MELEE)
+ return TRUE
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 9026acd470003..2570caa2008e0 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -2,7 +2,7 @@
icon = 'icons/obj/structures/structures.dmi'
var/climbable = FALSE
var/climb_delay = 50
- var/flags_barrier = NONE
+ var/barrier_flags = NONE
var/broken = FALSE //similar to machinery's stat BROKEN
obj_flags = CAN_BE_HIT
anchored = TRUE
@@ -49,7 +49,7 @@
do_climb(usr)
-/obj/structure/specialclick(mob/living/carbon/user)
+/obj/structure/CtrlClick(mob/living/carbon/user)
. = ..()
INVOKE_ASYNC(src, PROC_REF(do_climb), user)
@@ -73,7 +73,7 @@
if(!user.Adjacent(src))
return
- if((flags_atom & ON_BORDER))
+ if((atom_flags & ON_BORDER))
if(user_turf != destination_turf && user_turf != get_step(destination_turf, dir))
to_chat(user, span_warning("You need to be up against [src] to leap over."))
return
@@ -88,7 +88,7 @@
var/obj/structure/structure = object
if(structure.allow_pass_flags & PASS_WALKOVER)
continue
- if(object.density && (!(object.flags_atom & ON_BORDER) || object.dir & get_dir(src,user)))
+ if(object.density && (!(object.atom_flags & ON_BORDER) || object.dir & get_dir(src,user)))
to_chat(user, span_warning("There's \a [object.name] in the way."))
return
@@ -97,7 +97,7 @@
var/obj/structure/structure = object
if(structure.allow_pass_flags & PASS_WALKOVER)
continue
- if(object.density && (object.flags_atom & ON_BORDER) && object.dir & get_dir(user, src))
+ if(object.density && (object.atom_flags & ON_BORDER) && object.dir & get_dir(user, src))
to_chat(user, span_warning("There's \a [object.name] in the way."))
return
@@ -108,7 +108,7 @@
if(user.do_actions || !can_climb(user))
return
- user.visible_message(span_warning("[user] starts [flags_atom & ON_BORDER ? "leaping over" : "climbing onto"] \the [src]!"))
+ user.visible_message(span_warning("[user] starts [atom_flags & ON_BORDER ? "leaping over" : "climbing onto"] \the [src]!"))
if(!do_after(user, climb_delay, IGNORE_HELD_ITEM, src, BUSY_ICON_GENERIC))
return
@@ -121,7 +121,7 @@
user.unbuckle_mob(m)
user.forceMove(destination_turf)
- user.visible_message(span_warning("[user] [flags_atom & ON_BORDER ? "leaps over" : "climbs onto"] \the [src]!"))
+ user.visible_message(span_warning("[user] [atom_flags & ON_BORDER ? "leaps over" : "climbs onto"] \the [src]!"))
/obj/structure/proc/structure_shaken()
diff --git a/code/game/objects/structures/barricade.dm b/code/game/objects/structures/barricade.dm
index 24fd65e74fae9..1c5f878f53b14 100644
--- a/code/game/objects/structures/barricade.dm
+++ b/code/game/objects/structures/barricade.dm
@@ -6,13 +6,13 @@
anchored = TRUE
density = TRUE
layer = BELOW_OBJ_LAYER
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
resistance_flags = XENO_DAMAGEABLE
allow_pass_flags = PASS_DEFENSIVE_STRUCTURE|PASSABLE|PASS_WALKOVER
climb_delay = 20 //Leaping a barricade is universally much faster than clumsily climbing on a table or rack
interaction_flags = INTERACT_CHECK_INCAPACITATED
max_integrity = 100
- flags_barrier = HANDLE_BARRIER_CHANCE
+ barrier_flags = HANDLE_BARRIER_CHANCE
///The type of stack the barricade dropped when disassembled if any.
var/stack_type
///The amount of stack dropped when disassembled at full health
@@ -75,18 +75,20 @@
/obj/structure/barricade/attack_animal(mob/user)
return attack_alien(user)
-/obj/structure/barricade/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/barricade/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(is_wired)
- balloon_alert(X, "Wire slices into us")
- X.apply_damage(10, blocked = MELEE , sharp = TRUE, updating_health = TRUE)
+ balloon_alert(xeno_attacker, "Wire slices into us")
+ xeno_attacker.apply_damage(10, blocked = MELEE , sharp = TRUE, updating_health = TRUE)
return ..()
/obj/structure/barricade/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
for(var/obj/effect/xenomorph/acid/A in loc)
if(A.acid_t == src)
@@ -267,6 +269,8 @@
//Item Attack
/obj/structure/barricade/snow/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
for(var/obj/effect/xenomorph/acid/A in loc)
if(A.acid_t == src)
@@ -345,6 +349,8 @@
/obj/structure/barricade/wooden/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
for(var/obj/effect/xenomorph/acid/A in loc)
if(A.acid_t == src)
@@ -438,6 +444,8 @@
/* RUTGMC DELETION, moved to modular
/obj/structure/barricade/metal/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/stack/sheet/metal))
return
@@ -894,6 +902,8 @@
/* RUTGMC DELETION, moved to modular
/obj/structure/barricade/plasteel/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/plasteel_sheets = I
@@ -1003,6 +1013,8 @@
/obj/structure/barricade/sandbags/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
for(var/obj/effect/xenomorph/acid/A in loc)
if(A.acid_t == src)
@@ -1059,7 +1071,7 @@
is_wired = FALSE
soft_armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 100, FIRE = 100, ACID = 30)
///Whether this item can be deployed or undeployed
- var/flags_item = IS_DEPLOYABLE
+ var/item_flags = IS_DEPLOYABLE
///What it deploys into. typecast version of internal_item
var/obj/item/weapon/shield/riot/marine/deployable/internal_shield
@@ -1073,9 +1085,10 @@
name = internal_shield.name
desc = internal_shield.desc
//if the shield is wired, it deploys wired
- if (internal_shield.is_wired)
+ if(internal_shield.is_wired)
can_wire = FALSE
is_wired = TRUE
+ climbable = FALSE
/obj/structure/barricade/metal/deployable/get_internal_item()
return internal_shield
@@ -1085,8 +1098,8 @@
///Dissassembles the device
/obj/structure/barricade/metal/deployable/proc/disassemble(mob/user)
- if(CHECK_BITFIELD(internal_shield.flags_item, DEPLOYED_NO_PICKUP))
- balloon_alert(user, "cannot be disassembled")
+ if(CHECK_BITFIELD(internal_shield.item_flags, DEPLOYED_NO_PICKUP))
+ balloon_alert(user, "Cannot disassemble")
return
SEND_SIGNAL(src, COMSIG_ITEM_UNDEPLOY, user)
diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm
index 5de219f123bf6..fccf55b9d037f 100644
--- a/code/game/objects/structures/barsign.dm
+++ b/code/game/objects/structures/barsign.dm
@@ -70,6 +70,8 @@
/obj/structure/sign/double/barsign/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(ismultitool(I))
var/sign_type = tgui_input_list(user, "What would you like to change the barsign to?", null, list("Off", "Pink Flamingo", "Magma Sea", "Limbo", "Rusty Axe", "Armok Bar", "Broken Drum", "Mead Bay", "The Damn Wall", "The Cavern", "Cindi Kate", "The Orchard", "The Saucy Clown", "The Clowns Head", "Whiskey Implant", "Carpe Carp", "Robust Roadhouse", "The Redshirt", "Maltese Falcon", "The Bark", "The Harmbaton", "The Singulo", "The Drunk Carp", "Scotch Servin Willys", "Officer Beersky", "The Cavern", "The Outer Spess", "Slippery Shots","The Grey Tide", "Honked N Loaded", "The Nest", "The Coderbus", "The Adminbus", "The Old Cock Inn", "The Wretched Hive", "The Robusta Cafe", "The Emergency Rum Party", "The Combo Cafe", "Vlad's Salad Bar", "The Shaken", "The Ale Nath", "The Aloha Snackbar", "The Net", "Maid Cafe", "The Lightbulb", "The Syndi Cat", "ERROR"))
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index 46eafc7015f98..e7db0eccdca67 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -101,7 +101,8 @@ LINEN BINS
. += "There are [amount] bed sheets in the bin."
-/obj/structure/bedsheetbin/update_icon()
+/obj/structure/bedsheetbin/update_icon_state()
+ . = ..()
switch(amount)
if(0)
icon_state = "linenbin-empty"
@@ -113,6 +114,8 @@ LINEN BINS
/obj/structure/bedsheetbin/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/bedsheet))
if(!user.drop_held_item())
diff --git a/code/game/objects/structures/benchpress.dm b/code/game/objects/structures/benchpress.dm
index 1c799861315dc..6b30b436325b9 100644
--- a/code/game/objects/structures/benchpress.dm
+++ b/code/game/objects/structures/benchpress.dm
@@ -85,11 +85,11 @@
return
do_workout_set(user)
-/obj/structure/benchpress/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/structure/benchpress/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(.)
return
- do_workout_set(X)
+ do_workout_set(xeno_attacker)
///checks if possible and if yes performs a workout set for this mob
/obj/structure/benchpress/proc/do_workout_set(mob/living/user)
@@ -99,7 +99,7 @@
ADD_TRAIT(src, BENCH_BEING_USED, WEIGHTBENCH_TRAIT) // yea this is meh but IN_USE and interact code are a mess rn and too buggy so less sidestep it
update_icon()
user.setDir(SOUTH)
- user.flags_atom |= DIRLOCK
+ user.atom_flags |= DIRLOCK
ADD_TRAIT(user, TRAIT_IMMOBILE, WEIGHTBENCH_TRAIT)
user.forceMove(loc)
var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
@@ -112,7 +112,7 @@
creak_loop.stop(src)
playsound(user, 'sound/machines/click.ogg', 60, TRUE)
REMOVE_TRAIT(src, BENCH_BEING_USED, WEIGHTBENCH_TRAIT)
- user.flags_atom &= ~DIRLOCK
+ user.atom_flags &= ~DIRLOCK
REMOVE_TRAIT(user, TRAIT_IMMOBILE, WEIGHTBENCH_TRAIT)
update_icon()
if(user.faction)
diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm
index d5bfa240ac36e..51f2ae164ccd6 100644
--- a/code/game/objects/structures/bookcase.dm
+++ b/code/game/objects/structures/bookcase.dm
@@ -18,6 +18,8 @@
/obj/structure/bookcase/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/book))
user.drop_held_item()
@@ -67,7 +69,8 @@
qdel(src)
-/obj/structure/bookcase/update_icon()
+/obj/structure/bookcase/update_icon_state()
+ . = ..()
if(length(contents) < 5)
icon_state = "book-[length(contents)]"
else
diff --git a/code/game/objects/structures/campaign_props.dm b/code/game/objects/structures/campaign_props.dm
index 6723521d5dcf1..c0beb09ae244e 100644
--- a/code/game/objects/structures/campaign_props.dm
+++ b/code/game/objects/structures/campaign_props.dm
@@ -21,6 +21,15 @@
allow_pass_flags = PASS_AIR
bound_width = 128
+/obj/structure/prop/train/Initialize(mapload)
+ . = ..()
+ update_icon()
+
+/obj/structure/prop/train/update_overlays()
+ . = ..()
+ var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_ALL_MOB_LAYER, dir)
+ . += new_overlay
+
/obj/structure/prop/train/carriage
name = "rail carriage"
desc = "A heavy duty maglev carriage. I wonder what's inside?."
diff --git a/code/game/objects/structures/campaign_structures/campaign_structure.dm b/code/game/objects/structures/campaign_structures/campaign_structure.dm
index f0b5597afde8d..7c3c2d9aae227 100644
--- a/code/game/objects/structures/campaign_structures/campaign_structure.dm
+++ b/code/game/objects/structures/campaign_structures/campaign_structure.dm
@@ -27,9 +27,11 @@
anchored = TRUE
allow_pass_flags = PASSABLE
destroy_sound = 'sound/effects/meteorimpact.ogg'
-
icon = 'icons/obj/structures/campaign_structures.dmi'
+ ///overhead timer
+ var/obj/effect/countdown/campaign_objective/countdown
+
/obj/structure/campaign_objective/Initialize(mapload)
. = ..()
GLOB.campaign_objectives += src
@@ -56,3 +58,7 @@
/obj/structure/campaign_objective/proc/update_control_minimap_icon()
SSminimaps.remove_marker(src)
SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('icons/UI_icons/map_blips.dmi', null, "campaign_objective", HIGH_FLOAT_LAYER))
+
+///Remaining time for overhead countdown if applicable
+/obj/structure/campaign_objective/proc/get_time_left()
+ return
diff --git a/code/game/objects/structures/campaign_structures/capture_objectives.dm b/code/game/objects/structures/campaign_structures/capture_objectives.dm
index 1c68a76a20b13..cc6681602c561 100644
--- a/code/game/objects/structures/campaign_structures/capture_objectives.dm
+++ b/code/game/objects/structures/campaign_structures/capture_objectives.dm
@@ -15,8 +15,6 @@
var/capturing_faction
///Timer holder for the current capture/decapture timer
var/capture_timer
- ///overhead timer
- var/obj/effect/countdown/campaign_objective/countdown
/obj/structure/campaign_objective/capture_objective/Initialize(mapload)
. = ..()
@@ -112,6 +110,9 @@
owning_faction = null
update_icon()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_DECAPTURED, src, user)
+ if(user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
+ personal_statistics.mission_objective_decaptured ++
return
finish_capture(user)
@@ -120,10 +121,12 @@
SHOULD_CALL_PARENT(TRUE)
owning_faction = user.faction
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CAMPAIGN_CAPTURE_OBJECTIVE_CAPTURED, src, user)
+ if(user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[user.ckey]
+ personal_statistics.mission_objective_captured ++
update_icon()
-///Returns time left on the nuke in seconds
-/obj/structure/campaign_objective/capture_objective/proc/get_time_left()
+/obj/structure/campaign_objective/capture_objective/get_time_left()
return capture_timer ? round(timeleft(capture_timer) MILLISECONDS) : null
//sensor tower
@@ -131,7 +134,13 @@
name = "sensor tower objective"
icon = 'icons/obj/structures/sensor.dmi'
icon_state = "sensor"
- mission_types = list(/datum/campaign_mission/tdm, /datum/campaign_mission/tdm/lv624, /datum/campaign_mission/tdm/first_mission, /datum/campaign_mission/tdm/mech_wars)
+ mission_types = list(
+ /datum/campaign_mission/tdm,
+ /datum/campaign_mission/tdm/orion,
+ /datum/campaign_mission/tdm/first_mission,
+ /datum/campaign_mission/tdm/mech_wars,
+ /datum/campaign_mission/tdm/mech_wars/som,
+ )
spawn_object = /obj/structure/campaign_objective/capture_objective/sensor_tower
/obj/structure/campaign_objective/capture_objective/sensor_tower
@@ -148,6 +157,7 @@
countdown.pixel_y = 90
/obj/structure/campaign_objective/capture_objective/sensor_tower/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(!owning_faction)
switch(capturing_faction)
@@ -220,12 +230,17 @@
icon_state = "asat"
desc = "A sophisticated surface to space missile system designed for attacking orbiting satellites or spacecraft."
capture_flags = CAPTURE_OBJECTIVE_RECAPTURABLE
- ///owning faction
- var/faction = FACTION_TERRAGOV
+ owning_faction = FACTION_TERRAGOV
/obj/structure/campaign_objective/capture_objective/fultonable/asat_system/capture_check(mob/living/user)
//This is a 'defend' objective. The defending faction can't actually claim it for themselves, just decap it.
- if((user.faction == faction) && !capturing_faction && !owning_faction)
+ if((user.faction == owning_faction) && !capturing_faction)
user.balloon_alert(user, "Defend this objective!")
return FALSE
return ..()
+
+/obj/structure/campaign_objective/capture_objective/fultonable/asat_system/do_capture(mob/living/user)
+ capturing_faction = null
+ capture_timer = null
+ countdown.stop()
+ finish_capture(user)
diff --git a/code/game/objects/structures/campaign_structures/deploy_blockers.dm b/code/game/objects/structures/campaign_structures/deploy_blockers.dm
index 7e544312cded0..3558749cfc1e8 100644
--- a/code/game/objects/structures/campaign_structures/deploy_blockers.dm
+++ b/code/game/objects/structures/campaign_structures/deploy_blockers.dm
@@ -17,7 +17,7 @@
icon_state = "tele_blocker"
pixel_x = -16
///What flag this removes from the mission
- var/flags_to_remove = MISSION_DISALLOW_TELEPORT
+ var/to_remove_flags = MISSION_DISALLOW_TELEPORT
///The faction this belongs to
var/faction = FACTION_TERRAGOV
var/owning_faction_notification = "A teleportation disruptor has been deployed in this area. Protect the disruptor to ensure hostile forces cannot deploy via teleportation. "
@@ -43,12 +43,15 @@
/obj/structure/campaign_deployblocker/ex_act()
return
-/obj/structure/campaign_deployblocker/plastique_act()
+/obj/structure/campaign_deployblocker/plastique_act(mob/living/plastique_user)
+ if(plastique_user && plastique_user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[plastique_user.ckey]
+ personal_statistics.mission_blocker_destroyed += (faction != plastique_user.faction ? 1 : -1)
qdel(src)
///Signals its destruction, enabling the use of the teleporter asset
/obj/structure/campaign_deployblocker/proc/deactivate()
- SEND_SIGNAL(SSdcs, COMSIG_GLOB_CAMPAIGN_TELEBLOCKER_DISABLED, src, flags_to_remove, faction)
+ SEND_SIGNAL(SSdcs, COMSIG_GLOB_CAMPAIGN_TELEBLOCKER_DISABLED, src, to_remove_flags, faction)
SSminimaps.remove_marker(src)
GLOB.campaign_structures -= src
@@ -56,13 +59,17 @@
name = "TELEBLOCKER"
icon = 'icons/obj/structures/campaign_structures.dmi'
icon_state = "drop_block"
- mission_types = list(/datum/campaign_mission/destroy_mission/supply_raid, /datum/campaign_mission/destroy_mission/fire_support_raid)
+ mission_types = list(
+ /datum/campaign_mission/destroy_mission/supply_raid,
+ /datum/campaign_mission/destroy_mission/fire_support_raid,
+ /datum/campaign_mission/raiding_base,
+ )
spawn_object = /obj/structure/campaign_deployblocker/drop_blocker
/obj/structure/campaign_deployblocker/drop_blocker
name = "drop pod guidance disruptor array"
desc = "A sophisticated device intended to severely disrupt drop pod guidance systems, rendering them unusable while the tower stands."
- flags_to_remove = MISSION_DISALLOW_DROPPODS
+ to_remove_flags = MISSION_DISALLOW_DROPPODS
faction = FACTION_SOM
owning_faction_notification = "A drop pod disruptor has been deployed in this area. Protect the disruptor to ensure hostile forces cannot deploy via drop pod. "
hostile_faction_notification = "The enemy has a device in this area that will prevent the use of our drop pods. Destroy this first to allow for drop pod assault against primary objectives. "
diff --git a/code/game/objects/structures/campaign_structures/destroy_objectives.dm b/code/game/objects/structures/campaign_structures/destroy_objectives.dm
index b36a00e85cd72..ddc07b4891e0c 100644
--- a/code/game/objects/structures/campaign_structures/destroy_objectives.dm
+++ b/code/game/objects/structures/campaign_structures/destroy_objectives.dm
@@ -5,12 +5,17 @@
soft_armor = list(MELEE = 200, BULLET = 200, LASER = 200, ENERGY = 200, BOMB = 200, BIO = 200, FIRE = 200, ACID = 200) //require c4 normally
///explosion smoke particle holder
var/obj/effect/abstract/particle_holder/explosion_smoke
+ ///The faction this belongs to
+ var/faction = FACTION_TERRAGOV
/obj/structure/campaign_objective/destruction_objective/Destroy()
QDEL_NULL(explosion_smoke)
return ..()
-/obj/structure/campaign_objective/destruction_objective/plastique_act()
+/obj/structure/campaign_objective/destruction_objective/plastique_act(mob/living/plastique_user)
+ if(plastique_user && plastique_user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[plastique_user.ckey]
+ personal_statistics.mission_objective_destroyed += (faction != plastique_user.faction ? 1 : -1)
qdel(src)
/obj/structure/campaign_objective/destruction_objective/plastique_time_mod(time)
@@ -30,6 +35,7 @@
icon = 'icons/Marine/howitzer.dmi'
icon_state = "howitzer_deployed"
pixel_x = -16
+ faction = FACTION_SOM
//MLRS
/obj/effect/landmark/campaign_structure/mlrs
@@ -67,10 +73,13 @@
/obj/structure/campaign_objective/destruction_objective/mlrs/update_overlays()
. = ..()
- var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_MOB_LAYER, dir)
+ var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_ALL_MOB_LAYER, dir)
. += new_overlay
-/obj/structure/campaign_objective/destruction_objective/mlrs/plastique_act()
+/obj/structure/campaign_objective/destruction_objective/mlrs/plastique_act(mob/living/plastique_user)
+ if(plastique_user && plastique_user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[plastique_user.ckey]
+ personal_statistics.mission_objective_destroyed += (faction != plastique_user.faction ? 1 : -1)
disable()
/obj/structure/campaign_objective/destruction_objective/mlrs/disable()
@@ -115,8 +124,8 @@
spawn_object = /obj/structure/campaign_objective/destruction_objective/mlrs/tank
/obj/structure/campaign_objective/destruction_objective/mlrs/tank
- name = "\improper tank"
- desc = "A massive multi launch rocket system on a tracked chassis. Can unleash a tremendous amount of firepower in a short amount of time."
+ name = "\improper M34A2 Longstreet Light Tank"
+ desc = "A giant piece of armor with a big gun, good for blowing stuff up."
icon_state = "tank"
/obj/effect/landmark/campaign_structure/apc
@@ -128,8 +137,8 @@
spawn_object = /obj/structure/campaign_objective/destruction_objective/mlrs/apc
/obj/structure/campaign_objective/destruction_objective/mlrs/apc
- name = "\improper APC"
- desc = "A massive multi launch rocket system on a tracked chassis. Can unleash a tremendous amount of firepower in a short amount of time."
+ name = "\improper M577 armored personnel carrier"
+ desc = "A giant piece of armor for carrying troops in relative safety. Still has a pretty big gun."
icon_state = "apc"
smoke_type = /particles/tank_wreck_smoke/apc
@@ -137,13 +146,6 @@
position = list(87, 60, 0)
//Supply depot objectives
-/obj/effect/landmark/campaign_structure/supply_objective
- name = "howitzer objective"
- icon = 'icons/Marine/howitzer.dmi'
- icon_state = "howitzer_deployed"
- mission_types = list(/datum/campaign_mission/destroy_mission/fire_support_raid)
- spawn_object = /obj/structure/campaign_objective/destruction_objective/howitzer
-
/obj/structure/campaign_objective/destruction_objective/supply_objective
name = "SUPPLY_OBJECTIVE"
icon = 'icons/Marine/howitzer.dmi'
@@ -165,6 +167,15 @@
allow_pass_flags = PASS_PROJECTILE|PASS_AIR
bound_width = 128
+/obj/structure/campaign_objective/destruction_objective/supply_objective/train/Initialize(mapload)
+ . = ..()
+ update_icon()
+
+/obj/structure/campaign_objective/destruction_objective/supply_objective/train/update_overlays()
+ . = ..()
+ var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_ALL_MOB_LAYER, dir)
+ . += new_overlay
+
/obj/effect/landmark/campaign_structure/train/carriage
name = "carriage objective"
icon_state = "carriage_lit"
@@ -190,6 +201,7 @@
icon_state = "phoron_stack"
bound_height = 32
bound_width = 64
+ faction = FACTION_SOM
/obj/structure/campaign_objective/destruction_objective/supply_objective/phoron_stack/Initialize(mapload)
. = ..()
@@ -197,7 +209,7 @@
/obj/structure/campaign_objective/destruction_objective/supply_objective/phoron_stack/update_overlays()
. = ..()
- var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_MOB_LAYER, dir)
+ var/image/new_overlay = image(icon, src, "[icon_state]_overlay", ABOVE_ALL_MOB_LAYER, dir)
. += new_overlay
//NT base
@@ -242,6 +254,7 @@
bound_width = 64
pixel_y = -18
pixel_x = -16
+ faction = FACTION_SOM
var/status = BLUESPACE_CORE_OK
/obj/structure/campaign_objective/destruction_objective/bluespace_core/Initialize(mapload)
@@ -260,10 +273,10 @@
switch(status)
if(BLUESPACE_CORE_OK)
. += image(icon, icon_state = "top_overlay", layer = ABOVE_MOB_LAYER)
- . += image(icon, icon_state = "bsd_c_s", layer = TANK_BARREL_LAYER)
+ . += image(icon, icon_state = "bsd_c_s", layer = ABOVE_MOB_PROP_LAYER)
if(BLUESPACE_CORE_UNSTABLE)
. += image(icon, icon_state = "top_overlay", layer = ABOVE_MOB_LAYER)
- . += image(icon, icon_state = "bsd_c_u", layer = TANK_BARREL_LAYER)
+ . += image(icon, icon_state = "bsd_c_u", layer = ABOVE_MOB_PROP_LAYER)
if(BLUESPACE_CORE_BROKEN)
. += image(icon, icon_state = "top_overlay_broken", layer = ABOVE_MOB_LAYER)
@@ -276,15 +289,18 @@
if(status == BLUESPACE_CORE_BROKEN)
disable()
-/obj/structure/campaign_objective/destruction_objective/bluespace_core/plastique_act()
+/obj/structure/campaign_objective/destruction_objective/bluespace_core/plastique_act(mob/living/plastique_user)
if(status == BLUESPACE_CORE_OK)
change_status(BLUESPACE_CORE_UNSTABLE)
else if(status == BLUESPACE_CORE_UNSTABLE)
+ if(plastique_user && plastique_user.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[plastique_user.ckey]
+ personal_statistics.mission_objective_destroyed += (faction != plastique_user.faction ? 1 : -1)
change_status(BLUESPACE_CORE_BROKEN)
//airbase
/obj/structure/prop/som_fighter
- name = "\improper Harbinger"
+ name = "harbinger"
desc = "A state of the art Harbinger class fighter. The premier fighter for SOM forces in space and atmosphere, bristling with high tech systems and weapons."
icon = 'icons/Marine/mainship_props96.dmi'
icon_state = "SOM_fighter"
@@ -294,7 +310,7 @@
allow_pass_flags = PASS_AIR
/obj/effect/landmark/campaign_structure/harbinger
- name = "\improper Harbinger"
+ name = "harbinger"
icon = 'icons/Marine/mainship_props96.dmi'
icon_state = "SOM_fighter"
pixel_x = -33
@@ -303,7 +319,7 @@
spawn_object = /obj/structure/campaign_objective/destruction_objective/harbinger
/obj/structure/campaign_objective/destruction_objective/harbinger
- name = "\improper Harbinger"
+ name = "harbinger"
desc = "A state of the art harbinger class fighter. The premier fighter for SOM forces in space and atmosphere, bristling with high tech systems and weapons."
icon = 'icons/Marine/mainship_props96.dmi'
icon_state = "SOM_fighter"
@@ -313,6 +329,7 @@
bound_width = 3
bound_x = -32
layer = ABOVE_MOB_LAYER
+ faction = FACTION_SOM
/obj/effect/landmark/campaign_structure/viper
name = "\improper Viper"
diff --git a/code/game/objects/structures/campaign_structures/misc_structures.dm b/code/game/objects/structures/campaign_structures/misc_structures.dm
new file mode 100644
index 0000000000000..a46501d122a38
--- /dev/null
+++ b/code/game/objects/structures/campaign_structures/misc_structures.dm
@@ -0,0 +1,26 @@
+//misc campaign structures/landmark spawners. Make sure mission types are set correctly, with child types made as required to avoid conflicts
+/obj/effect/landmark/campaign_structure/barricade
+ name = "fire_support_raid_barricade"
+ icon = 'icons/Marine/barricades.dmi'
+ icon_state = "metal_0"
+ mission_types = list(/datum/campaign_mission/destroy_mission/fire_support_raid)
+ spawn_object = /obj/structure/barricade/metal
+
+/obj/effect/landmark/campaign_structure/barricade/sandbags
+ name = "fire_support_raid_sandbags"
+ icon_state = "sandbag_0"
+ mission_types = list(/datum/campaign_mission/destroy_mission/fire_support_raid)
+ spawn_object = /obj/structure/barricade/sandbags
+
+/obj/effect/landmark/campaign_structure/barricade/sandbags/som
+ mission_types = list(/datum/campaign_mission/destroy_mission/fire_support_raid/som)
+
+/obj/effect/landmark/campaign_structure/barricade/sandbags/asat
+ name = "ASAT_capture_sandbags"
+ mission_types = list(/datum/campaign_mission/capture_mission/asat)
+
+/obj/effect/landmark/campaign_structure/barricade/concrete
+ name = "fire_support_raid_concrete"
+ icon_state = "concrete_0"
+ mission_types = list(/datum/campaign_mission/destroy_mission/fire_support_raid)
+ spawn_object = /obj/structure/barricade/concrete
diff --git a/code/game/objects/structures/campaign_structures/orbital_beacons.dm b/code/game/objects/structures/campaign_structures/orbital_beacons.dm
new file mode 100644
index 0000000000000..4a2808959010f
--- /dev/null
+++ b/code/game/objects/structures/campaign_structures/orbital_beacons.dm
@@ -0,0 +1,118 @@
+/obj/item/campaign_beacon
+ name = "default campaign beacon"
+ desc = "what smelly admin spawned this?"
+ icon = 'icons/Marine/marine-navigation.dmi'
+ icon_state = "motion4"
+ w_class = WEIGHT_CLASS_SMALL
+ item_flags = IS_DEPLOYABLE
+ ///Type path for what this deploys into
+ var/deployable_type
+ ///Time to deploy
+ var/deploy_time = 2 SECONDS
+ ///Time to undeploy
+ var/undeploy_time = 2 SECONDS
+
+/obj/item/campaign_beacon/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/deployable_item, deployable_type, deploy_time, undeploy_time, CALLBACK(src, PROC_REF(can_deploy)))
+
+///Any Additional checks for deploying validity
+/obj/item/campaign_beacon/proc/can_deploy(mob/user, turf/location)
+ return TRUE
+
+/obj/item/campaign_beacon/bunker_buster
+ name = "orbital beacon"
+ desc = "A bulky device that is used to provide precision guidance to powerful orbital weapon systems."
+ icon = 'icons/Marine/marine-navigation.dmi'
+ icon_state = "motion4"
+ deployable_type = /obj/structure/campaign_objective/destruction_objective/bunker_buster
+ deploy_time = 2 SECONDS
+ undeploy_time = 2 SECONDS
+ ///Can only be deployed in map areas listed here
+ var/list/valid_deploy_areas
+
+/obj/item/campaign_beacon/bunker_buster/Initialize(mapload)
+ . = ..()
+ GLOB.campaign_objectives += src
+ var/datum/campaign_mission/raiding_base/current_mission = get_current_mission()
+ if(!istype(current_mission))
+ return
+ valid_deploy_areas = current_mission.get_valid_beacon_areas()
+
+/obj/item/campaign_beacon/bunker_buster/Destroy()
+ GLOB.campaign_objectives -= src
+ return ..()
+
+/obj/item/campaign_beacon/bunker_buster/examine(mob/user)
+ . = ..()
+ if(!length(valid_deploy_areas))
+ return
+ var/location_info
+ location_info += "Can be deployed in the following areas: \n"
+ for(var/area/valid_area AS in valid_deploy_areas)
+ location_info += "[valid_area::name]\n"
+ . += location_info
+
+///Checks if we can deploy the beacon here
+/obj/item/campaign_beacon/bunker_buster/can_deploy(mob/user, turf/location)
+ var/area/beacon_area = get_area(location)
+ if(beacon_area.type in valid_deploy_areas)
+ return TRUE
+ if(user)
+ user.balloon_alert(user, "Cannot deploy here")
+ return FALSE
+
+///Delay between beacon timer finishing and the actual explosion
+#define CAMPAIGN_OB_BEACON_IMPACT_DELAY 10 SECONDS
+
+/obj/structure/campaign_objective/destruction_objective/bunker_buster
+ name = "deployed orbital beacon"
+ desc = "An ominous red beacon, used to provide precision guidance to powerful orbital weapon systems."
+ icon = 'icons/Marine/marine-navigation.dmi'
+ icon_state = "motion1"
+ faction = FACTION_TERRAGOV
+ density = FALSE
+ ///How long the beacon takes to trigger its effect
+ var/beacon_duration = 3 MINUTES
+ ///Holds the actual timer for the beacon
+ var/beacon_timer
+
+/obj/structure/campaign_objective/destruction_objective/bunker_buster/Initialize(mapload)
+ . = ..()
+ RegisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_TRIGGERED, PROC_REF(cancel_beacon))
+ SEND_SIGNAL(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_ACTIVATION, src)
+
+ beacon_timer = addtimer(CALLBACK(src, PROC_REF(beacon_effect)), beacon_duration, TIMER_STOPPABLE)
+ countdown = new(src)
+ countdown.pixel_x = 7
+ countdown.pixel_y = 24
+ countdown.start()
+
+/obj/structure/campaign_objective/destruction_objective/bunker_buster/Destroy()
+ QDEL_NULL(countdown)
+ if(beacon_timer)
+ deltimer(beacon_timer)
+ beacon_timer = null
+ return ..()
+
+/obj/structure/campaign_objective/destruction_objective/bunker_buster/get_time_left()
+ return beacon_timer ? round(timeleft(beacon_timer) MILLISECONDS) : null
+
+///Clears the beacon if another beacon successfully activates
+/obj/structure/campaign_objective/destruction_objective/bunker_buster/proc/cancel_beacon(datum/source)
+ SIGNAL_HANDLER
+ qdel(src)
+
+///Effects triggered when the timer runs out
+/obj/structure/campaign_objective/destruction_objective/bunker_buster/proc/beacon_effect()
+ UnregisterSignal(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_TRIGGERED)
+ SEND_SIGNAL(SSdcs, COMSIG_GLOB_CAMPAIGN_OB_BEACON_TRIGGERED, src, CAMPAIGN_OB_BEACON_IMPACT_DELAY)
+ for(var/mob/mob AS in GLOB.player_list)
+ if(mob.z != z)
+ continue
+ var/play_sound = 'sound/effects/OB_warning_announce_novoiceover.ogg'
+ if(isobserver(mob) || mob.faction == faction)
+ play_sound = 'sound/effects/OB_warning_announce.ogg'
+ mob.playsound_local(loc, play_sound, 125, falloff = 10, distance_multiplier = 0.2)
+
+#undef CAMPAIGN_OB_BEACON_IMPACT_DELAY
diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm
index 150dbf4121217..16035f84ab4ac 100644
--- a/code/game/objects/structures/coathanger.dm
+++ b/code/game/objects/structures/coathanger.dm
@@ -5,7 +5,7 @@
icon_state = "coatrack0"
coverage = 5
var/obj/item/clothing/suit/coat
- var/list/allowed = list(/obj/item/clothing/suit/storage/labcoat, /obj/item/clothing/suit/storage/det_suit, /obj/item/clothing/suit/bomber)
+ var/list/allowed = list(/obj/item/clothing/suit/storage/labcoat, /obj/item/clothing/suit/storage/det_suit, /obj/item/clothing/suit/storage/bomber)
/obj/structure/coatrack/Initialize(mapload)
. = ..()
@@ -25,6 +25,8 @@
/obj/structure/coatrack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!(I.type in allowed) || coat)
to_chat(user, span_notice("You cannot hang [I] on [src]"))
@@ -50,11 +52,11 @@
break
-/obj/structure/coatrack/update_icon()
- overlays.Cut()
+/obj/structure/coatrack/update_overlays()
+ . = ..()
if(istype(coat, /obj/item/clothing/suit/storage/labcoat))
- overlays += image(icon, icon_state = "coat_lab")
+ . += image(icon, icon_state = "coat_lab")
if(istype(coat, /obj/item/clothing/suit/storage/labcoat/cmo))
- overlays += image(icon, icon_state = "coat_cmo")
+ . += image(icon, icon_state = "coat_cmo")
if(istype(coat, /obj/item/clothing/suit/storage/det_suit))
- overlays += image(icon, icon_state = "coat_det")
+ . += image(icon, icon_state = "coat_det")
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 8007f73dcfade..268bcfd48835f 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -215,17 +215,17 @@
dump_contents()
qdel(src)
-/obj/structure/closet/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/structure/closet/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(!.)
return
- if(X.a_intent == INTENT_HARM && !opened && prob(70))
+ if(xeno_attacker.a_intent == INTENT_HARM && !opened && prob(70))
break_open()
/obj/structure/closet/attackby(obj/item/I, mob/user, params)
if(user in src)
return FALSE
- if(I.flags_item & ITEM_ABSTRACT)
+ if(I.item_flags & ITEM_ABSTRACT)
return FALSE
. = ..()
if(opened)
@@ -323,15 +323,17 @@
else
balloon_alert(usr, "Can't do this")
-/obj/structure/closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
- overlays.Cut()
+/obj/structure/closet/update_icon_state()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
+ . = ..()
if(!opened)
icon_state = icon_closed
- if(welded)
- overlays += image(icon, overlay_welded)
else
icon_state = icon_opened
+/obj/structure/closet/update_overlays()
+ . = ..()
+ if(!opened && welded)
+ . += image(icon, overlay_welded)
/obj/structure/closet/resisted_against(datum/source)
container_resist(source)
@@ -458,7 +460,7 @@
return FALSE
if(!CHECK_BITFIELD(destination.closet_flags, CLOSET_ALLOW_DENSE_OBJ) && density)
return FALSE
- if(CHECK_BITFIELD(flags_item, DELONDROP))
+ if(CHECK_BITFIELD(item_flags, DELONDROP))
return FALSE
var/item_size = CEILING(w_class * 0.5, 1)
if(item_size + destination.item_size_counter > destination.storage_capacity)
diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm
index 8d2413ac2367c..6a0eab48d6d7c 100644
--- a/code/game/objects/structures/crates_lockers/closets/coffin.dm
+++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm
@@ -8,6 +8,7 @@
anchored = FALSE
/obj/structure/closet/coffin/update_icon_state()
+ . = ..()
if(!opened)
icon_state = icon_closed
else
diff --git a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm
index 9504f2a66392c..b4dc832c61e04 100644
--- a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm
@@ -30,7 +30,7 @@
to_chat(user, "You disable the locking modules.")
update_icon()
return
- else if(!(O.flags_item & NOBLUDGEON) && O.force)
+ else if(!(O.item_flags & NOBLUDGEON) && O.force)
var/obj/item/W = O
if(src.smashed || src.localopened)
if(localopened)
@@ -53,7 +53,7 @@
return
if (istype(O, /obj/item/weapon/twohanded/fireaxe) && src.localopened)
if(!fireaxe)
- if(O.flags_item & WIELDED)
+ if(O.item_flags & WIELDED)
to_chat(user, span_warning("Unwield the axe first."))
return
fireaxe = O
@@ -191,7 +191,9 @@
to_chat(user, span_notice("Cabinet unlocked."))
return
-/obj/structure/closet/fireaxecabinet/update_icon() //Template: fireaxe[has fireaxe][is opened][hits taken][is smashed]. If you want the opening or closing animations, add "opening" or "closing" right after the numbers
+//Template: fireaxe[has fireaxe][is opened][hits taken][is smashed]. If you want the opening or closing animations, add "opening" or "closing" right after the numbers
+/obj/structure/closet/fireaxecabinet/update_icon_state()
+ . = ..()
var/hasaxe = 0
if(fireaxe)
hasaxe = 1
diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
index 06e05dff0860f..c4f4a99119ad5 100644
--- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm
+++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
@@ -9,6 +9,7 @@
AddElement(/datum/element/debris, DEBRIS_WOOD, -10, 5)
/obj/structure/closet/cabinet/update_icon_state()
+ . = ..()
if(!opened)
icon_state = icon_closed
else
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
index c3686b58dc40e..92590d29814b3 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
@@ -23,6 +23,7 @@
new /obj/item/reagent_containers/food/drinks/cans/beer( src )
/obj/structure/closet/secure_closet/bar/update_icon_state()
+ . = ..()
if(broken)
icon_state = icon_broken
return
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
index 7e65054f0121d..854b71e9c9752 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
@@ -8,6 +8,7 @@
icon_off = "fridge1"
/obj/structure/closet/secure_closet/freezer/update_icon_state()
+ . = ..()
if(broken)
icon_state = icon_broken
return
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm
index c2314e38e1a0c..7082cbc11ba9d 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm
@@ -13,9 +13,9 @@
. = ..()
switch(rand(1,2))
if(1)
- new /obj/item/clothing/suit/apron(src)
+ new /obj/item/clothing/suit/storage/apron(src)
if(2)
- new /obj/item/clothing/suit/apron/overalls(src)
+ new /obj/item/clothing/suit/storage/apron/overalls(src)
new /obj/item/storage/bag/plants(src)
new /obj/item/clothing/under/rank/hydroponics(src)
new /obj/item/tool/analyzer/plant_analyzer(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
index 68434d3284483..ab112d2039125 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -31,7 +31,8 @@
icon_broken = "cabinetdetective_broken"
icon_off = "cabinetdetective_broken"
-/obj/structure/closet/secure_closet/personal/cabinet/update_icon()
+/obj/structure/closet/secure_closet/personal/cabinet/update_icon_state()
+ . = ..()
if(broken)
icon_state = icon_broken
else
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index a29102023f1a2..93618348f5f14 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -50,14 +50,17 @@
return
togglelock(usr)
-/obj/structure/closet/secure_closet/update_icon()
- overlays.Cut()
+/obj/structure/closet/secure_closet/update_icon_state()
+ . = ..()
if(opened)
icon_state = icon_opened
else
icon_state = locked ? icon_locked : icon_closed
+
+/obj/structure/closet/secure_closet/update_overlays()
+ . = ..()
if(welded)
- overlays += overlay_welded
+ . += overlay_welded
/obj/structure/closet/secure_closet/break_open()
broken = TRUE
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 12872e153fd1f..e91d658cfd0a5 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -271,7 +271,8 @@
new /obj/item/armor_module/storage/uniform/holster/armpit(src)
-/obj/structure/closet/secure_closet/detective/update_icon()
+/obj/structure/closet/secure_closet/detective/update_icon_state()
+ . = ..()
if(broken)
icon_state = icon_broken
else
@@ -356,7 +357,8 @@
large = FALSE
-/obj/structure/closet/secure_closet/wall/update_icon()
+/obj/structure/closet/secure_closet/wall/update_icon_state()
+ . = ..()
if(broken)
icon_state = icon_broken
else
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 58fc58a48db8b..461263a1d6fc0 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -78,7 +78,8 @@
new /obj/item/tool/extinguisher(src)
new /obj/item/clothing/head/hardhat/red(src)
-/obj/structure/closet/firecloset/update_icon()
+/obj/structure/closet/firecloset/update_icon_state()
+ . = ..()
if(!opened)
icon_state = icon_closed
else
diff --git a/code/game/objects/structures/crates_lockers/largecrate_supplies.dm b/code/game/objects/structures/crates_lockers/largecrate_supplies.dm
index 41f1254c74285..f05ef65fc5837 100644
--- a/code/game/objects/structures/crates_lockers/largecrate_supplies.dm
+++ b/code/game/objects/structures/crates_lockers/largecrate_supplies.dm
@@ -139,7 +139,7 @@
/obj/structure/largecrate/supply/weapons/standard_hmg
name = "\improper HSG-102 mounted heavy smartgun chest (x2)"
desc = "A supply crate containing two boxed HSG-102 mounted heavy smartguns."
- supplies = list(/obj/item/storage/box/tl102 = 2)
+ supplies = list(/obj/item/storage/box/hsg_102 = 2)
/obj/structure/largecrate/supply/weapons/standard_atgun
name = "\improper AT-36 anti tank gun and ammo chest (x1, x10)"
@@ -160,6 +160,11 @@
/obj/item/ammo_magazine/auto_cannon/flak = 3,
)
+/obj/structure/largecrate/supply/weapons/heavy_flakgun
+ name = "\improper FK-88 mounted flak gun (x1)"
+ desc = "A supply crate containing a FK-88 mounted flak gun. Ammo sold separately."
+ supplies = list(/obj/item/weapon/gun/heavy_isg = 1)
+
/obj/structure/largecrate/supply/ammo
name = "ammunition case"
icon_state = "case"
@@ -197,7 +202,7 @@
/obj/structure/largecrate/supply/ammo/standard_hmg
name = "\improper HSG-102 ammunition box case (x6)"
desc = "An ammunition case containing six HSG-102 ammunition boxes."
- supplies = list(/obj/item/ammo_magazine/tl102 = 6)
+ supplies = list(/obj/item/ammo_magazine/hsg_102 = 6)
/obj/structure/largecrate/supply/ammo/standard_ammo
name = "large surplus ammuniton crate"
@@ -397,7 +402,7 @@
/obj/structure/largecrate/machine/autodoc/attackby(obj/item/I, mob/user, params)
. = ..()
- if(!.)
+ if(.)
return
if(iscrowbar(I))
@@ -417,7 +422,7 @@
/obj/structure/largecrate/supply/machine/bodyscanner/attackby(obj/item/I, mob/user, params)
. = ..()
- if(!.)
+ if(.)
return
if(iscrowbar(I))
@@ -436,7 +441,7 @@
/obj/structure/largecrate/machine/sleeper/attackby(obj/item/I, mob/user, params)
. = ..()
- if(!.)
+ if(.)
return
if(iscrowbar(I))
diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm
index 06f22499cc5e6..ac69840f78c02 100644
--- a/code/game/objects/structures/crates_lockers/secure_crates.dm
+++ b/code/game/objects/structures/crates_lockers/secure_crates.dm
@@ -17,16 +17,17 @@
. = ..()
update_icon()
-
-/obj/structure/closet/crate/secure/update_icon()
- overlays.Cut()
+/obj/structure/closet/crate/secure/update_icon_state()
+ . = ..()
if(opened)
icon_state = icon_opened
else
icon_state = locked ? icon_locked : icon_unlocked
- if(welded)
- overlays += overlay_welded
+/obj/structure/closet/crate/secure/update_overlays()
+ . = ..()
+ if(welded)
+ . += overlay_welded
/obj/structure/closet/crate/secure/can_open()
return !locked
diff --git a/code/game/objects/structures/crates_lockers/walllocker.dm b/code/game/objects/structures/crates_lockers/walllocker.dm
index cfe5ff7b18c10..c37ccbcdebed2 100644
--- a/code/game/objects/structures/crates_lockers/walllocker.dm
+++ b/code/game/objects/structures/crates_lockers/walllocker.dm
@@ -50,6 +50,7 @@
icon_closed = "hydrant"
icon_opened = "hydrantopen"
overlay_welded = "hydrant-medical_welded"
+ layer = ABOVE_OBJ_LAYER
/obj/structure/closet/walllocker/hydrant/extinguisher
diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm
index eea081b66866b..c8d0e8e33e4f9 100644
--- a/code/game/objects/structures/curtains.dm
+++ b/code/game/objects/structures/curtains.dm
@@ -23,11 +23,11 @@
playsound(get_turf(loc), "rustle", 15, 1, 6)
toggle()
-/obj/structure/curtain/attack_alien(mob/living/carbon/xenomorph/attackingxeno, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
- if(!do_after(attackingxeno, XENO_CURTAIN_PULL_DELAY, NONE, src, BUSY_ICON_FRIENDLY))
+/obj/structure/curtain/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(!do_after(xeno_attacker, XENO_CURTAIN_PULL_DELAY, NONE, src, BUSY_ICON_FRIENDLY))
return
- attackingxeno.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- attackingxeno.visible_message(span_danger("\The [attackingxeno] pulls [src] down and slices it apart!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] pulls [src] down and slices it apart!"), \
span_danger("You pull the [src] down and rip it to shreds!"), null, 5)
qdel(src)
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 70352e706a1a8..d1e29cdba9921 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -24,7 +24,8 @@
*/
-/obj/structure/displaycase/update_icon()
+/obj/structure/displaycase/update_icon_state()
+ . = ..()
if(destroyed)
icon_state = "glassboxb[occupied]"
else
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index edb2d65539f29..8fc90a3ebafa6 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -136,7 +136,8 @@
/obj/structure/door_assembly/attackby(obj/item/I, mob/user, params)
. = ..()
-
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen))
var/t = copytext(stripped_input(user, "Enter the name for the door.", name, created_name), 1, MAX_NAME_LEN)
if(!t)
diff --git a/code/game/objects/structures/droppod.dm b/code/game/objects/structures/droppod.dm
index 7ff0b37230fac..0d0489116c595 100644
--- a/code/game/objects/structures/droppod.dm
+++ b/code/game/objects/structures/droppod.dm
@@ -4,6 +4,8 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
#define DROPPOD_TRANSIT_TIME 10 SECONDS
///radius of dispersion for leader pods
#define LEADER_POD_DISPERSION 5
+///radius of dispersion for pods for randomisation or obstacle avoidance
+#define DROPPOD_BASE_DISPERSION 1
///base marine drop pod. can be controlled by an attached [/obj/structure/droppod/leader] or [/obj/machinery/computer/droppod_control]
/obj/structure/droppod
@@ -18,7 +20,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
interaction_flags = INTERACT_OBJ_DEFAULT|INTERACT_POWERLOADER_PICKUP_ALLOWED_BYPASS_ANCHOR
soft_armor = list(MELEE = 25, BULLET = 80, LASER = 80, ENERGY = 90, BOMB = 70, BIO = 100, FIRE = 0, ACID = 0)
max_integrity = 75
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
coverage = 75
buckle_flags = CAN_BUCKLE|BUCKLE_PREVENTS_PULL
light_range = 1
@@ -99,6 +101,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
set_light(0)
/obj/structure/droppod/update_icon_state()
+ . = ..()
if(drop_state == DROPPOD_ACTIVE)
icon_state = initial(icon_state)
else if(operation_started && launch_allowed)
@@ -167,7 +170,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
balloon_alert(user, "Hazardous zone")
return FALSE
var/area/targetarea = get_area(target)
- if(targetarea.flags_area & NO_DROPPOD) // Thou shall not pass!
+ if(targetarea.area_flags & NO_DROPPOD) // Thou shall not pass!
if(user)
balloon_alert(user, "Invalid area")
return FALSE
@@ -210,13 +213,18 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
if(drop_state != DROPPOD_READY)
return
+ var/turf/target = locate(target_x, target_y, target_z)
+ if(!commanded_drop) //we randomise the landing slightly, its already randomised for mass launch
+ target = find_new_target()
+ target_x = target.x
+ target_y = target.y
+
if(!checklanding(user))
return
for(var/mob/podder AS in buckled_mobs)
podder.forceMove(src)
- var/turf/target = locate(target_x, target_y, target_z)
if(user)
log_game("[key_name(user)] launched pod [src] at [AREACOORD(target)]")
deadchat_broadcast(" has been launched", src, turf_target = target)
@@ -230,6 +238,22 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
flick("[icon_state]_closing", src)
addtimer(CALLBACK(src, PROC_REF(launch_pod), user), 2.5 SECONDS)
+///Find a new suitable target turf around the pods initial target
+/obj/structure/droppod/proc/find_new_target(mob/user)
+ var/scatter_radius = DROPPOD_BASE_DISPERSION + GLOB.current_orbit
+ var/turf/T0 = locate(target_x + scatter_radius, target_y + scatter_radius, target_z)
+ var/turf/T1 = locate(target_x - scatter_radius, target_y - scatter_radius, target_z)
+ var/list/block = block(T0,T1)
+ shuffle_inplace(block)
+ for(var/turf/attemptdrop AS in block)
+ if(!checklanding(optional_turf = attemptdrop))
+ continue
+ return attemptdrop
+
+ if(user)
+ to_chat(user, span_warning("[icon2html(src, user)] RECALCULATION FAILED!"))
+ return locate(target_x, target_y, target_z) //no other alt spots found, we return our original target
+
///actually launches the pod
/obj/structure/droppod/proc/launch_pod(mob/user)
if(!launch_allowed)
@@ -244,33 +268,21 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
playsound(src, 'sound/effects/escape_pod_launch.ogg', 70)
playsound(src, 'sound/effects/droppod_launch.ogg', 70)
- addtimer(CALLBACK(src, PROC_REF(finish_drop), user), DROPPOD_TRANSIT_TIME)
+ addtimer(CALLBACK(src, PROC_REF(finish_drop), user), ROUND_UP(DROPPOD_TRANSIT_TIME * ((GLOB.current_orbit + 3) / 6)))
forceMove(pick(reserved_area.reserved_turfs))
new /area/arrival(loc) //adds a safezone so we dont suffocate on the way down, cleaned up with reserved turfs
/// Moves the droppod into its target turf, which it updates if needed
/obj/structure/droppod/proc/finish_drop(mob/user)
var/turf/targetturf = locate(target_x, target_y, target_z)
- for(var/a in targetturf.contents)
- var/atom/target = a
- if(target.density) //if theres something dense in the turf try to recalculate a new turf
- if(user)
- to_chat(user, span_warning("[icon2html(src, user)] WARNING! TARGET ZONE OCCUPIED! EVADING!"))
- balloon_alert(user, "EVADING")
- var/turf/T0 = locate(target_x + 2,target_y + 2, target_z)
- var/turf/T1 = locate(target_x - 2,target_y - 2, target_z)
- var/list/block = block(T0,T1) - targetturf
- for(var/t in block)//Randomly selects a free turf in a 5x5 block around the target
- var/turf/attemptdrop = t
- if(!attemptdrop.density && !is_type_in_typecache(attemptdrop, GLOB.blocked_droppod_tiles))
- targetturf = attemptdrop
- break
- if(targetturf.density)//We tried and failed, revert to the old one, which has a new dense obj but is at least not dense
- if(user)
- to_chat(user, span_warning("[icon2html(src, user)] RECALCULATION FAILED!"))
- targetturf = locate(target_x, target_y, target_z)
- break
-
+ for(var/atom/target AS in targetturf.contents)
+ if(!target.density)
+ continue
+ if(user)
+ to_chat(user, span_warning("[icon2html(src, user)] WARNING! TARGET ZONE OCCUPIED! EVADING!"))
+ balloon_alert(user, "EVADING")
+ targetturf = find_new_target(user)
+ break
forceMove(targetturf)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_DROPPOD_LANDED, targetturf)
pixel_y = 500
@@ -320,7 +332,8 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
for(var/obj/structure/droppod/pod AS in GLOB.droppod_list)
if(LAZYLEN(pod.buckled_mobs) || LAZYLEN(pod.contents))
occupied_pods++
- var/dispersion = max(LEADER_POD_DISPERSION, LEADER_POD_DISPERSION + ((occupied_pods - 10) / 5))
+ var/dispersion = LEADER_POD_DISPERSION + GLOB.current_orbit
+ dispersion = max(dispersion, dispersion + ((occupied_pods - 10) / 5))
var/turf/topright = locate(new_x + dispersion, new_y + dispersion, target_z)
var/turf/bottomleft = locate(new_x - dispersion, new_y - dispersion, target_z)
var/list/block = block(bottomleft, topright) - locate()
@@ -374,6 +387,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
return ..()
/obj/structure/droppod/nonmob/update_icon_state()
+ . = ..()
if(drop_state == DROPPOD_ACTIVE)
icon_state = initial(icon_state)
else if(stored_object)
@@ -466,7 +480,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
/obj/structure/droppod/nonmob/mech_pod
name = "\improper TGMC Zeus mech drop pod"
- desc = "A menacing metal hunk of steel that is used by the TGMC for quick tactical redeployment. This is a larger model designed specifically to carry mechs."
+ desc = "A menacing metal hunk of steel that is used by the TGMC for quick tactical redeployment. This is a larger model designed specifically to carry mechs. Shift click to enter when inside a mech."
icon = 'icons/obj/structures/big_droppod.dmi'
icon_state = "mechpod"
light_range = 2
@@ -494,7 +508,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
/obj/structure/droppod/nonmob/mech_pod/ex_act(severity)
switch(severity)
if(EXPLODE_DEVASTATE)
- take_damage(100, BRUTE, BOMB, 0)
+ take_damage(100, BRUTE, BOMB)
if(EXPLODE_HEAVY)
take_damage(50, BRUTE, BOMB, 0)
*/
@@ -610,3 +624,12 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi
/obj/structure/drop_pod_launcher/leader
pod_type = /obj/structure/droppod/leader
+
+/obj/structure/drop_pod_launcher/mech
+ pod_type = /obj/structure/droppod/nonmob/mech_pod
+
+/obj/structure/drop_pod_launcher/supply
+ pod_type = /obj/structure/droppod/nonmob/supply_pod
+
+/obj/structure/drop_pod_launcher/sentry
+ pod_type = /obj/structure/droppod/nonmob/turret_pod
diff --git a/code/game/objects/structures/dropship_ammo.dm b/code/game/objects/structures/dropship_ammo.dm
index ce2a8fc74f8d6..a6e5c8ac72eb6 100644
--- a/code/game/objects/structures/dropship_ammo.dm
+++ b/code/game/objects/structures/dropship_ammo.dm
@@ -16,16 +16,23 @@
var/travelling_time = 10 SECONDS
///type of equipment that accept this type of ammo.
var/equipment_type
+ ///current ammo count
var/ammo_count
+ ///maximum ammo count. does NOT determine starting ammo
var/max_ammo_count
- var/ammo_name = "rounds" //what to call the ammo in the ammo transfering message
+ ///what to call the ammo in the ammo transfering message
+ var/ammo_name = "rounds"
var/ammo_id
///whether the ammo inside this magazine can be transfered to another magazine.
var/transferable_ammo = FALSE
///sound played mere seconds before impact
var/warning_sound = 'sound/machines/hydraulics_2.ogg'
+ ///voiceline to play half a second after the weapon is fired
+ var/firing_voiceline
+ ///how much ammo to use up per firing sequence
var/ammo_used_per_firing = 1
- var/point_cost = 0 //how many points it costs to build this with the fabricator, set to 0 if unbuildable.
+ ///how many points it costs to build this with the fabricator, set to 0 if unbuildable.
+ var/point_cost = 0
///Type of ammo
var/ammo_type
@@ -211,12 +218,12 @@
transferable_ammo = TRUE
ammo_used_per_firing = 200
point_cost = 100
+ ammo_type = CAS_30MM
+ cas_effect = /obj/effect/overlay/blinking_laser/heavygun
///Radius of the square that the bullets will strafe
var/bullet_spread_range = 2
///Width of the square we are attacking, so you can make rectangular attacks later
var/attack_width = 3
- ammo_type = CAS_30MM
- cas_effect = /obj/effect/overlay/blinking_laser/heavygun
/obj/structure/ship_ammo/cas/heavygun/examine(mob/user)
. = ..()
@@ -268,7 +275,7 @@
name = "high-velocity 30mm ammo crate"
icon_state = "30mm_crate_hv"
desc = "A crate full of 30mm high-velocity bullets used on the dropship heavy guns. Moving this will require some sort of lifter."
- travelling_time = 3 SECONDS
+ travelling_time = 2 SECONDS
point_cost = 225
@@ -322,10 +329,10 @@
ammo_used_per_firing = 10
warning_sound = 'sound/effects/nightvision.ogg'
point_cost = 150
- ///The length of the beam that will come out of when we fire do both ends xxxoxxx where o is where you click
- var/laze_radius = 4
ammo_type = CAS_LASER_BATTERY
cas_effect = /obj/effect/overlay/blinking_laser/laser
+ ///The length of the beam that will come out of when we fire do both ends xxxoxxx where o is where you click
+ var/laze_radius = 4
/obj/structure/ship_ammo/cas/laser_battery/examine(mob/user)
. = ..()
@@ -367,7 +374,7 @@
T.ignite(5, 30) //short but intense
-//Rockets
+//Rockets are defined by being one shot and done, and generally having solid payloads and low travel times.
/obj/structure/ship_ammo/cas/rocket
name = "abstract rocket"
@@ -378,6 +385,7 @@
max_ammo_count = 1
ammo_name = "rocket"
ammo_id = ""
+ firing_voiceline = 'sound/voice/plane_vws/shot_missile.ogg'
bound_width = 64
bound_height = 32
travelling_time = 4 SECONDS
@@ -385,39 +393,76 @@
ammo_type = CAS_MISSILE
/obj/structure/ship_ammo/cas/rocket/detonate_on(turf/impact, attackdir = NORTH)
+ impact.ceiling_debris_check(3)
+ explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range)
qdel(src)
+//ATGMs, defined by 3 second travel time and tight explosion sizes.
-//this one is air-to-air only
+// The widowmaker is defined by being the fastest ATGM on offer, however it suffers in explosive potiential due to being so fast.
/obj/structure/ship_ammo/cas/rocket/widowmaker
- name = "\improper AIM-224 'Widowmaker'"
- desc = "The AIM-224 is the latest in air to air missile technology. Earning the nickname of 'Widowmaker' from various dropship pilots after improvements to its guidence warhead prevents it from being jammed leading to its high kill rate. Not well suited for ground bombardment, but its high velocity makes it reach its target quickly. Moving this will require some sort of lifter."
+ name = "\improper AGM-224 'Widowmaker'"
+ desc = "The AGM-224 is the latest in air to ground missile technology. Earning the nickname of 'Widowmaker' from various pilots after improvements allow it to land at incredibly high speeds, at the cost of explosive payload. Well suited for ground bombardment, its high velocity making it reach its target quickly. Moving this will require some sort of lifter."
icon_state = "single"
- travelling_time = 3 SECONDS //not powerful, but reaches target fast
+ travelling_time = 2 SECONDS //The epitome of ATGMs.
ammo_id = ""
+ point_cost = 300
+ devastating_explosion_range = 2
+ heavy_explosion_range = 3
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/widowmaker
+
+/obj/structure/ship_ammo/cas/rocket/keeper
+ name = "\improper AGM-67 'Keeper II"
+ desc = "The AGM-67 'Keeper II' is the latest in a generation of laser guided weaponry that spans all the way back to the 20th century. Earning its nickname from a contract that developed its guidance system and the various uses of it during peacekeeping conflicts. Its payload is designed to devastate armored targets. Moving this will require some sort of lifter."
+ icon_state = "keeper"
+ ammo_id = "k"
point_cost = 225
devastating_explosion_range = 2
heavy_explosion_range = 4
- light_explosion_range = 7
+ travelling_time = 3 SECONDS
prediction_type = CAS_AMMO_EXPLOSIVE
- cas_effect = /obj/effect/overlay/blinking_laser/widowmaker
-/obj/structure/ship_ammo/cas/rocket/widowmaker/detonate_on(turf/impact, attackdir = NORTH)
+// Da warcrime ATGM. Lower explosive yield, but long lasting fire.
+/obj/structure/ship_ammo/cas/rocket/napalm
+ name = "\improper AGM-99 'Napalm'"
+ desc = "The AGM-99 'Napalm' is an incendiary rocket used to turn specific targeted areas into giant balls of fire for quite a long time, it has a smaller outer explosive payload than other AGMs, however. Moving this will require some sort of lifter."
+ icon_state = "napalm"
+ ammo_id = "n"
+ point_cost = 275
+ devastating_explosion_range = 2
+ heavy_explosion_range = 3
+ light_explosion_range = 4
+ fire_range = 3
+ travelling_time = 3 SECONDS
+ prediction_type = CAS_AMMO_INCENDIARY
+ cas_effect = /obj/effect/overlay/blinking_laser/napalm
+
+/obj/structure/ship_ammo/cas/rocket/napalm/detonate_on(turf/impact, attackdir = NORTH)
impact.ceiling_debris_check(3)
explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range)
+ flame_radius(fire_range, impact, 30, 60) //cooking for a long time
+ var/datum/effect_system/smoke_spread/phosphorus/warcrime = new
+ warcrime.set_up(fire_range + 1, impact, 7)
+ warcrime.start()
qdel(src)
+
+// High yield missiles are defined by having... high yields and high travel time, usually around six seconds.
+
+//The Banshee is defined by combining both explosive and fire into one, literally. At the cost of some outer payload yield.
/obj/structure/ship_ammo/cas/rocket/banshee
- name = "\improper AGM-227 'Banshee'"
- desc = "The AGM-227 missile is a mainstay of the overhauled dropship fleet against any mobile or armored ground targets. It's earned the nickname of 'Banshee' from the sudden wail that it emitts right before hitting a target. Useful to clear out large areas. Moving this will require some sort of lifter."
+ name = "\improper PGHM-227 'Banshee'"
+ desc = "The PGHM-227 missile is a mainstay of the fleet against any mobile or armored ground targets. It's earned the nickname of 'Banshee' from the sudden wail that it emitts right before hitting a target. Useful to clear out large areas. Moving this will require some sort of lifter."
icon_state = "banshee"
ammo_id = "b"
- point_cost = 225
+ point_cost = 275
devastating_explosion_range = 2
heavy_explosion_range = 4
- light_explosion_range = 7
+ light_explosion_range = 5
fire_range = 7
prediction_type = CAS_AMMO_INCENDIARY
+ travelling_time = 6 SECONDS
cas_effect = /obj/effect/overlay/blinking_laser/banshee
/obj/structure/ship_ammo/cas/rocket/banshee/detonate_on(turf/impact, attackdir = NORTH)
@@ -425,32 +470,18 @@
explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range, flame_range = fire_range) //more spread out, with flames
qdel(src)
-/obj/structure/ship_ammo/cas/rocket/keeper
- name = "\improper GBU-67 'Keeper II'"
- desc = "The GBU-67 'Keeper II' is the latest in a generation of laser guided weaponry that spans all the way back to the 20th century. Earning its nickname from a shortening of 'Peacekeeper' which comes from the program that developed its guidance system and the various uses of it during peacekeeping conflicts. Its payload is designed to devastate armored targets. Moving this will require some sort of lifter."
- icon_state = "keeper"
- ammo_id = "k"
- point_cost = 300
- devastating_explosion_range = 4
- heavy_explosion_range = 4
- light_explosion_range = 5
- prediction_type = CAS_AMMO_EXPLOSIVE
-
-/obj/structure/ship_ammo/cas/rocket/keeper/detonate_on(turf/impact, attackdir = NORTH)
- impact.ceiling_debris_check(3)
- explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range) //tighter blast radius, but more devastating near center
- qdel(src)
-
+//The fatty is well.. Fat.
/obj/structure/ship_ammo/cas/rocket/fatty
- name = "\improper SM-17 'Fatty'"
- desc = "The SM-17 'Fatty' is the most devestating rocket in TGMC arsenal, only second after its big cluster brother in Orbital Cannon. These rocket are also known for highest number of Friendly-on-Friendly incidents due to secondary cluster explosions as well as range of these explosions, TGMC recommends pilots to encourage usage of signal flares or laser for 'Fatty' support. Moving this will require some sort of lifter."
+ name = "\improper PHGM-17 'Fatty'"
+ desc = "The PHGM-17 'Fatty' is the most devestating rocket in TGMC arsenal, only second after its big cluster brother in Orbital Cannon. These rocket are also known for highest number of Friendly-on-Friendly incidents due to secondary cluster explosions as well as range of these explosions, TGMC recommends pilots to encourage usage of signal flares or laser for 'Fatty' support. Moving this will require some sort of lifter."
icon_state = "fatty"
ammo_id = "f"
- point_cost = 325
+ point_cost = 300
devastating_explosion_range = 2
heavy_explosion_range = 3
light_explosion_range = 4
prediction_type = CAS_AMMO_EXPLOSIVE
+ travelling_time = 6 SECONDS
cas_effect = /obj/effect/overlay/blinking_laser/fatty
/obj/structure/ship_ammo/cas/rocket/fatty/detonate_on(turf/impact, attackdir = NORTH)
@@ -474,31 +505,36 @@
explosion(detonation_target, devastating_explosion_range, heavy_explosion_range, light_explosion_range, adminlog = FALSE)
qdel(src)
-/obj/structure/ship_ammo/cas/rocket/napalm
- name = "\improper XN-99 'Napalm'"
- desc = "The XN-99 'Napalm' is an incendiary rocket used to turn specific targeted areas into giant balls of fire for a long time. Moving this will require some sort of lifter."
- icon_state = "napalm"
- ammo_id = "n"
+// This is the "Default" heavy rocket.
+/obj/structure/ship_ammo/cas/rocket/monarch
+ name = "\improper PHGM-7 'Monarch'"
+ desc = "The PHGM-7 'Monarch' is a well tried and tested dumb rocket design due to being a mere dumb rocket. Its payload is designed to devastate areas for cheap. Moving this will require some sort of lifter."
+ icon_state = "monarch"
+ ammo_id = "m"
point_cost = 250
- devastating_explosion_range = 2
- heavy_explosion_range = 3
- light_explosion_range = 4
- fire_range = 5
- prediction_type = CAS_AMMO_INCENDIARY
- cas_effect = /obj/effect/overlay/blinking_laser/incendiary
-
-/obj/structure/ship_ammo/cas/rocket/napalm/detonate_on(turf/impact, attackdir = NORTH)
- impact.ceiling_debris_check(3)
- explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range) //relatively weak
- flame_radius(fire_range, impact, 60, 30) //cooking for a long time
- var/datum/effect_system/smoke_spread/phosphorus/warcrime = new
- warcrime.set_up(fire_range + 1, impact, 7)
- warcrime.start()
- qdel(src)
+ devastating_explosion_range = 3
+ heavy_explosion_range = 5
+ light_explosion_range = 7
+ travelling_time = 6 SECONDS
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/monarch
+// High speed missiles are defined by their four second deploy time, solid yield.
-//minirockets
+//The Swansong is the bogstandard missile, it missiles.
+/obj/structure/ship_ammo/cas/rocket/swansong
+ name = "\improper PLGM-50 'Swansong'"
+ desc = "The PLGM-7 'Swansong' is the bogstandard air to ground missile load of the Navy. Named after barely dodging discontinuation dozens of times to more expensive design types. Moving this will require some sort of lifter."
+ icon_state = "swansong"
+ ammo_id = "s"
+ point_cost = 200
+ devastating_explosion_range = 2
+ heavy_explosion_range = 4
+ light_explosion_range = 6
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/swansong
+//Minirockets are effectively just da small rockets.
/obj/structure/ship_ammo/cas/minirocket
name = "mini rocket stack"
desc = "A pack of explosive laser guided mini rockets. Moving this will require some sort of lifter."
@@ -508,6 +544,7 @@
ammo_count = 6
max_ammo_count = 6
ammo_name = "minirocket"
+ firing_voiceline = 'sound/voice/plane_vws/shot_missile.ogg'
travelling_time = 2 SECONDS
transferable_ammo = TRUE
point_cost = 175
@@ -589,6 +626,7 @@
point_cost = 50 // Not a real rocket, so its cheap
travelling_time = 4 SECONDS
cas_effect = /obj/effect/overlay/blinking_laser/flare
+ firing_voiceline = 'sound/voice/plane_vws/shot_flare.ogg'
devastating_explosion_range = 0
heavy_explosion_range = 0
light_explosion_range = 0
@@ -602,3 +640,96 @@
/obj/structure/ship_ammo/cas/minirocket/illumination/proc/drop_cas_flare(turf/impact)
new /obj/effect/temp_visual/above_flare(impact)
+
+// Bombs have a long travel time but are decently numerous, ranging in payloads from 200 to 1000lbs. Higher is bigger.
+/obj/structure/ship_ammo/cas/bomb
+ name = "\improper AOE-200lb 'Tiny' stack"
+ desc = "A decent-sized payload of explosive bombs, will only fit in a full-sized bomb pod. Moving this will require some sort of lifter."
+ icon_state = "bomb_200"
+ icon = 'icons/Marine/mainship_props.dmi'
+ equipment_type = /obj/structure/dropship_equipment/cas/weapon/bomb_pod
+ ammo_count = 8
+ max_ammo_count = 8
+ ammo_name = "bomb_200"
+ firing_voiceline = 'sound/voice/plane_vws/shot_bomb.ogg'
+ travelling_time = 12 SECONDS
+ transferable_ammo = TRUE
+ point_cost = 200 // Bombs are numerous.
+ ammo_type = CAS_BOMB
+ devastating_explosion_range = 0
+ heavy_explosion_range = 3
+ light_explosion_range = 4
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/bomb
+
+
+/obj/structure/ship_ammo/cas/bomb/detonate_on(turf/impact, attackdir = NORTH)
+ impact.ceiling_debris_check(2)
+ explosion(impact, devastating_explosion_range, heavy_explosion_range, light_explosion_range, adminlog = FALSE)//no messaging admin, that'd spam them.
+
+// Four hundos have no real gimmick beyond being a bigger payload.
+/obj/structure/ship_ammo/cas/bomb/fourhundred
+ name = "\improper AOE-400lb 'Mighty' stack"
+ desc = "A decently-sized payload of explosive bombs, will only fit in a full-sized bomb pod. Moving this will require some sort of lifter."
+ icon_state = "bomb_400"
+ equipment_type = /obj/structure/dropship_equipment/cas/weapon/bomb_pod
+ ammo_count = 4
+ max_ammo_count = 4
+ ammo_name = "bomb_400"
+ point_cost = 225 // Bombs are numerous.
+ heavy_explosion_range = 4
+ light_explosion_range = 5
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/bomb
+
+// The mother of all bombs, Jack.
+/obj/structure/ship_ammo/cas/bomb/moab
+ name = "\improper AOE-1000lb 'MOAB' stack"
+ desc = "A incredibly high yield payload bomb used to utterly ruin someone's day, generally termed as the 'Mother of all Bombs'. will only fit in a full-sized bomb pod. Moving this will require some sort of lifter."
+ icon_state = "bomb_1000"
+ ammo_count = 2
+ max_ammo_count = 2
+ devastating_explosion_range = 6
+ heavy_explosion_range = 8
+ light_explosion_range = 0
+ ammo_name = "bomb_1000"
+ travelling_time = 14 SECONDS
+ point_cost = 600 // This is literally a minituare OB.
+ cas_effect = /obj/effect/overlay/blinking_laser/bomb_fat
+
+// Bomblets are small and numerious, with small paylods but high quantity.
+/obj/structure/ship_ammo/cas/bomblet
+ name = "\improper AOE-50lb 'Dandelions' stack"
+ desc = "A large litter of explosive bomblets, will only fit in a bomblet pod. Moving this will require some sort of lifter."
+ icon_state = "bomb_50"
+ icon = 'icons/Marine/mainship_props.dmi'
+ equipment_type = /obj/structure/dropship_equipment/cas/weapon/bomblet_pod
+ ammo_count = 40
+ max_ammo_count = 40
+ ammo_name = "bomb_50"
+ firing_voiceline = 'sound/voice/plane_vws/shot_bomb.ogg'
+ travelling_time = 10 SECONDS
+ transferable_ammo = TRUE
+ point_cost = 150
+ ammo_type = CAS_BOMBLET
+ light_explosion_range = 2
+ heavy_explosion_range = 0
+ prediction_type = CAS_AMMO_EXPLOSIVE
+ cas_effect = /obj/effect/overlay/blinking_laser/bomblet
+
+
+/obj/structure/ship_ammo/cas/bomblet/detonate_on(turf/impact, attackdir = NORTH)
+ impact.ceiling_debris_check(2)
+ explosion(impact, heavy_explosion_range, light_explosion_range, adminlog = FALSE)//no messaging admin, that'd spam them.
+
+/obj/structure/ship_ammo/cas/bomblet/medium
+ name = "\improper AOE-75lb 'Poppies' stack"
+ desc = "A large litter of explosive bomblets. Moving this will require some sort of lifter."
+ icon_state = "bomb_75"
+ ammo_count = 20
+ max_ammo_count = 20
+ ammo_name = "bomb_75"
+ travelling_time = 12 SECONDS
+ point_cost = 175
+ light_explosion_range = 3
+ prediction_type = CAS_AMMO_EXPLOSIVE
diff --git a/code/game/objects/structures/dropship_equipment.dm b/code/game/objects/structures/dropship_equipment.dm
index 918e89b11f420..89de39d69df67 100644
--- a/code/game/objects/structures/dropship_equipment.dm
+++ b/code/game/objects/structures/dropship_equipment.dm
@@ -104,9 +104,11 @@
pixel_y = 32
/obj/effect/attach_point/crew_weapon
- name = "rear attach point"
+ name = "interior attach point"
base_category = DROPSHIP_CREW_WEAPON
density = FALSE
+ layer = HOLOPAD_LAYER //Keeps xenos from hiding under them
+ plane = FLOOR_PLANE //Doesn't layer under weeds unless it has this
/obj/effect/attach_point/crew_weapon/dropship1
ship_tag = SHUTTLE_ALAMO
@@ -323,6 +325,8 @@
/obj/structure/dropship_equipment/shuttle/flare_launcher/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/explosive/grenade/flare) && stored_amount < max_amount)
stored_amount++
user.balloon_alert(user, "You insert a flare, remaining flares [stored_amount].")
@@ -506,6 +510,7 @@
update_icon()
/obj/structure/dropship_equipment/shuttle/weapon_holder/update_icon_state()
+ . = ..()
if(ship_base)
icon_state = deployed_icon_state
else
@@ -518,10 +523,10 @@
/obj/structure/dropship_equipment/shuttle/weapon_holder/machinegun
name = "machinegun deployment system"
- desc = "A box that deploys a modified M56D crewserved machine gun. Fits on the crewserved weapon attach points of dropships. You need a powerloader to lift it."
+ desc = "A box that deploys a modified HSG-102 crewserved machine gun. Fits on the crewserved weapon attach points of dropships. You need a powerloader to lift it."
icon_state = "mg_system"
point_cost = 300
- deployable_type = /obj/item/weapon/gun/tl102/hsg_nest
+ deployable_type = /obj/item/weapon/gun/hsg_102/hsg_nest
/obj/structure/dropship_equipment/shuttle/weapon_holder/minigun
name = "minigun deployment system"
@@ -642,9 +647,12 @@
bound_height = 64
dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE|FIRE_MISSION_ONLY
screen_mode = 1
- COOLDOWN_DECLARE(last_fired) //used for weapon cooldown after use.
+ ///used for weapon cooldown after use
+ COOLDOWN_DECLARE(last_fired)
+ ///primary firing sound on the plane
var/firing_sound
- var/firing_delay = 20 //delay between firing. 2 seconds by default
+ ///delay between firing.
+ var/firing_delay = 2 SECONDS
/obj/structure/dropship_equipment/cas/weapon/update_equipment()
if(ship_base)
@@ -681,13 +689,18 @@
/obj/structure/dropship_equipment/cas/weapon/proc/open_fire(obj/selected_target, attackdir)
var/turf/target_turf = get_turf(selected_target)
if(firing_sound)
- playsound(loc, firing_sound, 70, 1)
+ playsound(loc, firing_sound, 70, TRUE)
var/obj/structure/ship_ammo/SA = ammo_equipped //necessary because we nullify ammo_equipped when firing big rockets
var/ammo_travelling_time = SA.travelling_time //how long the rockets/bullets take to reach the ground target.
var/ammo_warn_sound = SA.warning_sound
deplete_ammo()
COOLDOWN_START(src, last_fired, firing_delay)
+ if((SA.max_ammo_count > 1) && (SA.ammo_count <= 0))
+ playsound(loc, 'sound/voice/plane_vws/ammunition_zero.ogg', 70, FALSE)
+ else if(SA.firing_voiceline)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), loc, SA.firing_voiceline, 80, FALSE), 5)
+
if(ammo_warn_sound)
playsound(target_turf, ammo_warn_sound, 70, 1)
@@ -706,14 +719,15 @@
/obj/structure/dropship_equipment/cas/weapon/heavygun
name = "\improper GAU-21 30mm cannon"
- desc = "A dismounted GAU-21 'Rattler' 30mm rotary cannon. It seems to be missing its feed links and has exposed connection wires. Capable of firing 5200 rounds a minute, feared by many for its power. Earned the nickname 'Rattler' from the vibrations it would cause on dropships in its inital production run. Moving this will require some sort of lifter."
+ desc = "A dismounted GAU-21 'Rattler' 30mm rotary cannon. Capable of firing 5200 rounds a minute, feared by many for its power. Earned the nickname 'Rattler' from the vibrations it would cause on ships in its inital production run. Moving this will require some sort of lifter."
icon_state = "30mm_cannon"
firing_sound = 'sound/weapons/gunship_chaingun.ogg'
point_cost = 300
dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE
ammo_type_used = CAS_30MM
-/obj/structure/dropship_equipment/cas/weapon/heavygun/update_icon()
+/obj/structure/dropship_equipment/cas/weapon/heavygun/update_icon_state()
+ . = ..()
if(ammo_equipped)
icon_state = "30mm_cannon_loaded[ammo_equipped.ammo_count?"1":"0"]"
else
@@ -744,7 +758,8 @@
ammo_equipped = null //nothing left to empty after firing
update_icon()
-/obj/structure/dropship_equipment/cas/weapon/rocket_pod/update_icon()
+/obj/structure/dropship_equipment/cas/weapon/rocket_pod/update_icon_state()
+ . = ..()
if(ammo_equipped?.ammo_count)
icon_state = "rocket_pod_loaded[ammo_equipped.ammo_id]"
else
@@ -764,7 +779,8 @@
point_cost = 450
ammo_type_used = CAS_MINI_ROCKET
-/obj/structure/dropship_equipment/cas/weapon/minirocket_pod/update_icon()
+/obj/structure/dropship_equipment/cas/weapon/minirocket_pod/update_icon_state()
+ . = ..()
if(ammo_equipped?.ammo_count)
icon_state = "minirocket_pod_loaded"
else
@@ -789,7 +805,8 @@
dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE
ammo_type_used = CAS_LASER_BATTERY
-/obj/structure/dropship_equipment/cas/weapon/laser_beam_gun/update_icon()
+/obj/structure/dropship_equipment/cas/weapon/laser_beam_gun/update_icon_state()
+ . = ..()
if(ammo_equipped?.ammo_count)
icon_state = "laser_beam_loaded"
else
@@ -810,7 +827,8 @@
equip_category = DROPSHIP_CREW_WEAPON //fits inside the central spot of the dropship
point_cost = 0
-/obj/structure/dropship_equipment/cas/weapon/launch_bay/update_icon()
+/obj/structure/dropship_equipment/cas/weapon/launch_bay/update_icon_state()
+ . = ..()
if(ammo_equipped?.ammo_count)
icon_state = "launch_bay_loaded"
else
@@ -857,3 +875,43 @@
deployed_table.layer = ABOVE_OBJ_LAYER + 0.01 //make sure its directly ABOVE the layer
deployed_table.loc = loc
icon_state = "table2-idle"
+
+/obj/structure/dropship_equipment/cas/weapon/bomblet_pod
+ name = "bomblet pod"
+ icon_state = "bomblet_pod"
+ desc = "A pnuematic thrower machine capable of up to 40 smaller bombs, generally called 'bomblets'. Moving this will require some sort of lifter."
+ icon = 'icons/Marine/mainship_props64.dmi'
+ firing_sound = 'sound/weapons/gunship_rocketpod.ogg'
+ firing_delay = 0.5 SECONDS
+ point_cost = 450
+ dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE
+ ammo_type_used = CAS_BOMBLET
+
+/obj/structure/dropship_equipment/cas/weapon/bomblet_pod/update_icon_state()
+ . = ..()
+ if(ammo_equipped?.ammo_count)
+ icon_state = "bomblet_pod_loaded"
+ else if(ship_base)
+ icon_state = "bomblet_pod_installed"
+ else
+ icon_state = "bomblet_pod"
+
+/obj/structure/dropship_equipment/cas/weapon/bomb_pod
+ name = "bomb pod"
+ icon_state = "bomb_pod"
+ desc = "A bomb pod capable of launching several large bombs. Moving this will require some sort of lifter."
+ icon = 'icons/Marine/mainship_props64.dmi'
+ firing_sound = 'sound/weapons/gunship_rocketpod.ogg'
+ firing_delay = 2 SECONDS
+ point_cost = 450
+ dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE
+ ammo_type_used = CAS_BOMB
+
+/obj/structure/dropship_equipment/cas/weapon/bomb_pod/update_icon_state()
+ . = ..()
+ if(ammo_equipped?.ammo_count)
+ icon_state = "bomb_pod_loaded"
+ else if(ship_base)
+ icon_state = "bomb_pod_installed"
+ else
+ icon_state = "bomb_pod"
diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm
index 97b19ed104a51..0c76545d36271 100644
--- a/code/game/objects/structures/extinguisher.dm
+++ b/code/game/objects/structures/extinguisher.dm
@@ -30,6 +30,8 @@
/obj/structure/extinguisher_cabinet/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/extinguisher))
if(has_extinguisher || !opened)
@@ -58,12 +60,14 @@
opened = !opened
update_icon()
-/obj/structure/extinguisher_cabinet/update_icon()
- overlays.Cut()
+/obj/structure/extinguisher_cabinet/update_icon_state()
+ . = ..()
icon_state = "[initial(icon_state)][opened]"
+/obj/structure/extinguisher_cabinet/update_overlays()
+ . = ..()
if(opened && has_extinguisher)
- overlays += "extinguishero_[has_extinguisher.sprite_name]"
+ . += "extinguishero_[has_extinguisher.sprite_name]"
/obj/structure/extinguisher_cabinet/mini
starter_extinguisher = /obj/item/tool/extinguisher/mini
diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm
index 9fe779360f734..475bc15bb8bb1 100644
--- a/code/game/objects/structures/fence.dm
+++ b/code/game/objects/structures/fence.dm
@@ -16,6 +16,8 @@
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = list(SMOOTH_GROUP_FENCE)
canSmoothWith = list(SMOOTH_GROUP_FENCE)
+ ///Chance for the fence to break on /init
+ var/chance_to_break = 80 //Defaults to 80%
/obj/structure/fence/ex_act(severity)
switch(severity)
@@ -30,6 +32,8 @@
/obj/structure/fence/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/rods) && obj_integrity < max_integrity)
if(user.skills.getRating(SKILL_CONSTRUCTION) < SKILL_CONSTRUCTION_PLASTEEL)
@@ -71,46 +75,46 @@
else if(cut) //Cut/brokn grilles can't be messed with further than this
return
- else if(istype(I, /obj/item/grab) && get_dist(src, user) < 2)
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
+ if(!iswirecutter(I))
+ return
+ user.visible_message(span_notice("[user] starts cutting through [src] with [I]."),
+ "You start cutting through [src] with [I]")
+ playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD))
+ return
- var/mob/living/M = G.grabbed_thing
- var/state = user.grab_state
- user.drop_held_item()
- switch(state)
- if(GRAB_PASSIVE)
- M.visible_message(span_warning("[user] slams [M] against \the [src]!"))
- M.apply_damage(7, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(10)
- if(GRAB_AGGRESSIVE)
- M.visible_message(span_danger("[user] bashes [M] against \the [src]!"))
- if(prob(50))
- M.Paralyze(2 SECONDS)
- M.apply_damage(10, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(25)
- if(GRAB_NECK)
- M.visible_message(span_danger("[user] crushes [M] against \the [src]!"))
- M.Paralyze(10 SECONDS)
- M.apply_damage(20, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(50)
-
- else if(iswirecutter(I))
- user.visible_message(span_notice("[user] starts cutting through [src] with [I]."),
- "You start cutting through [src] with [I]")
- playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
- if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD))
- return
+ playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
+ user.visible_message(span_notice("[user] cuts through [src] with [I]."),
+ "You cut through [src] with [I]")
+ deconstruct(TRUE)
- playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
- user.visible_message(span_notice("[user] cuts through [src] with [I]."),
- "You cut through [src] with [I]")
- deconstruct(TRUE)
+/obj/structure/fence/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!isliving(grab.grabbed_thing))
+ return
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ var/state = user.grab_state
+ user.drop_held_item()
+ var/damage = (user.skills.getRating(SKILL_CQC) * CQC_SKILL_DAMAGE_MOD)
+ switch(state)
+ if(GRAB_PASSIVE)
+ damage += BASE_OBJ_SLAM_DAMAGE
+ grabbed_mob.visible_message(span_warning("[user] slams [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "slammed", "", "against \the [src]")
+ if(GRAB_AGGRESSIVE)
+ damage += BASE_OBJ_SLAM_DAMAGE * 1.5
+ grabbed_mob.visible_message(span_danger("[user] bashes [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "bashed", "", "against \the [src]")
+ if(prob(50))
+ grabbed_mob.Paralyze(2 SECONDS)
+ if(GRAB_NECK)
+ damage += BASE_OBJ_SLAM_DAMAGE * 2
+ grabbed_mob.visible_message(span_danger("[user] crushes [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "crushed", "", "against \the [src]")
+ grabbed_mob.Paralyze(2 SECONDS)
+ grabbed_mob.apply_damage(damage, blocked = MELEE, updating_health = TRUE)
+ take_damage(damage * 2, BRUTE, MELEE)
+ return TRUE
/obj/structure/fence/deconstruct(disassembled = TRUE)
SHOULD_CALL_PARENT(FALSE)
@@ -123,7 +127,7 @@
/obj/structure/fence/Initialize(mapload, start_dir)
. = ..()
- if(prob(80))
+ if(prob(chance_to_break))
obj_integrity = 0
deconstruct(FALSE)
@@ -137,5 +141,8 @@
/obj/structure/fence/fire_act(exposed_temperature, exposed_volume)
if(exposed_temperature > T0C + 800)
- take_damage(round(exposed_volume / 100), BURN, "fire")
+ take_damage(round(exposed_volume / 100), BURN, FIRE)
return ..()
+
+/obj/structure/fence/broken
+ chance_to_break = 100
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 8967fa3d1759f..9b8e5742d3f2e 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -78,6 +78,8 @@
/obj/structure/flora/tree/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!I.sharp && I.force <= 0)
return
@@ -510,6 +512,8 @@
/obj/structure/flora/jungle/vines/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(I.sharp != IS_SHARP_ITEM_BIG || !isliving(user))
return
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 527d448e3cdd4..e2d948d5e2aa7 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -14,7 +14,7 @@
var/reinforcement = null
var/icon_prefix = "girder"
smoothing_flags = SMOOTH_BITMASK
- canSmoothWith = list(SMOOTH_GROUP_GIRDER,SMOOTH_GROUP_SURVIVAL_TITANIUM_WALLS,)
+ canSmoothWith = list(SMOOTH_GROUP_GIRDER,SMOOTH_GROUP_SURVIVAL_TITANIUM_WALLS)
smoothing_groups = list(SMOOTH_GROUP_GIRDER)
base_icon_state = "girder"
@@ -53,6 +53,8 @@
/obj/structure/girder/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, GIRDER_REINF_METAL) || istype(I, GIRDER_REINF_PLASTEEL))
if(user.do_actions)
return TRUE //no afterattack
@@ -334,6 +336,7 @@
/obj/structure/girder/update_icon_state()
+ . = ..()
switch(girder_state)
if(GIRDER_BROKEN, GIRDER_BROKEN_PATCHED)
icon = 'icons/obj/smooth_objects/girder_broke.dmi'
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index ad149b922b016..dbe4709fcffc5 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -7,7 +7,7 @@
density = TRUE
anchored = TRUE
coverage = 10
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
allow_pass_flags = PASS_AIR|PASS_PROJECTILE|PASS_GRILLE
layer = OBJ_LAYER
resistance_flags = XENO_DAMAGEABLE
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index ffe92ca493949..123739e74ddb5 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -73,6 +73,8 @@
/obj/structure/inflatable/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(can_puncture(I))
visible_message(span_danger("[user] pierces [src] with [I]!"))
deflate(TRUE)
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index 5b1b8fa98006d..45ecbc10a5532 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -34,6 +34,8 @@
/obj/structure/janitorialcart/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/storage/bag/trash) && !mybag)
user.drop_held_item()
diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm
index 5189ccb463c2c..d9c9ef48f4e8f 100644
--- a/code/game/objects/structures/ladders.dm
+++ b/code/game/objects/structures/ladders.dm
@@ -53,6 +53,7 @@
return ..()
/obj/structure/ladder/update_icon_state()
+ . = ..()
if(up && down)
icon_state = "ladder11"
@@ -65,8 +66,8 @@
else //wtf make your ladders properly assholes
icon_state = "ladder00"
-/obj/structure/ladder/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- return attack_hand(X)
+/obj/structure/ladder/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ return attack_hand(xeno_attacker)
/obj/structure/ladder/attack_larva(mob/living/carbon/xenomorph/larva/X)
return attack_hand(X)
@@ -209,6 +210,8 @@
//Throwing Shiet
/obj/structure/ladder/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/explosive/grenade))
var/obj/item/explosive/grenade/G = I
diff --git a/code/game/objects/structures/lamarr_cage.dm b/code/game/objects/structures/lamarr_cage.dm
index c3d25dadd31f4..3e83aed557759 100644
--- a/code/game/objects/structures/lamarr_cage.dm
+++ b/code/game/objects/structures/lamarr_cage.dm
@@ -55,5 +55,5 @@
stat = DEAD
-/obj/item/clothing/mask/facehugger/lamarr/update_icon()
+/obj/item/clothing/mask/facehugger/lamarr/update_icon_state()
return
diff --git a/code/game/objects/structures/mine_structures.dm b/code/game/objects/structures/mine_structures.dm
index 343799e5ec4e3..b8c020005e916 100644
--- a/code/game/objects/structures/mine_structures.dm
+++ b/code/game/objects/structures/mine_structures.dm
@@ -17,10 +17,10 @@
density = TRUE
/obj/structure/mine_structure/wooden/flamer_fire_act(burnlevel)
- take_damage(burnlevel, BURN, "fire")
+ take_damage(burnlevel, BURN, FIRE)
/obj/structure/mine_structure/wooden/fire_act()
- take_damage(25, BURN, "fire")
+ take_damage(25, BURN, FIRE)
/obj/structure/mine_structure/wooden/support_wall
name = "wooden support"
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index d3681918b2e7d..6c994d67dbfc7 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -75,7 +75,8 @@
update_icon()
addtimer(VARSET_CALLBACK(src, switching_states, FALSE), 1 SECONDS)
-/obj/structure/mineral_door/update_icon()
+/obj/structure/mineral_door/update_icon_state()
+ . = ..()
if(open)
icon_state = "[base_icon_state][smoothing_flags ? "-[smoothing_junction]" : ""]-open"
else
@@ -84,13 +85,15 @@
/obj/structure/mineral_door/attackby(obj/item/W, mob/living/user)
. = ..()
+ if(.)
+ return
if(QDELETED(src))
return
var/multiplier = 1
- if(istype(W, /obj/item/tool/pickaxe/plasmacutter) && !user.do_actions)
+ if(isplasmacutter(W) && !user.do_actions)
var/obj/item/tool/pickaxe/plasmacutter/P = W
- if(P.start_cut(user, src.name, src, PLASMACUTTER_BASE_COST * PLASMACUTTER_VLOW_MOD))
+ if(P.start_cut(user, src.name, src, PLASMACUTTER_BASE_COST * PLASMACUTTER_VLOW_MOD, no_string = TRUE))
if(istype(src, /obj/structure/mineral_door/resin))
multiplier += PLASMACUTTER_RESIN_MULTIPLIER //Plasma cutters are particularly good at destroying resin structures.
else
@@ -117,24 +120,28 @@
name = "silver door"
material_type = /obj/item/stack/sheet/mineral/silver
base_icon_state = "silver"
+ icon_state = "silver"
max_integrity = 500
/obj/structure/mineral_door/gold
name = "gold door"
material_type = /obj/item/stack/sheet/mineral/gold
base_icon_state = "gold"
+ icon_state = "gold"
max_integrity = 250
/obj/structure/mineral_door/uranium
name = "uranium door"
material_type = /obj/item/stack/sheet/mineral/uranium
base_icon_state = "uranium"
+ icon_state = "uranium"
max_integrity = 500
/obj/structure/mineral_door/sandstone
name = "sandstone door"
material_type = /obj/item/stack/sheet/mineral/sandstone
base_icon_state = "sandstone"
+ icon_state = "sandstone"
max_integrity = 100
/obj/structure/mineral_door/transparent
@@ -150,6 +157,7 @@
name = "phoron door"
material_type = /obj/item/stack/sheet/mineral/phoron
base_icon_state = "phoron"
+ icon_state = "phoron"
max_integrity = 250
/obj/structure/mineral_door/transparent/phoron/attackby(obj/item/W as obj, mob/user as mob)
@@ -172,6 +180,7 @@
name = "diamond door"
material_type = /obj/item/stack/sheet/mineral/diamond
base_icon_state = "diamond"
+ icon_state = "diamond"
max_integrity = 1000
@@ -179,6 +188,7 @@
name = "wooden door"
material_type = /obj/item/stack/sheet/wood
base_icon_state = "wood"
+ icon_state = "wood"
trigger_sound = 'sound/effects/doorcreaky.ogg'
max_integrity = 100
diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm
index 2479de87a51c2..e51e78fd16b4c 100644
--- a/code/game/objects/structures/misc.dm
+++ b/code/game/objects/structures/misc.dm
@@ -73,6 +73,8 @@
/obj/structure/mopbucket/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/mop))
if(reagents.total_volume < 1)
@@ -382,7 +384,7 @@
/obj/structure/cryopods
name = "hypersleep chamber"
icon = 'icons/obj/machines/cryogenics.dmi'
- icon_state = "body_scanner_0"
+ icon_state = "body_scanner"
desc = "A large automated capsule with LED displays intended to put anyone inside into 'hypersleep'."
density = TRUE
anchored = TRUE
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 10bd407fd3dc5..7c52734fc2517 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -23,7 +23,8 @@
QDEL_NULL(connected)
return ..()
-/obj/structure/morgue/update_icon()
+/obj/structure/morgue/update_icon_state()
+ . = ..()
if (morgue_open)
icon_state = "[morgue_type]0"
else
@@ -87,6 +88,8 @@
/obj/structure/morgue/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/pen))
var/t = copytext(stripped_input(user, "What would you like the label to be?", name, null), 1, MAX_MESSAGE_LEN)
@@ -181,11 +184,9 @@
/obj/structure/morgue/crematorium/update_icon()
+ . = ..()
if(cremating)
icon_state = "[morgue_type]_active"
- else
- ..()
-
/obj/structure/morgue/crematorium/proc/cremate(mob/user)
set waitfor = 0
diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm
index 366fd419017c9..071d535e9bad0 100644
--- a/code/game/objects/structures/noticeboard.dm
+++ b/code/game/objects/structures/noticeboard.dm
@@ -19,6 +19,8 @@
//attaching papers!!
/obj/structure/noticeboard/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
if(notices >= 5)
diff --git a/code/game/objects/structures/orbital_cannon.dm b/code/game/objects/structures/orbital_cannon.dm
index 2cb104172289a..32e9a3f52e819 100644
--- a/code/game/objects/structures/orbital_cannon.dm
+++ b/code/game/objects/structures/orbital_cannon.dm
@@ -45,6 +45,7 @@
return ..()
/obj/structure/orbital_cannon/update_icon_state()
+ . = ..()
if(chambered_tray)
icon_state = "OBC_chambered"
return
@@ -171,6 +172,13 @@
/// Handles the playing of the Orbital Bombardment incoming sound and other visual and auditory effects of the cannon, usually a spiraling whistle noise but can be overridden.
/obj/structure/orbital_cannon/proc/handle_ob_firing_effects(target, ob_sound = 'sound/effects/OB_incoming.ogg')
flick("OBC_firing",src)
+ for(var/mob/living/current_mob AS in GLOB.mob_living_list)
+ if(!current_mob || !is_mainship_level(current_mob.z))
+ continue
+ if(get_dist(src, current_mob) > 20)
+ current_mob.playsound_local(current_mob, 'sound/effects/obalarm.ogg', 25)
+ shake_camera(current_mob, 0.7 SECONDS)
+ to_chat(current_mob, span_warning("The deck of the [SSmapping.configs[SHIP_MAP].map_name] shudders as her orbital cannon opens fire."))
playsound(loc, 'sound/effects/obfire.ogg', 100, FALSE, 20, 4)
for(var/mob/M AS in hearers(WARHEAD_FALLING_SOUND_RANGE, target))
M.playsound_local(target, ob_sound, falloff = 2)
@@ -200,11 +208,23 @@
if("plasma")
inaccurate_fuel = abs(GLOB.marine_main_ship?.ob_type_fuel_requirements[4] - tray.fuel_amt)
- var/turf/target = locate(T.x + inaccurate_fuel * pick(-1,1),T.y + inaccurate_fuel * pick(-1,1),T.z)
+ // Give marines a warning if misfuelled.
+ var/fuel_warning = "Warhead fuel level: safe."
+ if(inaccurate_fuel > 0)
+ fuel_warning = "Warhead fuel level: incorrect. Warhead may be inaccurate."
- playsound_z_humans(target.z, 'sound/effects/OB_warning_announce.ogg', 100) //for marines on ground
+ var/turf/target = locate(T.x + inaccurate_fuel * pick(-1,1),T.y + inaccurate_fuel * pick(-1,1),T.z)
+ GLOB.round_statistics.obs_fired++
+ SSblackbox.record_feedback("tally", "round_statistics", 1, "obs_fired")
+ priority_announce(
+ message = "Get out of danger close!
Warhead type: [tray.warhead.warhead_kind]. [fuel_warning] Estimated location of impact: [get_area(T)].",
+ title = "Orbital bombardment launch command detected!",
+ type = ANNOUNCEMENT_PRIORITY,
+ sound = 'sound/effects/OB_warning_announce.ogg',
+ channel_override = SSsounds.random_available_channel(), // This way, we can't have it be cut off by other sounds.
+ color_override = "red"
+ )
playsound(target, 'sound/effects/OB_warning_announce_novoiceover.ogg', 125, FALSE, 30, 10) //VOX-less version for xenomorphs
- playsound_z(z, 'sound/effects/OB_warning_announce.ogg', 100) //for the ship
var/impact_time = 10 SECONDS + (WARHEAD_FLY_TIME * (GLOB.current_orbit/3))
@@ -327,7 +347,7 @@
. += "Moving this will require some sort of lifter."
-/obj/structure/ob_ammo/obj_destruction(damage_amount, damage_type, damage_flag)
+/obj/structure/ob_ammo/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
explosion(loc, light_impact_range = 2, flash_range = 3, flame_range = 2)
return ..()
@@ -363,7 +383,7 @@
/obj/structure/ob_ammo/warhead/incendiary/warhead_impact(turf/target, inaccuracy_amt = 0)
. = ..()
var/range_num = max(15 - inaccuracy_amt, 12)
- flame_radius(range_num, target, burn_intensity = 36, burn_duration = 40, colour = "blue")
+ flame_radius(range_num, target, burn_intensity = 46, burn_duration = 40, colour = "blue")
var/datum/effect_system/smoke_spread/phosphorus/warcrime = new
warcrime.set_up(17, target, 20)
warcrime.start()
@@ -385,7 +405,7 @@
var/total_amt = max(25 - inaccuracy_amt, 20)
for(var/i = 1 to total_amt)
var/turf/U = pick_n_take(turf_list)
- explosion(U, 1, 4, 6, 0, 6, throw_range = 0, adminlog = FALSE) //rocket barrage
+ explosion(U, 2, 4, 6, 0, 6, throw_range = 0, adminlog = FALSE) //rocket barrage
sleep(0.1 SECONDS)
*/
@@ -399,7 +419,7 @@
/obj/structure/ob_ammo/warhead/plasmaloss/warhead_impact(turf/target, inaccuracy_amt = 0)
. = ..()
var/datum/effect_system/smoke_spread/plasmaloss/smoke = new
- smoke.set_up(25, target, 3 SECONDS)//Vape nation
+ smoke.set_up(25, target, 30 - (inaccuracy_amt * 2))//Vape nation
smoke.start()
*/
@@ -423,7 +443,7 @@
icon_state = "ob_console"
screen_overlay = "ob_console_screen"
dir = WEST
- flags_atom = ON_BORDER|CONDUCT
+ atom_flags = ON_BORDER|CONDUCT
var/orbital_window_page = 0
/obj/machinery/computer/orbital_cannon_console/Initialize(mapload)
diff --git a/code/game/objects/structures/patrol_points.dm b/code/game/objects/structures/patrol_points.dm
index 9841d4e610d53..07dc1a7df3d33 100644
--- a/code/game/objects/structures/patrol_points.dm
+++ b/code/game/objects/structures/patrol_points.dm
@@ -1,6 +1,10 @@
+#define PATROL_POINT_RAPPEL_EFFECT "patrol_point_rappel_effect"
+#define RAPPEL_DURATION 0.6 SECONDS
+#define RAPPEL_HEIGHT 128
+
/obj/structure/patrol_point
name = "Patrol start point"
- desc = "A one way ticket to the combat zone."
+ desc = "A one way ticket to the combat zone. Shift click to deploy when inside a mech."
icon = 'icons/effects/effects.dmi'
icon_state = "patrolpoint"
anchored = TRUE
@@ -66,8 +70,22 @@
span_notice("You walk through the [src]."))
user.trainteleport(linked_point.loc)
add_spawn_protection(user)
+ if(!obj_mover)
+ new /atom/movable/effect/rappel_rope(linked_point.loc) //mechs don't need a rope
+
+ var/atom/movable/mover = obj_mover ? obj_mover : user
+
+ mover.add_filter(PATROL_POINT_RAPPEL_EFFECT, 2, drop_shadow_filter(y = -RAPPEL_HEIGHT, color = COLOR_TRANSPARENT_SHADOW, size = 4))
+ var/shadow_filter = mover.get_filter(PATROL_POINT_RAPPEL_EFFECT)
- new /atom/movable/effect/rappel_rope(linked_point.loc)
+ var/current_layer = mover.layer
+ mover.pixel_y += RAPPEL_HEIGHT
+ mover.layer = FLY_LAYER
+
+ animate(mover, pixel_y = mover.pixel_y - RAPPEL_HEIGHT, time = RAPPEL_DURATION)
+ animate(shadow_filter, y = 0, size = 0.9, time = RAPPEL_DURATION, flags = ANIMATION_PARALLEL)
+
+ addtimer(CALLBACK(src, PROC_REF(end_rappel), user, mover, current_layer), RAPPEL_DURATION)
if(!user)
return
@@ -111,10 +129,21 @@
user.forceMove(linked_point.loc)
///Temporarily applies godmode to prevent spawn camping
-/obj/structure/patrol_point/proc/add_spawn_protection(mob/user)
+/obj/structure/patrol_point/proc/add_spawn_protection(mob/living/user)
+ user.ImmobilizeNoChain(RAPPEL_DURATION) //looks weird if they can move while rappeling
user.status_flags |= GODMODE
addtimer(CALLBACK(src, PROC_REF(remove_spawn_protection), user), 10 SECONDS)
+///Ends the rappel effects
+/obj/structure/patrol_point/proc/end_rappel(mob/living/user, atom/movable/mover, original_layer)
+ mover.remove_filter(PATROL_POINT_RAPPEL_EFFECT)
+ mover.layer = original_layer
+ SEND_SIGNAL(mover, COMSIG_MOVABLE_PATROL_DEPLOYED, TRUE, 1.5, 2)
+ if(ismecha(mover))
+ new /obj/effect/temp_visual/rappel_dust(linked_point.loc, 3)
+ playsound(linked_point.loc, 'sound/effects/behemoth/behemoth_stomp.ogg', 40, TRUE)
+ shake_camera(user, 0.2 SECONDS, 0.5)
+
///Removes spawn protection godmode
/obj/structure/patrol_point/proc/remove_spawn_protection(mob/user)
user.status_flags &= ~GODMODE
diff --git a/code/game/objects/structures/platforms.dm b/code/game/objects/structures/platforms.dm
index 670b23a7d8a36..4cd05b6e94c2c 100644
--- a/code/game/objects/structures/platforms.dm
+++ b/code/game/objects/structures/platforms.dm
@@ -6,7 +6,7 @@
coverage = 10
density = TRUE
layer = BELOW_OBJ_LAYER
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
resistance_flags = RESIST_ALL
interaction_flags = INTERACT_CHECK_INCAPACITATED
allow_pass_flags = PASS_LOW_STRUCTURE|PASSABLE|PASS_WALKOVER
@@ -75,6 +75,11 @@
new_overlay.pixel_x = -32
. += new_overlay
+/obj/structure/platform/nondense
+ density = FALSE
+ climbable = FALSE
+ coverage = 0
+
/obj/structure/platform/rockcliff
icon_state = "rockcliff"
name = "rock cliff"
@@ -83,6 +88,11 @@
/obj/structure/platform/rockcliff/icycliff
icon_state = "icerock"
+/obj/structure/platform/rockcliff/icycliff/nondense
+ density = FALSE
+ climbable = FALSE
+ coverage = 0
+
/obj/structure/platform/metalplatform
icon_state = "metalplatform"
@@ -102,7 +112,7 @@
desc = "A square metal surface resting on four legs."
icon = 'icons/obj/structures/platforms.dmi'
icon_state = "platform_deco"
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
resistance_flags = RESIST_ALL
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
diff --git a/code/game/objects/structures/prop.dm b/code/game/objects/structures/prop.dm
index ec19cdda3760c..c9ab75560fc11 100644
--- a/code/game/objects/structures/prop.dm
+++ b/code/game/objects/structures/prop.dm
@@ -75,6 +75,7 @@
set_light(initial(light_range))
/obj/machinery/prop/computer/update_icon_state()
+ . = ..()
if(machine_stat & (BROKEN|DISABLED))
icon_state = "[initial(icon_state)]_broken"
else
@@ -331,8 +332,7 @@
fallen_list += D.fallen_names
qdel(D)
return TRUE
- else
- . = ..()
+ return ..()
/obj/structure/prop/mainship/ship_memorial/examine(mob/user)
. = ..()
@@ -1094,7 +1094,7 @@
///BROKEN VEHICLE PROPS
/obj/structure/prop/vehicle
- layer = TANK_BARREL_LAYER
+ layer = ABOVE_MOB_PROP_LAYER
/obj/structure/prop/vehicle/van
name = "van"
desc = "An old van, seems to be broken down."
@@ -1242,7 +1242,7 @@
/obj/structure/prop/vehicle/tank/east/barrel
icon_state = "ltb_cannon_0"
- layer = TANK_BARREL_LAYER
+ layer = ABOVE_MOB_PROP_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/obj/structure/prop/vehicle/tank/east/barrel/broken
@@ -1326,10 +1326,10 @@
icon_state = "glauncher_0"
/obj/structure/prop/vehicle/tank/east/decoration/cupolaone
- icon_state = "m56cupola_1"
+ icon_state = "hsg102cupola_1"
/obj/structure/prop/vehicle/tank/east/decoration/cupolazero
- icon_state = "m56cupola_0"
+ icon_state = "hsg102cupola_0"
/obj/structure/prop/vehicle/tank/east/decoration/towlauncherone
icon_state = "towlauncher_1"
@@ -1453,10 +1453,10 @@
icon_state = "glauncher_0"
/obj/structure/prop/vehicle/tank/north/decoration/cupolaone
- icon_state = "m56cupola_1"
+ icon_state = "hsg102cupola_1"
/obj/structure/prop/vehicle/tank/north/decoration/cupolazero
- icon_state = "m56cupola_0"
+ icon_state = "hsg102cupola_0"
/obj/structure/prop/vehicle/tank/north/decoration/towlauncherone
icon_state = "towlauncher_1"
diff --git a/code/game/objects/structures/razorwire.dm b/code/game/objects/structures/razorwire.dm
index 3a409db9717f1..a837bbc24e3cc 100644
--- a/code/game/objects/structures/razorwire.dm
+++ b/code/game/objects/structures/razorwire.dm
@@ -125,6 +125,8 @@
/obj/structure/razorwire/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/metal_sheets = I
@@ -142,33 +144,28 @@
update_icon()
return
- if(!istype(I, /obj/item/grab))
- return
- if(isxeno(user))//I am very tempted to remove this >:)
+/obj/structure/razorwire/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!isliving(grab.grabbed_thing))
return
-
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
+ if(user.grab_state < GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
return
- var/mob/living/M = G.grabbed_thing
- if(user.a_intent == INTENT_HARM)
- if(user.grab_state <= GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
-
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(user.a_intent == INTENT_HARM && user.grab_state > GRAB_AGGRESSIVE)
var/def_zone = ran_zone()
- M.apply_damage(RAZORWIRE_BASE_DAMAGE, BRUTE, def_zone, MELEE, TRUE, updating_health = TRUE)
- user.visible_message(span_danger("[user] spartas [M]'s into [src]!"),
- span_danger("You sparta [M]'s against [src]!"))
- log_combat(user, M, "spartaed", "", "against \the [src]")
+ grabbed_mob.apply_damage(RAZORWIRE_BASE_DAMAGE, BRUTE, def_zone, MELEE, TRUE, updating_health = TRUE)
+ user.visible_message(span_danger("[user] spartas [grabbed_mob]'s into [src]!"),
+ span_danger("You sparta [grabbed_mob]'s against [src]!"))
+ log_combat(user, grabbed_mob, "spartaed", "", "against \the [src]")
playsound(src, 'sound/effects/barbed_wire_movement.ogg', 25, 1)
+ return TRUE
- else if(user.grab_state >= GRAB_AGGRESSIVE)
- M.forceMove(loc)
- M.Paralyze(10 SECONDS)
- user.visible_message(span_danger("[user] throws [M] on [src]."),
- span_danger("You throw [M] on [src]."))
+ grabbed_mob.forceMove(loc)
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.visible_message(span_danger("[user] throws [grabbed_mob] on [src]."),
+ span_danger("You throw [grabbed_mob] on [src]."))
+ return TRUE
/obj/structure/razorwire/wirecutter_act(mob/living/user, obj/item/I)
user.visible_message(span_notice("[user] starts disassembling [src]."),
@@ -184,11 +181,11 @@
deconstruct(TRUE)
return TRUE
-/obj/structure/razorwire/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/razorwire/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- X.apply_damage(RAZORWIRE_BASE_DAMAGE, blocked = MELEE, updating_health = TRUE) //About a third as damaging as actually entering
+ xeno_attacker.apply_damage(RAZORWIRE_BASE_DAMAGE, blocked = MELEE, updating_health = TRUE) //About a third as damaging as actually entering
update_icon()
return ..()
@@ -214,6 +211,7 @@
return ..()
/obj/structure/razorwire/update_icon_state()
+ . = ..()
var/health_percent = round(obj_integrity/max_integrity * 100)
var/remaining = CEILING(health_percent, 25)
icon_state = "[base_icon_state]_[remaining]"
diff --git a/code/game/objects/structures/reagent_dispensers.dm b/code/game/objects/structures/reagent_dispensers.dm
index 698bd0300e3b9..426cd7101abc9 100644
--- a/code/game/objects/structures/reagent_dispensers.dm
+++ b/code/game/objects/structures/reagent_dispensers.dm
@@ -143,6 +143,8 @@
/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/assembly_holder))
return
@@ -238,13 +240,13 @@
exploding = TRUE
if(reagents.total_volume > 500)
- flame_radius(5, loc, 46, 40, 31, 30, colour = "blue")
+ flame_radius(5, loc, 40, 46, 31, 30, colour = "blue")
explosion(loc, light_impact_range = 5)
else if(reagents.total_volume > 100)
- flame_radius(4, loc, 46, 40, 31, 30, colour = "blue")
+ flame_radius(4, loc, 40, 46, 31, 30, colour = "blue")
explosion(loc, light_impact_range = 4)
else
- flame_radius(3, loc, 46, 40, 31, 30, colour = "blue")
+ flame_radius(3, loc, 40, 46, 31, 30, colour = "blue")
explosion(loc, light_impact_range = 3)
qdel(src)
diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm
index dc1a780521454..4069b3d0d1d80 100644
--- a/code/game/objects/structures/safe.dm
+++ b/code/game/objects/structures/safe.dm
@@ -96,6 +96,7 @@ FLOOR SAFES
/obj/structure/safe/update_icon_state()
+ . = ..()
if(open)
icon_state = "[initial(icon_state)]-open"
else
@@ -177,6 +178,8 @@ FLOOR SAFES
/obj/structure/safe/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!open)
return
diff --git a/code/game/objects/structures/sensor_tower.dm b/code/game/objects/structures/sensor_tower.dm
index 351b017ff7723..84a233b893faf 100644
--- a/code/game/objects/structures/sensor_tower.dm
+++ b/code/game/objects/structures/sensor_tower.dm
@@ -36,6 +36,7 @@
update_icon()
/obj/structure/sensor_tower/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(current_timer || activated)
icon_state += "_tgmc"
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index b35fc93b94ac3..781e628df9776 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -28,6 +28,8 @@
/obj/structure/sign/attackby(obj/item/I, mob/user, params) //deconstruction
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && !istype(src, /obj/structure/sign/double))
to_chat(user, "You unfasten the sign with your [I].")
@@ -47,6 +49,8 @@
/obj/item/sign/attackby(obj/item/I, mob/user, params) //construction
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && isturf(user.loc))
var/direction = tgui_input_list(user, "In which direction?", "Select direction.", list("North", "East", "South", "West"))
diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
index 8e3809224d3df..f3f1a2eb1c2aa 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -38,6 +38,7 @@
icon_state = "bunkbed"
/obj/structure/bed/update_icon_state()
+ . = ..()
if(!base_bed_icon)
return
if(LAZYLEN(buckled_mobs) || buckled_bodybag)
@@ -172,6 +173,8 @@
/obj/structure/bed/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
if(!buildstacktype)
@@ -182,15 +185,18 @@
new buildstacktype(loc, buildstackamount)
qdel(src)
- else if(istype(I, /obj/item/grab) && !LAZYLEN(buckled_mobs) && !buckled_bodybag)
- var/obj/item/grab/G = I
- if(!ismob(G.grabbed_thing))
- return
-
- var/mob/M = G.grabbed_thing
- to_chat(user, span_notice("You place [M] on [src]."))
- M.forceMove(loc)
- return TRUE
+/obj/structure/bed/grab_interact(obj/item/grab/grab, mob/user, base_damage = 5, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ return
+ if(LAZYLEN(buckled_mobs) || buckled_bodybag)
+ return
+ if(!ismob(grab.grabbed_thing))
+ return
+ var/mob/grabbed_mob = grab.grabbed_thing
+ to_chat(user, span_notice("You place [grabbed_mob] on [src]."))
+ grabbed_mob.forceMove(loc)
+ return TRUE
/obj/structure/bed/alien
icon_state = "abed"
@@ -240,6 +246,8 @@
/obj/item/roller/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/roller_holder) && rollertype == /obj/structure/bed/roller)
var/obj/item/roller_holder/RH = I
@@ -295,7 +303,7 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
/obj/structure/bed/medevac_stretcher
name = "medevac stretcher"
- desc = "A medevac stretcher with integrated beacon for rapid evacuation of an injured patient via dropship lift and an emergency bluespace teleporter for tele-evacuation to a linked beacon. Accepts patients and body bags."
+ desc = "A medevac stretcher with integrated beacon for rapid evacuation of an injured patient via dropship lift and an emergency bluespace teleporter for tele-evacuation to a linked beacon. Accepts patients and body bags. Right click to activate."
icon = 'icons/obj/rollerbed.dmi'
icon_state = "stretcher_down"
buckling_y = 6
@@ -316,13 +324,13 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
. = ..()
radio = new(src)
-/obj/structure/bed/medevac_stretcher/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/bed/medevac_stretcher/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(buckled_bodybag)
unbuckle_bodybag()
for(var/m in buckled_mobs)
- user_unbuckle_mob(m, X, TRUE)
+ user_unbuckle_mob(m, xeno_attacker, TRUE)
/obj/structure/bed/medevac_stretcher/attack_ghost(mob/dead/observer/user)
. = ..()
@@ -336,24 +344,14 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
linked_beacon.remove_stretcher(src)
return ..()
-/obj/structure/bed/medevac_stretcher/update_icon()
- ..()
- overlays.Cut()
+/obj/structure/bed/medevac_stretcher/update_overlays()
+ . = ..()
+
if(stretcher_activated)
- overlays += image("beacon_active_[density ? "up":"down"]")
+ . += image("beacon_active_[density ? "up":"down"]")
if(LAZYLEN(buckled_mobs) || buckled_bodybag)
- overlays += image("icon_state"="stretcher_box","layer"=LYING_MOB_LAYER + 0.1)
-
-
-/obj/structure/bed/medevac_stretcher/verb/activate_medevac_displacer()
- set name = "Activate Medevac Displacement Field"
- set desc = "Teleport the occupant of the stretcher to a linked beacon."
- set category = "Object"
- set src in oview(1)
-
- activate_medevac_teleport(usr)
-
+ . += image("icon_state"="stretcher_box","layer"=LYING_MOB_LAYER + 0.1)
/obj/structure/bed/medevac_stretcher/attack_hand_alternate(mob/living/user)
activate_medevac_teleport(user)
@@ -508,7 +506,7 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
/obj/item/roller/medevac
name = "medevac stretcher"
- desc = "A collapsed medevac stretcher that can be carried around."
+ desc = "A collapsed medevac stretcher that can be carried around. Can be used to instantly transport a marine to a linked beacon. Don't forget the beacon!"
icon_state = "stretcher_folded"
var/last_teleport = null
var/obj/item/medevac_beacon/linked_beacon = null
@@ -575,6 +573,8 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
/obj/item/roller/medevac/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/medevac_beacon))
var/obj/item/medevac_beacon/B = I
@@ -691,6 +691,8 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
/obj/item/medevac_beacon/attackby(obj/item/I, mob/user, params) //Corpsmen can lock their beacons.
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
if(!allowed(user))
diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
index 271c32652297f..d93d55b0ed9f9 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
@@ -1,6 +1,16 @@
-#define DROPSHIP_CHAIR_UNFOLDED 1
-#define DROPSHIP_CHAIR_FOLDED 2
-#define DROPSHIP_CHAIR_BROKEN 3
+#define DROPSHIP_CHAIR_UNBUCKLED ""
+#define DROPSHIP_CHAIR_FOLDED 0
+#define DROPSHIP_CHAIR_BUCKLED "_buckled"
+#define DROPSHIP_CHAIR_BROKEN "_broken"
+
+#define LEADER_CHAIR 0
+
+#define NO_CHAIR_COLOR ""
+#define ALPHA_CHAIR "_alpha"
+#define BRAVO_CHAIR "_bravo"
+#define CHARLIE_CHAIR "_charlie"
+#define DELTA_CHAIR "_delta"
+#define FC_CHAIR "_fc"
/obj/structure/bed/chair //YES, chairs are a type of bed, which are a type of stool. This works, believe me. -Pete
name = "chair"
@@ -82,6 +92,8 @@
/obj/structure/bed/chair/reinforced/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
to_chat(user, span_warning("You can only deconstruct this by welding it down!"))
@@ -95,7 +107,7 @@
user.visible_message(span_notice("[user] fumbles around figuring out how to weld down \the [src]."),
span_notice("You fumble around figuring out how to weld down \the [src]."))
var/fumbling_time = 5 SECONDS * (SKILL_ENGINEER_METAL - user.skills.getRating(SKILL_ENGINEER))
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return
if(!WT.remove_fuel(0, user))
@@ -260,9 +272,34 @@
icon_state = "officechair_dark"
anchored = FALSE
+/obj/structure/bed/chair/dropship
+ name = "dropship chair"
+ desc = "Holds you in place during high altitude drops."
+ icon_state = "shuttle_chair"
+ /// Handles the chair buckle bars overlay
+ var/image/chairbar = null
+ buildstacktype = 0
+ /// Handles the current state of the chair (buckled, unbuckled, folded, broke)
+ var/chair_state = DROPSHIP_CHAIR_UNBUCKLED
+
+/obj/structure/bed/chair/dropship/update_overlays()
+ . = ..()
+ if(chair_state == DROPSHIP_CHAIR_BUCKLED)
+ . += image('icons/obj/objects.dmi', icon_state = "shuttle_bars", layer = ABOVE_MOB_LAYER)
+ return
+
+/obj/structure/bed/chair/dropship/doublewide/post_buckle_mob(mob/buckling_mob)
+ chair_state = DROPSHIP_CHAIR_BUCKLED
+ update_icon()
+ return ..()
+
+/obj/structure/bed/chair/dropship/doublewide/post_unbuckle_mob(mob/buckled_mob)
+ chair_state = DROPSHIP_CHAIR_UNBUCKLED
+ update_icon()
+ return ..()
+
/obj/structure/bed/chair/dropship/pilot
icon_state = "pilot_chair"
- anchored = TRUE
name = "pilot's chair"
desc = "A specially designed chair for pilots to sit in."
@@ -271,47 +308,24 @@
/obj/structure/bed/chair/dropship/passenger
name = "passenger seat"
- desc = "Holds you in place during high altitude drops."
- icon_state = "shuttle_chair"
- var/image/chairbar = null
- var/chair_state = DROPSHIP_CHAIR_UNFOLDED
- buildstacktype = 0
resistance_flags = RESIST_ALL
var/is_animating = 0
/obj/structure/bed/chair/dropship/passenger/CanAllowThrough(atom/movable/mover, turf/target, height = 0, air_group = 0)
- if(chair_state == DROPSHIP_CHAIR_UNFOLDED && istype(mover, /obj/vehicle/multitile) && !is_animating)
+ if(chair_state == DROPSHIP_CHAIR_UNBUCKLED && istype(mover, /obj/vehicle/sealed) && !is_animating)
visible_message(span_danger("[mover] slams into [src] and breaks it!"))
INVOKE_ASYNC(src, PROC_REF(fold_down), TRUE)
return FALSE
return ..()
-/obj/structure/bed/chair/dropship/passenger/Initialize(mapload)
- . = ..()
- chairbar = image("icons/obj/objects.dmi", "shuttle_bars")
- chairbar.layer = ABOVE_MOB_LAYER
-
-
-/obj/structure/bed/chair/dropship/passenger/post_buckle_mob(mob/buckling_mob)
- icon_state = "shuttle_chair_buckled"
- overlays += chairbar
- return ..()
-
-
-/obj/structure/bed/chair/dropship/passenger/post_unbuckle_mob(mob/buckled_mob)
- icon_state = "shuttle_chair"
- overlays -= chairbar
- return ..()
-
-
/obj/structure/bed/chair/dropship/passenger/buckle_mob(mob/living/buckling_mob, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0, silent)
- if(chair_state != DROPSHIP_CHAIR_UNFOLDED)
+ if(chair_state != DROPSHIP_CHAIR_UNBUCKLED)
return FALSE
return ..()
/obj/structure/bed/chair/dropship/passenger/proc/fold_down(break_it = FALSE)
- if(chair_state == DROPSHIP_CHAIR_UNFOLDED)
+ if(chair_state == DROPSHIP_CHAIR_UNBUCKLED)
is_animating = 1
flick("shuttle_chair_new_folding", src)
is_animating = 0
@@ -330,7 +344,7 @@
is_animating = 1
flick("shuttle_chair_new_unfolding", src)
is_animating = 0
- chair_state = DROPSHIP_CHAIR_UNFOLDED
+ chair_state = DROPSHIP_CHAIR_UNBUCKLED
sleep(0.5 SECONDS)
icon_state = "shuttle_chair"
@@ -338,20 +352,22 @@
return // no
-/obj/structure/bed/chair/dropship/passenger/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/bed/chair/dropship/passenger/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
if(chair_state != DROPSHIP_CHAIR_BROKEN)
- X.visible_message(span_warning("[X] smashes \the [src], shearing the bolts!"),
+ xeno_attacker.visible_message(span_warning("[xeno_attacker] smashes \the [src], shearing the bolts!"),
span_warning("We smash \the [src], shearing the bolts!"))
fold_down(1)
/obj/structure/bed/chair/dropship/passenger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
switch(chair_state)
- if(DROPSHIP_CHAIR_UNFOLDED)
+ if(DROPSHIP_CHAIR_UNBUCKLED)
user.visible_message(span_warning("[user] begins loosening the bolts on \the [src]."),
span_warning("You begin loosening the bolts on \the [src]."))
playsound(loc, 'sound/items/ratchet.ogg', 25, 1)
@@ -396,6 +412,138 @@
span_warning("You repair \the [src]."))
chair_state = DROPSHIP_CHAIR_FOLDED
+/obj/structure/bed/chair/dropship/doublewide
+ name = "doublewide seat"
+ icon_state = "doublewide_chair" //only facing south cause the rest are ugly
+ max_integrity = 130
+ /// Handles the color of the chair
+ var/chair_color = NO_CHAIR_COLOR
+ /// If the chair can only be sat in by a leader or not
+ var/leader_chair = FALSE
+ /// pixel x shift to give to the buckled mob
+ var/buckling_x = 0
+
+/obj/structure/bed/chair/dropship/doublewide/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+ if(X.status_flags & INCORPOREAL)
+ return FALSE
+ if(LAZYLEN(buckled_mobs))
+ unbuckle_all_mobs(TRUE)
+ return ..()
+
+/obj/structure/bed/chair/dropship/doublewide/welder_act(mob/living/user, obj/item/I)
+ if(LAZYLEN(buckled_mobs))
+ balloon_alert_to_viewers("You cannot repair this chair while someone is sitting in it")
+ return
+ welder_repair_act(user, I, 130, 1 SECONDS, 0, SKILL_ENGINEER_METAL, 1)
+ chair_state = DROPSHIP_CHAIR_UNBUCKLED
+ update_icon()
+ return
+
+/obj/structure/bed/chair/dropship/doublewide/update_icon_state()
+ . = ..()
+ var/percentage = (obj_integrity / max_integrity) * 100
+ switch(percentage)
+ if(-INFINITY to 65)
+ chair_state = DROPSHIP_CHAIR_BROKEN
+ icon_state = "doublewide_chair[chair_color][chair_state]"
+
+/obj/structure/bed/chair/dropship/doublewide/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if(LAZYLEN(buckled_mobs) && chair_state == DROPSHIP_CHAIR_BROKEN)
+ unbuckle_mob(buckled_mobs[1])
+ balloon_alert_to_viewers("This chair is too damaged to stay sitting in")
+
+/obj/structure/bed/chair/dropship/doublewide/buckle_mob(mob/living/buckling_mob, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0, silent)
+ if(chair_state == DROPSHIP_CHAIR_BROKEN)
+ balloon_alert_to_viewers("This chair is too damaged to sit in")
+ return FALSE
+ if(leader_chair && buckling_mob.skills.getRating(SKILL_LEADERSHIP) < SKILL_LEAD_TRAINED)
+ balloon_alert(buckling_mob, "You don't feel worthy enough to sit in this chair")
+ return FALSE
+ if(buckling_x)
+ src.pixel_x = buckling_x
+ return ..()
+
+/obj/structure/bed/chair/dropship/doublewide/post_buckle_mob(mob/buckling_mob)
+ buckling_mob.pixel_x = buckling_x
+ buckling_mob.old_x = buckling_x
+ doublewide_mob_density(buckling_mob, TRUE)
+ return ..()
+
+/obj/structure/bed/chair/dropship/doublewide/post_unbuckle_mob(mob/buckled_mob)
+ buckled_mob.pixel_x = initial(buckled_mob.pixel_x)
+ buckled_mob.old_x = initial(buckled_mob.pixel_x)
+ doublewide_mob_density(buckled_mob, FALSE)
+ return ..()
+
+/// Handles checking the changing density for the person buckling or unbuckling and the person next to the buckling/unbuckling person
+/obj/structure/bed/chair/dropship/doublewide/proc/doublewide_mob_density(mob/interactionmob, buckling)
+ var/obj/structure/bed/chair/dropship/doublewide/other_doublewide = locate(/obj/structure/bed/chair/dropship/doublewide) in interactionmob.loc
+ var/mob/living/other_chair_buckled_mob
+ if(other_doublewide) //if there is another doublewide
+ if(LAZYLEN(other_doublewide.buckled_mobs) && (other_doublewide.buckled_mobs[1] != interactionmob))
+ other_chair_buckled_mob = other_doublewide.buckled_mobs[1]
+ if(buckling)
+ other_chair_buckled_mob.density = TRUE
+ interactionmob.density = TRUE
+ return
+ //if theyre unbuckling with and there is another buckled mob
+ other_chair_buckled_mob.density = FALSE
+ interactionmob.density = TRUE
+ return
+ if(buckling) //if theyre buckling with no other chairs
+ interactionmob.density = FALSE
+ return
+ //if there is no other doublewide or theyre unbuckling
+ interactionmob.density = TRUE
+
+/obj/structure/bed/chair/dropship/doublewide/left
+ pixel_x = -8
+ buckling_x = -8
+
+/obj/structure/bed/chair/dropship/doublewide/right
+ pixel_x = 9
+ buckling_x = 9
+
+/obj/structure/bed/chair/dropship/doublewide/left/alpha
+ name = "Alpha Squad Leader's Chair"
+ desc = "A chair specially reserved for the Alpha Squad Leader."
+ icon_state = "doublewide_chair_alpha"
+ chair_color = ALPHA_CHAIR
+ leader_chair = TRUE
+ max_integrity = 200
+
+/obj/structure/bed/chair/dropship/doublewide/right/bravo
+ name = "Bravo Squad Leader's Chair"
+ desc = "A chair specially reserved for the Bravo Squad Leader."
+ icon_state = "doublewide_chair_bravo"
+ chair_color = BRAVO_CHAIR
+ leader_chair = TRUE
+ max_integrity = 200
+
+/obj/structure/bed/chair/dropship/doublewide/left/charlie
+ name = "Charlie Squad Leader's Chair"
+ desc = "A chair specially reserved for the Charlie Squad Leader."
+ icon_state = "doublewide_chair_charlie"
+ chair_color = CHARLIE_CHAIR
+ leader_chair = TRUE
+ max_integrity = 200
+
+/obj/structure/bed/chair/dropship/doublewide/right/delta
+ name = "Delta Squad Leader's Chair"
+ desc = "A chair specially reserved for the Delta Squad Leader."
+ icon_state = "doublewide_chair_delta"
+ chair_color = DELTA_CHAIR
+ leader_chair = TRUE
+ max_integrity = 200
+
+/obj/structure/bed/chair/dropship/doublewide/fieldcommander
+ name = "Field Commander's Chair"
+ desc = "A chair specially reserved for the Field Commander."
+ icon_state = "doublewide_chair_fc"
+ chair_color = FC_CHAIR
+ leader_chair = TRUE
+ max_integrity = 200
/obj/structure/bed/chair/ob_chair
name = "seat"
diff --git a/code/game/objects/structures/stool_bed_chair_nest/janicart.dm b/code/game/objects/structures/stool_bed_chair_nest/janicart.dm
index 8e079d4feefba..c0d352904b6a1 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/janicart.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/janicart.dm
@@ -30,6 +30,8 @@
/obj/structure/bed/chair/janicart/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tool/mop))
if(reagents.total_volume <= 1)
diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
deleted file mode 100644
index a064bbee0065e..0000000000000
--- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
+++ /dev/null
@@ -1,139 +0,0 @@
-
-//MAKE ME A OFFICE CHAIR SUBTYPE!!
-
-/obj/structure/bed/chair/wheelchair
- name = "wheelchair"
- desc = "You sit in this. Either by will or force."
- icon_state = "wheelchair"
- anchored = FALSE
- buckle_flags = CAN_BUCKLE
- drag_delay = 1 //pulling something on wheels is easy
- var/bloodiness = 0
- var/move_delay = 6
-
-
-/obj/structure/bed/chair/wheelchair/relaymove(mob/user, direction)
- if(world.time <= last_move_time + move_delay)
- return
- // Redundant check?
- if(user.incapacitated() || user.lying_angle)
- return
-
- if(propelled) //can't manually move it mid-propelling.
- return
-
- if(ishuman(user))
- var/mob/living/carbon/human/driver = user
- var/datum/limb/left_hand = driver.get_limb("l_hand")
- var/datum/limb/right_hand = driver.get_limb("r_hand")
- var/working_hands = 2
- move_delay = initial(move_delay)
- if(!left_hand?.is_usable())
- move_delay += 4 //harder to move a wheelchair with a single hand
- working_hands--
- else if(left_hand.is_broken())
- move_delay++
- if(!right_hand?.is_usable())
- move_delay += 4
- working_hands--
- else if(right_hand.is_broken())
- move_delay += 2
- if(!working_hands)
- return // No hands to drive your chair? Tough luck!
- if(driver.pulling?.drag_delay) //Dragging stuff can slow you down a bit.
- var/pull_delay = driver.pulling.drag_delay
- if(ismob(driver.pulling))
- var/mob/M = driver.pulling
- if(M.buckled) //if the pulled mob is buckled to an object, we use that object's drag_delay.
- pull_delay = M.buckled.drag_delay
- move_delay += max(driver.pull_speed + pull_delay + 3 * driver.grab_state, 0) //harder grab makes you slower
-
- if(istype(driver.get_active_held_item(), /obj/item/weapon/gun)) //Wheelchair user has a gun out, so obviously can't move
- return
-
- if(driver.next_move_slowdown)
- move_delay += driver.next_move_slowdown
- driver.next_move_slowdown = 0
-
- step(src, direction)
-
-
-/obj/structure/bed/chair/wheelchair/Moved()
- . = ..()
- if(bloodiness)
- create_track()
- cut_overlays()
- if(LAZYLEN(buckled_mobs))
- handle_rotation_overlayed()
-
-
-/obj/structure/bed/chair/wheelchair/post_buckle_mob(mob/living/user)
- . = ..()
- handle_rotation_overlayed()
-
-/obj/structure/bed/chair/wheelchair/post_unbuckle_mob()
- . = ..()
- cut_overlays()
-
-/obj/structure/bed/chair/wheelchair/setDir(newdir)
- . = ..()
- handle_rotation(newdir)
-
-/obj/structure/bed/chair/wheelchair/handle_rotation(direction)
- if(LAZYLEN(buckled_mobs))
- handle_rotation_overlayed()
- for(var/m in buckled_mobs)
- var/mob/living/buckled_mob = m
- buckled_mob.setDir(direction)
-
-/obj/structure/bed/chair/wheelchair/proc/handle_rotation_overlayed()
- cut_overlays()
- var/image/V = image(icon = icon, icon_state = "w_overlay", layer = FLY_LAYER, dir = src.dir)
- add_overlay(V)
-
-
-/obj/structure/bed/chair/wheelchair/Bump(atom/A)
- . = ..()
- if(!LAZYLEN(buckled_mobs))
- return
-
- if(propelled)
- var/mob/living/occupant = buckled_mobs[1]
- unbuckle_mob(occupant)
-
- if (propelled)
- occupant.throw_at(A, 3, propelled)
-
- var/def_zone = ran_zone()
- var/armor_modifier = occupant.modify_by_armor(1, MELEE, 0, def_zone)
- occupant.throw_at(A, 3, propelled)
- occupant.apply_effect(6 SECONDS * armor_modifier, STUN)
- occupant.apply_effect(6 SECONDS * armor_modifier, WEAKEN)
- occupant.apply_effect(6 SECONDS * armor_modifier, STUTTER)
- occupant.apply_damage(10 * armor_modifier, BRUTE, def_zone)
- UPDATEHEALTH(occupant)
- playsound(src.loc, 'sound/weapons/punch1.ogg', 25, 1)
- if(isliving(A))
- var/mob/living/victim = A
- def_zone = ran_zone()
- armor_modifier = victim.modify_by_armor(1, MELEE, 0, def_zone)
- victim.apply_effect(6 SECONDS * armor_modifier, STUN)
- victim.apply_effect(6 SECONDS * armor_modifier, WEAKEN)
- victim.apply_effect(6 SECONDS * armor_modifier, STUTTER)
- victim.apply_damage(10 * armor_modifier, BRUTE, def_zone)
- UPDATEHEALTH(victim)
- occupant.visible_message(span_danger("[occupant] crashed into \the [A]!"))
-
-/obj/structure/bed/chair/wheelchair/proc/create_track()
- var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
- var/newdir = get_dir(get_step(loc, dir), loc)
- if(newdir == dir)
- B.setDir(newdir)
- else
- newdir = newdir|dir
- if(newdir == 3)
- newdir = 1
- else if(newdir == 12)
- newdir = 4
- B.setDir(newdir)
- bloodiness--
diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
index 40258c4cfdc14..c257b2bf33b80 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm
@@ -19,22 +19,18 @@
var/resisting_time = 0
layer = RESIN_STRUCTURE_LAYER
-/obj/structure/bed/nest/attackby(obj/item/I, mob/user, params)
- . = ..()
-
- if(istype(I, /obj/item/grab))
- var/obj/item/grab/G = I
- if(!ismob(G.grabbed_thing))
- return
- var/mob/M = G.grabbed_thing
- to_chat(user, span_notice("You place [M] on [src]."))
- M.forceMove(loc)
-
+/obj/structure/bed/nest/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!ismob(grab.grabbed_thing))
+ return
+ var/mob/grabbed_mob = grab.grabbed_thing
+ to_chat(user, span_notice("You place [grabbed_mob] on [src]."))
+ grabbed_mob.forceMove(loc)
+ return TRUE
//RUTGMC EDIT BEGIN - Moved to modular_RUtgmc\code\game\objects\structures\stool_bed_chair_nest\xeno_nest.dm
/*
-/obj/structure/bed/nest/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.a_intent != INTENT_HARM)
- return attack_hand(X)
+/obj/structure/bed/nest/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.a_intent != INTENT_HARM)
+ return attack_hand(xeno_attacker)
return ..()
*/ //RUTGMC EDIT END
diff --git a/code/game/objects/structures/supplypod.dm b/code/game/objects/structures/supplypod.dm
index c6777312b2d93..50fa0741096f8 100644
--- a/code/game/objects/structures/supplypod.dm
+++ b/code/game/objects/structures/supplypod.dm
@@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(pod_styles, list(\
closet_flags = CLOSET_ALLOW_OBJS|CLOSET_ALLOW_DENSE_OBJ
soft_armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, FIRE = 100, ACID = 80)
anchored = TRUE
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
var/adminNamed = FALSE
var/bluespace = FALSE
var/landingDelay = 30
@@ -75,16 +75,20 @@ GLOBAL_LIST_INIT(pod_styles, list(\
. = ..()
setStyle(style, TRUE)
+/obj/structure/closet/supplypod/update_icon_state()
+ . = ..()
+ icon_state = GLOB.pod_styles[style][POD_ICON_STATE]
+
+/obj/structure/closet/supplypod/update_overlays()
+ . = ..()
-/obj/structure/closet/supplypod/update_icon()
- cut_overlays()
if(style == STYLE_SEETHROUGH || style == STYLE_INVISIBLE)
return
if(opened)
- add_overlay("[icon_state]_open")
+ . += "[icon_state]_open"
else
- add_overlay("[icon_state]_door")
+ . += "[icon_state]_door"
/obj/structure/closet/supplypod/proc/setStyle(chosenStyle, duringInit = FALSE)
@@ -92,7 +96,6 @@ GLOBAL_LIST_INIT(pod_styles, list(\
setStyle(STYLE_CENTCOM)
return
style = chosenStyle
- icon_state = GLOB.pod_styles[chosenStyle][POD_ICON_STATE]
if(!adminNamed)
name = GLOB.pod_styles[chosenStyle][POD_NAME]
desc = GLOB.pod_styles[chosenStyle][POD_DESC]
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index b66ffbd4e6a5a..1350fa41b8fca 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -76,7 +76,8 @@
visible_message(span_danger("[O] plows straight through [src]!"))
deconstruct(FALSE)
-/obj/structure/table/update_icon()
+/obj/structure/table/update_icon_state()
+ . = ..()
if(flipped)
var/ttype = 0
var/tabledirs = 0
@@ -132,34 +133,7 @@
/obj/structure/table/attackby(obj/item/I, mob/user, params)
. = ..()
-
- if(istype(I, /obj/item/grab) && get_dist(src, user) <= 1)
- if(isxeno(user))
- return
-
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/M = G.grabbed_thing
- if(user.a_intent == INTENT_HARM)
- if(user.grab_state <= GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
-
- if(prob(15))
- M.Paralyze(10 SECONDS)
- M.apply_damage(8, BRUTE, "head", blocked = MELEE, updating_health = TRUE)
- user.visible_message(span_danger("[user] slams [M]'s face against [src]!"),
- span_danger("You slam [M]'s face against [src]!"))
- log_combat(user, M, "slammed", "", "against \the [src]")
- playsound(loc, 'sound/weapons/tablehit1.ogg', 25, 1)
-
- else if(user.grab_state >= GRAB_AGGRESSIVE)
- M.forceMove(loc)
- M.Paralyze(10 SECONDS)
- user.visible_message(span_danger("[user] throws [M] on [src]."),
- span_danger("You throw [M] on [src]."))
+ if(.)
return
if(user.a_intent != INTENT_HARM)
@@ -173,6 +147,24 @@
I.pixel_y = clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
return TRUE
+/obj/structure/table/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ playsound(loc, 'sound/weapons/tablehit1.ogg', 25, 1)
+ return
+ if(user.a_intent == INTENT_HARM)
+ return
+ if(user.grab_state < GRAB_AGGRESSIVE)
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ grabbed_mob.forceMove(loc)
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.visible_message(span_danger("[user] throws [grabbed_mob] on [src]."),
+ span_danger("You throw [grabbed_mob] on [src]."))
+ return TRUE
/obj/structure/table/proc/straight_table_check(direction)
var/obj/structure/table/T
@@ -231,7 +223,7 @@
if(T.flipped && T.dir == src.dir && !T.unflipping_check(new_dir))
return FALSE
for(var/obj/structure/S in loc)
- if((S.flags_atom & ON_BORDER) && S.density && S != src) //We would put back on a structure that wouldn't allow it
+ if((S.atom_flags & ON_BORDER) && S.density && S != src) //We would put back on a structure that wouldn't allow it
return FALSE
return TRUE
@@ -277,7 +269,7 @@
layer = FLY_LAYER
flipped = TRUE
coverage = 60
- flags_atom |= ON_BORDER
+ atom_flags |= ON_BORDER
for(var/D in list(turn(direction, 90), turn(direction, -90)))
var/obj/structure/table/T = locate() in get_step(src,D)
if(T && !T.flipped)
@@ -297,7 +289,7 @@
flipped = FALSE
coverage = 10
climbable = initial(climbable)
- flags_atom &= ~ON_BORDER
+ atom_flags &= ~ON_BORDER
for(var/D in list(turn(dir, 90), turn(dir, -90)))
var/obj/structure/table/T = locate() in get_step(src.loc,D)
if(T?.flipped && T.dir == src.dir)
@@ -464,6 +456,10 @@
table_status = TABLE_STATUS_FIRM
return TRUE
+/obj/structure/table/reinforced/weak //used for the icon, functionally similar to a table.
+ name = "rickety reinforced table"
+ desc = "A square metal surface resting on four legs. It has seen better days to whence it was strong."
+ max_integrity = 40
/obj/structure/table/reinforced/prison
desc = "A square metal surface resting on four legs. This one has side panels, making it useful as a desk, but impossible to flip."
@@ -529,6 +525,8 @@
/obj/structure/rack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
deconstruct(TRUE)
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 30052da2a34be..465e452440ef1 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -24,14 +24,18 @@
update_icon()
-/obj/structure/dispenser/update_icon()
- overlays.Cut()
+/obj/structure/dispenser/update_overlays()
+ . = ..()
switch(oxygentanks)
- if(1 to 3) overlays += "oxygen-[oxygentanks]"
- if(4 to INFINITY) overlays += "oxygen-4"
+ if(1 to 3)
+ . += "oxygen-[oxygentanks]"
+ if(4 to INFINITY)
+ . += "oxygen-4"
switch(phorontanks)
- if(1 to 4) overlays += "phoron-[phorontanks]"
- if(5 to INFINITY) overlays += "phoron-5"
+ if(1 to 4)
+ . += "phoron-[phorontanks]"
+ if(5 to INFINITY)
+ . += "phoron-5"
/obj/structure/dispenser/interact(mob/user)
. = ..()
@@ -49,6 +53,8 @@
/obj/structure/dispenser/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/tank/oxygen) || istype(I, /obj/item/tank/air) || istype(I, /obj/item/tank/anesthetic))
if(oxygentanks >= 10)
diff --git a/code/game/objects/structures/teleporter.dm b/code/game/objects/structures/teleporter.dm
index 69dcbb0f2c2f3..efbe3c1964f46 100644
--- a/code/game/objects/structures/teleporter.dm
+++ b/code/game/objects/structures/teleporter.dm
@@ -141,6 +141,7 @@
update_icon()
/obj/machinery/deployable/teleporter/update_icon_state()
+ . = ..()
var/obj/item/teleporter_kit/kit = get_internal_item()
if(powered() || kit?.cell?.charge > TELEPORTING_COST)
icon_state = default_icon_state + "_on"
@@ -154,10 +155,10 @@
icon_state = "teleporter"
max_integrity = 200
- flags_item = IS_DEPLOYABLE|DEPLOYED_WRENCH_DISASSEMBLE
+ item_flags = IS_DEPLOYABLE|DEPLOYED_WRENCH_DISASSEMBLE
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
///The linked teleporter
var/obj/item/teleporter_kit/linked_teleporter
///The optional cell to power the teleporter if off the grid
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index e91eb1a09b477..e36351b2bf4a3 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -46,11 +46,14 @@
open = !open
update_icon()
-/obj/structure/toilet/update_icon()
+/obj/structure/toilet/update_icon_state()
+ . = ..()
icon_state = "toilet[open][cistern]"
/obj/structure/toilet/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iscrowbar(I))
to_chat(user, span_notice("You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]."))
@@ -63,40 +66,6 @@
cistern = !cistern
update_icon()
- else if(istype(I, /obj/item/grab))
- if(isxeno(user))
- return
- var/obj/item/grab/G = I
-
- if(!iscarbon(G.grabbed_thing))
- return
-
- var/mob/living/carbon/C = G.grabbed_thing
-
- if(user.grab_state <= GRAB_PASSIVE)
- to_chat(user, span_notice("You need a tighter grip."))
- return
-
- if(!C.loc == get_turf(src))
- to_chat(user, span_notice("[C] needs to be on the toilet."))
- return
-
- if(open && !swirlie)
- user.visible_message(span_danger("[user] starts to give [C] a swirlie!"), span_notice("You start to give [C] a swirlie!"))
- swirlie = C
- if(!do_after(user, 3 SECONDS, NONE, src, BUSY_ICON_HOSTILE))
- return
-
- user.visible_message(span_danger("[user] gives [C] a swirlie!"), span_notice("You give [C] a swirlie!"), "You hear a toilet flushing.")
- log_combat(user, C, "given a swirlie")
- if(!C.internal)
- C.adjustOxyLoss(5)
- swirlie = null
- else
- user.visible_message(span_danger("[user] slams [C] into the [src]!"), span_notice("You slam [C] into the [src]!"))
- log_combat(user, C, "slammed", "", "into the \the [src]")
- C.apply_damage(8, BRUTE, blocked = MELEE, updating_health = TRUE)
-
else if(cistern && !issilicon(user)) //STOP PUTTING YOUR MODULES IN THE TOILET.
if(I.w_class > 3)
to_chat(user, span_notice("\The [I] does not fit."))
@@ -111,10 +80,43 @@
w_items += I.w_class
to_chat(user, "You carefully place \the [I] into the cistern.")
+/obj/structure/toilet/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ return
+ if(isxeno(user))
+ return
+ if(!iscarbon(grab.grabbed_thing))
+ return
+ if(!open || swirlie)
+ return
+
+ var/mob/living/carbon/grabbed_mob = grab.grabbed_thing
+
+ if(user.grab_state <= GRAB_PASSIVE)
+ to_chat(user, span_notice("You need a tighter grip."))
+ return
+
+ if(!grabbed_mob.loc == get_turf(src))
+ to_chat(user, span_notice("[grabbed_mob] needs to be on the toilet."))
+ return
+
+ user.visible_message(span_danger("[user] starts to give [grabbed_mob] a swirlie!"), span_notice("You start to give [grabbed_mob] a swirlie!"))
+ swirlie = grabbed_mob
+ if(!do_after(user, 3 SECONDS, NONE, src, BUSY_ICON_HOSTILE))
+ return
+
+ user.visible_message(span_danger("[user] gives [grabbed_mob] a swirlie!"), span_notice("You give [grabbed_mob] a swirlie!"), "You hear a toilet flushing.")
+ log_combat(user, grabbed_mob, "given a swirlie")
+ if(!grabbed_mob.internal)
+ grabbed_mob.adjustOxyLoss(5)
+ swirlie = null
+
/obj/structure/toilet/alternate
icon_state = "toilet200"
-/obj/structure/toilet/alternate/update_icon()
+/obj/structure/toilet/alternate/update_icon_state()
+ . = ..()
icon_state = "toilet2[open][cistern]"
/obj/structure/urinal
@@ -125,30 +127,6 @@
density = FALSE
anchored = TRUE
-/obj/structure/urinal/attackby(obj/item/I, mob/user, params)
- . = ..()
-
- if(istype(I, /obj/item/grab))
- if(isxeno(user))
- return
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/GM = G.grabbed_thing
- if(user.grab_state <= GRAB_PASSIVE)
- to_chat(user, span_notice("You need a tighter grip."))
- return
-
- if(!GM.loc == get_turf(src))
- to_chat(user, span_notice("[GM] needs to be on the urinal."))
- return
-
- user.visible_message(span_danger("[user] slams [GM] into the [src]!"), span_notice("You slam [GM] into the [src]!"))
- GM.apply_damage(8, blocked = MELEE)
- UPDATEHEALTH(GM)
-
-
/obj/machinery/shower
name = "shower"
desc = "The HS-451. Installed in the 2050s by the Nanotrasen Hygiene Division."
@@ -189,7 +167,7 @@
if(.)
return
on = !on
- update_icon()
+ update_mist()
if(on)
start_processing()
if (user.loc == loc)
@@ -202,6 +180,8 @@
/obj/machinery/shower/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(I.type == /obj/item/tool/analyzer)
to_chat(user, span_notice("The water temperature seems to be [watertemp]."))
@@ -221,8 +201,9 @@
watertemp = "normal"
user.visible_message(span_notice("[user] adjusts the shower with \the [I]."), span_notice("You adjust the shower with \the [I]."))
-/obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up
- overlays.Cut() //once it's been on for a while, in addition to handling the water overlay.
+/obj/machinery/shower/proc/update_mist()
+//this is terribly unreadable, but basically it makes the shower mist up once it's been on for a while
+ update_icon()
if(mymist)
qdel(mymist)
mymist = null
@@ -248,6 +229,11 @@
mymist = null
ismist = FALSE
+/obj/machinery/shower/update_overlays()
+ . = ..()
+ if(on)
+ . += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir)
+
/obj/machinery/shower/proc/on_cross(datum/source, atom/movable/O, oldloc, oldlocs)
SIGNAL_HANDLER
wash(O)
@@ -365,6 +351,8 @@
/obj/structure/sink/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(busy)
to_chat(user, span_warning("Someone's already washing here."))
@@ -395,7 +383,7 @@
L.Paralyze(20 SECONDS)
L.visible_message(span_danger("[L] was stunned by [L.p_their()] wet [I]!"))
- if(I.flags_item & ITEM_ABSTRACT)
+ if(I.item_flags & ITEM_ABSTRACT)
return
var/turf/location = user.loc
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index 0e04738990e01..52364d9f9c166 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -18,7 +18,7 @@
density = FALSE
dir = NORTH
allow_pass_flags = PASS_GLASS|PASS_AIR
- flags_atom = ON_BORDER
+ atom_flags = ON_BORDER
var/obj/item/circuitboard/airlock/electronics = null
@@ -47,10 +47,13 @@
update_icon()
/obj/structure/windoor_assembly/update_icon_state()
+ . = ..()
icon_state = "[facing]_[secure]windoor_assembly[state]"
/obj/structure/windoor_assembly/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
switch(state)
if("01")
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index d3b40eba36ca9..56c2ed4a5bccc 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -7,12 +7,14 @@
density = TRUE
anchored = TRUE
layer = WINDOW_LAYER
- flags_atom = ON_BORDER|DIRLOCK
+ atom_flags = ON_BORDER|DIRLOCK
allow_pass_flags = PASS_GLASS
resistance_flags = XENO_DAMAGEABLE | DROPSHIP_IMMUNE
coverage = 20
var/dismantle = FALSE //If we're dismantling the window properly no smashy smashy
max_integrity = 15
+ ///Optimization for dynamic explosion block values, for things whose explosion block is dependent on certain conditions.
+ var/real_explosion_block = 0
var/state = 2
var/reinf = FALSE
var/basestate = "window"
@@ -29,7 +31,7 @@
//I hate this as much as you do
/obj/structure/window/full
dir = 10
- flags_atom = DIRLOCK
+ atom_flags = DIRLOCK
/obj/structure/window/Initialize(mapload, start_dir, constructed)
..()
@@ -93,7 +95,7 @@
//Once a full window, it will always be a full window, so there's no point
//having the same type for both.
/obj/structure/window/proc/is_full_window()
- if(!(flags_atom & ON_BORDER) || ISDIAGONALDIR(dir))
+ if(!(atom_flags & ON_BORDER) || ISDIAGONALDIR(dir))
return TRUE
return FALSE
@@ -125,43 +127,41 @@
span_notice("You hear a knocking sound."))
windowknock_cooldown = world.time + 100
+/obj/structure/window/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!isliving(grab.grabbed_thing))
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ var/state = user.grab_state
+ user.drop_held_item()
+ step_towards(grabbed_mob, src)
+ var/damage = (user.skills.getRating(SKILL_CQC) * CQC_SKILL_DAMAGE_MOD)
+ switch(state)
+ if(GRAB_PASSIVE)
+ damage += base_damage
+ grabbed_mob.visible_message(span_warning("[user] slams [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "slammed", "", "against \the [src]")
+ if(GRAB_AGGRESSIVE)
+ damage += base_damage * 1.5
+ grabbed_mob.visible_message(span_danger("[user] bashes [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "bashed", "", "against \the [src]")
+ if(prob(50))
+ grabbed_mob.Paralyze(2 SECONDS)
+ if(GRAB_NECK)
+ damage += base_damage * 2
+ grabbed_mob.visible_message(span_danger("[user] crushes [grabbed_mob] against \the [src]!"))
+ log_combat(user, grabbed_mob, "crushed", "", "against \the [src]")
+ grabbed_mob.Paralyze(2 SECONDS)
+ grabbed_mob.apply_damage(damage, blocked = MELEE, updating_health = TRUE)
+ take_damage(damage * 2, BRUTE, MELEE)
+ return TRUE
+
/obj/structure/window/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
- if(istype(I, /obj/item/grab) && get_dist(src, user) < 2)
- if(isxeno(user))
- return
- var/obj/item/grab/G = I
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/M = G.grabbed_thing
- var/state = user.grab_state
- user.drop_held_item()
- switch(state)
- if(GRAB_PASSIVE)
- M.visible_message(span_warning("[user] slams [M] against \the [src]!"))
- log_combat(user, M, "slammed", "", "against \the [src]")
- M.apply_damage(7, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(10, BRUTE, MELEE)
- if(GRAB_AGGRESSIVE)
- M.visible_message(span_danger("[user] bashes [M] against \the [src]!"))
- log_combat(user, M, "bashed", "", "against \the [src]")
- if(prob(50))
- M.Paralyze(2 SECONDS)
- M.apply_damage(10, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(25, BRUTE, MELEE)
- if(GRAB_NECK)
- M.visible_message(span_danger("[user] crushes [M] against \the [src]!"))
- log_combat(user, M, "crushed", "", "against \the [src]")
- M.Paralyze(10 SECONDS)
- M.apply_damage(20, blocked = MELEE)
- UPDATEHEALTH(M)
- take_damage(50, BRUTE, MELEE)
-
- else if(I.flags_item & NOBLUDGEON)
+ if(I.item_flags & NOBLUDGEON)
return
else if(isscrewdriver(I) && deconstructable)
@@ -195,7 +195,7 @@
if(reinf)
new /obj/item/stack/sheet/glass/reinforced(loc, 2)
else
- new /obj/item/stack/sheet/glass(loc, 2)
+ new /obj/item/stack/sheet/glass/glass(loc, 2)
else
new shardtype(loc)
if(is_full_window())
@@ -245,9 +245,8 @@
INVOKE_NEXT_TICK(W, TYPE_PROC_REF(/atom/movable, update_icon))
//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
-/obj/structure/window/update_icon()
- //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
- //this way it will only update full-tile ones
+/obj/structure/window/update_icon_state()
+ . = ..()
if(!src)
return
if(!is_full_window())
@@ -388,9 +387,9 @@
basestate = "window"
max_integrity = 40
reinf = TRUE
- flags_atom = NONE
+ atom_flags = NONE
-/obj/structure/window/shuttle/update_icon() //icon_state has to be set manually
+/obj/structure/window/shuttle/update_icon_state()
return
//Framed windows
@@ -399,7 +398,7 @@
name = "theoretical window"
layer = TABLE_LAYER
static_frame = TRUE
- flags_atom = NONE //This is not a border object; it takes up the entire tile.
+ atom_flags = NONE //This is not a border object; it takes up the entire tile.
explosion_block = 2
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = list(
@@ -421,8 +420,7 @@
/obj/structure/window/framed/update_icon()
QUEUE_SMOOTH(src)
-
-
+ return ..()
/obj/structure/window/framed/deconstruct(disassembled = TRUE, leave_frame = TRUE)
if(window_frame && leave_frame)
diff --git a/code/game/objects/structures/window_frame.dm b/code/game/objects/structures/window_frame.dm
index cefe080862056..e6bbfc4dadb1c 100644
--- a/code/game/objects/structures/window_frame.dm
+++ b/code/game/objects/structures/window_frame.dm
@@ -49,6 +49,7 @@
/obj/structure/window_frame/update_icon()
QUEUE_SMOOTH(src)
+ return ..()
/obj/structure/window_frame/Destroy()
density = FALSE
@@ -61,6 +62,8 @@
/obj/structure/window_frame/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, sheet_type))
var/obj/item/stack/sheet/sheet = I
@@ -80,35 +83,31 @@
new window_type(loc) //This only works on Theseus windows!
qdel(src)
- else if(istype(I, /obj/item/grab))
- var/obj/item/grab/G = I
- if(isxeno(user))
- return
-
- if(!isliving(G.grabbed_thing))
- return
-
- var/mob/living/M = G.grabbed_thing
- if(user.grab_state < GRAB_AGGRESSIVE)
- to_chat(user, span_warning("You need a better grip to do that!"))
- return
-
- if(get_dist(src, M) > 1)
- to_chat(user, span_warning("[M] needs to be next to [src]."))
- return
-
- if(user.do_actions)
- return
-
- user.visible_message(span_notice("[user] starts pulling [M] onto [src]."),
- span_notice("You start pulling [M] onto [src]!"))
- if(!do_after(user, 2 SECONDS, NONE, M, BUSY_ICON_GENERIC))
- return
- M.Paralyze(4 SECONDS)
- user.visible_message(span_warning("[user] pulls [M] onto [src]."),
- span_notice("You pull [M] onto [src]."))
- M.forceMove(loc)
-
+/obj/structure/window_frame/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE)
+ . = ..()
+ if(.)
+ return
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(user.do_actions)
+ return
+ if(user.grab_state < GRAB_AGGRESSIVE)
+ to_chat(user, span_warning("You need a better grip to do that!"))
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ if(get_dist(src, grabbed_mob) > 1)
+ to_chat(user, span_warning("[grabbed_mob] needs to be next to [src]."))
+ return
+ user.visible_message(span_notice("[user] starts pulling [grabbed_mob] onto [src]."),
+ span_notice("You start pulling [grabbed_mob] onto [src]!"))
+ if(!do_after(user, 2 SECONDS, NONE, grabbed_mob, BUSY_ICON_GENERIC))
+ return
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.visible_message(span_warning("[user] pulls [grabbed_mob] onto [src]."),
+ span_notice("You pull [grabbed_mob] onto [src]."))
+ grabbed_mob.forceMove(loc)
+ return TRUE
/obj/structure/window_frame/mainship
icon = 'icons/obj/smooth_objects/ship_window_frame.dmi'
diff --git a/code/game/objects/structures/xeno.dm b/code/game/objects/structures/xeno.dm
index 4e0c29769d355..51d69f853c012 100644
--- a/code/game/objects/structures/xeno.dm
+++ b/code/game/objects/structures/xeno.dm
@@ -27,6 +27,8 @@
/obj/alien/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(user.a_intent == INTENT_HARM) //Already handled at the parent level.
return
@@ -63,7 +65,7 @@
desc = "Looks like some kind of slimy growth."
icon_state = "Resin1"
max_integrity = 200
- resistance_flags = XENO_DAMAGEABLE
+ resistance_flags = XENO_DAMAGEABLE|UNACIDABLE
/obj/alien/resin/attack_hand(mob/living/user)
@@ -117,14 +119,14 @@
victim.next_move_slowdown += slow_amt
/* RUTGMC DELETION
-/obj/alien/resin/sticky/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/alien/resin/sticky/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- if(X.a_intent == INTENT_HARM) //Clear it out on hit; no need to double tap.
- if(CHECK_BITFIELD(SSticker.mode?.flags_round_type, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active && refundable)
- SSresinshaping.quickbuild_points_by_hive[X.hivenumber]++
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW) //SFX
+ if(xeno_attacker.a_intent == INTENT_HARM) //Clear it out on hit; no need to double tap.
+ if(CHECK_BITFIELD(SSticker.mode?.round_type_flags, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active && refundable)
+ SSresinshaping.quickbuild_points_by_hive[xeno_attacker.hivenumber]++
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW) //SFX
playsound(src, "alien_resin_break", 25) //SFX
deconstruct(TRUE)
return
@@ -193,22 +195,22 @@
/* RUTGMC DELETION
//clicking on resin doors attacks them, or opens them without harm intent
-/obj/structure/mineral_door/resin/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- var/turf/cur_loc = X.loc
+/obj/structure/mineral_door/resin/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ var/turf/cur_loc = xeno_attacker.loc
if(!istype(cur_loc))
return FALSE //Some basic logic here
- if(X.a_intent != INTENT_HARM)
- try_toggle_state(X)
+ if(xeno_attacker.a_intent != INTENT_HARM)
+ try_toggle_state(xeno_attacker)
return TRUE
- if(CHECK_BITFIELD(SSticker.mode?.flags_round_type, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active)
- SSresinshaping.quickbuild_points_by_hive[X.hivenumber]++
+ if(CHECK_BITFIELD(SSticker.mode?.round_type_flags, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active)
+ SSresinshaping.quickbuild_points_by_hive[xeno_attacker.hivenumber]++
qdel(src)
return TRUE
- src.balloon_alert(X, "Destroying...")
+ src.balloon_alert(xeno_attacker, "Destroying...")
playsound(src, "alien_resin_break", 25)
- if(do_after(X, 1 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
- src.balloon_alert(X, "Destroyed")
+ if(do_after(xeno_attacker, 1 SECONDS, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
+ src.balloon_alert(xeno_attacker, "Destroyed")
qdel(src)
*/
@@ -283,27 +285,27 @@
/obj/item/resin_jelly
name = "resin jelly"
desc = "A foul, viscous resin jelly that doesnt seem to burn easily."
- icon = 'icons/unused/Marine_Research.dmi'
- icon_state = "biomass"
+ icon = 'icons/Xeno/xeno_materials.dmi'
+ icon_state = "resin_jelly"
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 200, ACID = 0)
var/immune_time = 15 SECONDS
///Holder to ensure only one user per resin jelly.
var/current_user
-/obj/item/resin_jelly/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/item/resin_jelly/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- if(X.xeno_caste.can_flags & CASTE_CAN_HOLD_JELLY)
- return attack_hand(X)
- if(X.do_actions || !isnull(current_user))
+ if(xeno_attacker.xeno_caste.can_flags & CASTE_CAN_HOLD_JELLY)
+ return attack_hand(xeno_attacker)
+ if(xeno_attacker.do_actions || !isnull(current_user))
return
- current_user = X
- X.balloon_alert(X, "Applying...")
- if(!do_after(X, RESIN_SELF_TIME, NONE, X, BUSY_ICON_MEDICAL))
+ current_user = xeno_attacker
+ xeno_attacker.balloon_alert(xeno_attacker, "Applying...")
+ if(!do_after(xeno_attacker, RESIN_SELF_TIME, NONE, xeno_attacker, BUSY_ICON_MEDICAL))
current_user = null
return
- activate_jelly(X)
+ activate_jelly(xeno_attacker)
/obj/item/resin_jelly/attack_self(mob/living/carbon/xenomorph/user)
//Activates if the item itself is clicked in hand.
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 3e1b91f67dec3..e1b7c6749b257 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -62,18 +62,27 @@ A good representation is: 'byond applies a volume reduction to the sound every X
frequency = GET_RANDOM_FREQ // Same frequency for everybody
// Looping through the player list has the added bonus of working for mobs inside containers
var/sound/S = sound(get_sfx(soundin))
- for(var/i in GLOB.player_list)
- var/mob/M = i
- if(!M.client)
+ for(var/mob/M AS in GLOB.player_list|GLOB.aiEyes)
+ if(!M.client && !istype(M, /mob/camera/aiEye))
continue
var/turf/T = get_turf(M)
if(!T || T.z != turf_source.z || get_dist(M, turf_source) > sound_range)
continue
- M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, S)
+ M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, S, sound_reciever = M)
+
+ for(var/obj/vehicle/sealed/armored/armor AS in GLOB.tank_list)
+ if(!armor.interior || armor.z != turf_source.z || get_dist(armor.loc, turf_source) > sound_range)
+ continue
+ for(var/mob/crew AS in armor.interior.occupants)
+ //turf source is null on purpose because it will not work properly since crew is on a different z
+ crew.playsound_local(null, soundin, vol*0.5, vary, frequency, falloff, is_global, channel, S, sound_reciever = crew)
+
//todo rename S to sound_to_use
-/mob/proc/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1)
- if(!client)
+/mob/proc/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1, mob/sound_reciever)
+ if(!sound_reciever)
+ sound_reciever = src
+ if(!sound_reciever.client)
return FALSE
if(!S)
@@ -108,10 +117,10 @@ A good representation is: 'byond applies a volume reduction to the sound every X
if(!is_global)
S.environment = SOUND_ENVIRONMENT_ROOM
- SEND_SOUND(src, S)
+ SEND_SOUND(sound_reciever, S)
-/mob/living/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1)
+/mob/living/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1, mob/sound_reciever)
if(ear_deaf > 0)
return FALSE
return ..()
diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm
index 46ac12cc0d072..0b380f666043b 100644
--- a/code/game/turfs/closed.dm
+++ b/code/game/turfs/closed.dm
@@ -51,12 +51,12 @@
minimap_color = MINIMAP_SOLID
overlays += rock_side
-/turf/closed/mineral/attack_alien(mob/living/carbon/xenomorph/xeno_user, isrightclick = FALSE)
+/turf/closed/mineral/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
- if(isxenobehemoth(xeno_user))
- xeno_user.do_attack_animation(src)
+ if(isxenobehemoth(xeno_attacker))
+ xeno_attacker.do_attack_animation(src)
playsound(src, 'sound/effects/behemoth/earth_pillar_eating.ogg', 10, TRUE)
- xeno_user.visible_message(span_xenowarning("\The [xeno_user] eats away at the [src.name]!"), \
+ xeno_attacker.visible_message(span_xenowarning("\The [xeno_attacker] eats away at the [src.name]!"), \
span_xenonotice(pick(
"We eat away at the stone. It tastes good, as expected of our primary diet.",
"Mmmmm... Delicious rock. A fitting meal for the hardiest of creatures.",
@@ -111,9 +111,9 @@
icon_state = "darkfrostwall-0"
walltype = "darkfrostwall"
base_icon_state = "darkfrostwall"
- resistance_flags = PLASMACUTTER_IMMUNE|UNACIDABLE
/turf/closed/mineral/smooth/darkfrostwall/indestructible
+ name = "tough rock"
resistance_flags = RESIST_ALL
icon_state = "wall-invincible"
@@ -162,6 +162,16 @@
resistance_flags = RESIST_ALL
icon_state = "wall-invincible"
+//basalt mineral wall
+/turf/closed/mineral/smooth/basalt
+ icon = 'icons/turf/walls/basaltwall.dmi'
+ icon_state = "basaltwall-0"
+ base_icon_state = "basaltwall"
+
+/turf/closed/mineral/smooth/basalt/indestructible
+ resistance_flags = RESIST_ALL
+ icon_state = "wall-invincible"
+
//Ground map dense jungle
/turf/closed/gm
icon = 'icons/turf/walls/jungle.dmi'
@@ -187,7 +197,7 @@
/turf/closed/gm/ex_act(severity)
switch(severity)
if(EXPLODE_DEVASTATE)
- ChangeTurf(/turf/open/ground/grass)
+ ChangeTurf(/turf/open/ground/grass/weedable)
/turf/closed/gm/dense
name = "dense jungle wall"
@@ -293,9 +303,7 @@
icon_state = "Intersection"
/turf/closed/attackby(obj/item/I, mob/user, params)
- . = ..()
-
- if(istype(I, /obj/item/tool/pickaxe/plasmacutter) && !user.do_actions)
+ if(isplasmacutter(I) && !user.do_actions)
var/obj/item/tool/pickaxe/plasmacutter/P = I
if(CHECK_BITFIELD(resistance_flags, PLASMACUTTER_IMMUNE))
to_chat(user, span_warning("[P] can't cut through this!"))
@@ -309,6 +317,8 @@
//change targetted turf to a new one to simulate deconstruction
ChangeTurf(open_turf_type)
+ return
+ return ..()
//Ice Thin Wall
/turf/closed/ice/thin
@@ -507,8 +517,13 @@
opacity = FALSE
allow_pass_flags = PASS_GLASS
+/turf/closed/shuttle/dropship1/aislewindow
+ icon_state = "shuttle_aisle_window"
+ opacity = FALSE
+
/turf/closed/shuttle/dropship1/panel
icon_state = "shuttle_interior_panel"
+ opacity = FALSE
/turf/closed/shuttle/dropship1/engineone
icon_state = "shuttle_interior_backengine"
diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm
index e320c17d47d8b..f1046378d3c0d 100644
--- a/code/game/turfs/floor.dm
+++ b/code/game/turfs/floor.dm
@@ -68,6 +68,7 @@
return W
/turf/open/floor/update_icon_state()
+ . = ..()
if(broken)
icon_state = broken_states()
else if(burnt)
@@ -116,7 +117,7 @@
return TRUE
. = ..()
if(.)
- return .
+ return
if(floor_tile && istype(object, /obj/item/stack/tile))
try_replace_tile(object, user, params)
return TRUE
diff --git a/code/game/turfs/floor_ground.dm b/code/game/turfs/floor_ground.dm
index 72d592521911a..c9deeab594a35 100644
--- a/code/game/turfs/floor_ground.dm
+++ b/code/game/turfs/floor_ground.dm
@@ -187,6 +187,7 @@
/turf/open/floor/plating/ground/mars/random/cave
name = "cave"
icon_state = "mars_cave"
+ smoothing_groups = list(SMOOTH_GROUP_SAND)
/turf/open/floor/plating/ground/mars/random/cave/darker
color = "#948a7c"
@@ -346,6 +347,20 @@
name = "asphalt"
icon_state = "cement_threeside"
+/turf/open/floor/plating/ground/desertdam/asphalt/autosmooth
+ name = "concrete"
+ icon = 'icons/turf/floors/asphalt-regular.dmi'
+ icon_state = "asphalt-icon"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = list(SMOOTH_GROUP_ASPHALT)
+ canSmoothWith = list(
+ SMOOTH_GROUP_ASPHALT,
+ )
+ base_icon_state = "asphalt-regular"
+
+/turf/open/floor/plating/ground/desertdam/asphalt/autosmooth/alt
+ icon = 'icons/turf/floors/asphalt-sunbleached.dmi'
+ base_icon_state = "aasphalt-sunbleached"
//CAVE
/turf/open/floor/plating/ground/desertdam/cave
@@ -412,3 +427,20 @@
mediumxenofootstep = FOOTSTEP_CONCRETE
barefootstep = FOOTSTEP_CONCRETE
shoefootstep = FOOTSTEP_CONCRETE
+
+///These are entirely for decoration purposes, do not make them functional, it will cause salt.
+/turf/open/floor/chasm
+ name = "chasm"
+ desc = "Watch your step."
+ icon = 'icons/turf/floors/chasms.dmi'
+ icon_state = "chasms-0"
+ base_icon_state = "chasms"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = list(SMOOTH_GROUP_TURF_CHASM)
+ canSmoothWith = list(SMOOTH_GROUP_TURF_CHASM)
+ density = TRUE //keep people from stepping on it
+
+/turf/open/floor/chasm/junglechasm
+ icon = 'icons/turf/floors/junglechasm.dmi'
+ icon_state = "junglechasm-0"
+ base_icon_state = "junglechasm"
diff --git a/code/game/turfs/floor_types.dm b/code/game/turfs/floor_types.dm
index ee826f2156318..6561f58d72292 100644
--- a/code/game/turfs/floor_types.dm
+++ b/code/game/turfs/floor_types.dm
@@ -20,9 +20,18 @@
/turf/open/floor/mainship/plate/outline
icon_state = "test_floor5"
+/turf/open/floor/mainship/hexagon
+ icon_state = "hexagon"
+
/turf/open/floor/mainship/cargo
icon_state = "cargo"
+/turf/open/floor/mainship/yellow_cargo
+ icon_state = "yellow_cargo"
+
+/turf/open/floor/mainship/yellow_cargo/arrow
+ icon_state = "yellow_cargo_arrow"
+
/turf/open/floor/mainship/cargo/arrow
icon_state = "cargo_arrow"
@@ -444,6 +453,8 @@
if(iscrowbar(I)) // Prevent generation of infinite 'floor_tile' objs caused by the overridden make_plating() above never clearing the var
return
. = ..()
+ if(.)
+ return
if(iswrench(I))
user.visible_message(span_notice("[user] starts removing [src]'s protective cover."),
@@ -904,6 +915,46 @@
/turf/open/floor/carpet/side
icon_state = "carpetside"
+/turf/open/floor/carpet/blue
+ icon = 'icons/turf/floors/carpet_blue.dmi'
+ base_icon_state = "carpet_blue"
+ icon_state = "carpet_blue-0"
+
+/turf/open/floor/carpet/black
+ icon = 'icons/turf/floors/carpet_black.dmi'
+ base_icon_state = "carpet_black"
+ icon_state = "carpet_black-0"
+
+/turf/open/floor/carpet/green
+ icon = 'icons/turf/floors/carpet_green.dmi'
+ base_icon_state = "carpet_green"
+ icon_state = "carpet_green-0"
+
+/turf/open/floor/carpet/orange
+ icon = 'icons/turf/floors/carpet_orange.dmi'
+ base_icon_state = "carpet_orange"
+ icon_state = "carpet_orange-0"
+
+/turf/open/floor/carpet/purple
+ icon = 'icons/turf/floors/carpet_purple.dmi'
+ base_icon_state = "carpet_purple"
+ icon_state = "carpet_purple-0"
+
+/turf/open/floor/carpet/red
+ icon = 'icons/turf/floors/carpet_red.dmi'
+ base_icon_state = "carpet_red"
+ icon_state = "carpet_red-0"
+
+/turf/open/floor/carpet/cyan
+ icon = 'icons/turf/floors/carpet_cyan.dmi'
+ base_icon_state = "carpet_cyan"
+ icon_state = "carpet_cyan-0"
+
+/turf/open/floor/carpet/royalblack
+ icon = 'icons/turf/floors/carpet_royalblack.dmi'
+ base_icon_state = "carpet_royalblack"
+ icon_state = "carpet_royalblack-0"
+
// Start Prison tiles
/turf/open/floor/prison
diff --git a/code/game/turfs/iron_floor.dm b/code/game/turfs/iron_floor.dm
index 82aa6c55c2b4b..ad3a0c9dccb7b 100644
--- a/code/game/turfs/iron_floor.dm
+++ b/code/game/turfs/iron_floor.dm
@@ -233,8 +233,12 @@
/turf/open/floor/glass
name = "glass floor"
desc = "Don't jump on it, or do, I'm not your mom."
- icon = 'icons/turf/floors.dmi'
+ icon = 'icons/turf/floors/glass.dmi'
icon_state = "glass-0"
+ base_icon_state = "glass"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = list(SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
+ canSmoothWith = list(SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
/turf/open/floor/glass/reinforced
name = "reinforced glass floor"
@@ -242,7 +246,17 @@
icon = 'icons/turf/floors/reinf_glass.dmi'
icon_state = "reinf_glass-0"
base_icon_state = "reinf_glass"
- smoothing_flags = SMOOTH_BITMASK
- smoothing_groups = list(SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
- canSmoothWith = list(SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
+/turf/open/floor/glass/plasma
+ name = "plasma glass floor"
+ desc = "Studies by the Nanotrasen Materials Safety Division have not yet determined if this is safe to jump on, do so at your own risk."
+ icon = 'icons/turf/floors/plasma_glass.dmi'
+ icon_state = "plasma_glass-0"
+ base_icon_state = "plasma_glass"
+
+/turf/open/floor/glass/reinforced/plasma
+ name = "reinforced plasma glass floor"
+ desc = "Do jump on it, jump on it while in a mecha, it can take it."
+ icon = 'icons/turf/floors/reinf_plasma_glass.dmi'
+ icon_state = "reinf_plasma_glass-0"
+ base_icon_state = "reinf_plasma_glass"
diff --git a/code/game/turfs/liquid_turfs.dm b/code/game/turfs/liquid_turfs.dm
index 478141830307f..3b9826febceea 100644
--- a/code/game/turfs/liquid_turfs.dm
+++ b/code/game/turfs/liquid_turfs.dm
@@ -193,9 +193,6 @@
icon_state = "shallow_water_cave_waterway_edge"
// LAVA
-
-#define LAVA_TILE_BURN_DAMAGE 20
-
/turf/open/liquid/lava
name = "lava"
icon = 'icons/turf/lava.dmi'
@@ -214,7 +211,7 @@
. = ..()
var/turf/current_turf = get_turf(src)
if(current_turf && density)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
/turf/open/liquid/lava/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
@@ -232,40 +229,17 @@
if(!burn_stuff())
STOP_PROCESSING(SSobj, src)
-/* RUTGMC DELETION, FIRE JUMPING
+///Handles burning turf contents or an entering AM. Returns true to keep processing
/turf/open/liquid/lava/proc/burn_stuff(AM)
- . = FALSE
-
- var/thing_to_check = src
- if (AM)
- thing_to_check = list(AM)
- for(var/thing in thing_to_check)
- if(ismecha(thing))
- var/obj/vehicle/sealed/mecha/burned_mech = thing
- burned_mech.take_damage(rand(40, 120), BURN, FIRE)
+ var/thing_to_check = AM ? list(AM) : src
+ for(var/atom/thing AS in thing_to_check)
+ if(thing.lava_act())
. = TRUE
- else if(isobj(thing))
- var/obj/O = thing
- O.fire_act(10000, 1000)
-
- else if (isliving(thing))
- var/mob/living/L = thing
-
- if(L.stat == DEAD)
- continue
-
- if(!L.on_fire || L.getFireLoss() <= 200)
- var/damage_amount = max(L.modify_by_armor(LAVA_TILE_BURN_DAMAGE, FIRE), LAVA_TILE_BURN_DAMAGE * 0.3) //snowflakey interaction to stop complete lava immunity
- L.take_overall_damage(damage_amount, BURN, updating_health = TRUE, max_limbs = 3)
- if(!CHECK_BITFIELD(L.pass_flags, PASS_FIRE))//Pass fire allow to cross lava without igniting
- L.adjust_fire_stacks(20)
- L.IgniteMob()
- . = TRUE
-*/
-
/turf/open/liquid/lava/attackby(obj/item/C, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(C, /obj/item/stack/rods))
var/obj/item/stack/rods/R = C
var/turf/open/lavaland/catwalk/H = locate(/turf/open/lavaland/catwalk, src)
@@ -281,7 +255,7 @@
ChangeTurf(/turf/open/lavaland/catwalk/built)
var/turf/current_turf = get_turf(src)
if(current_turf && density)
- current_turf.flags_atom &= ~AI_BLOCKED
+ current_turf.atom_flags &= ~AI_BLOCKED
else
to_chat(user, span_warning("You need four rods to build a heatproof catwalk."))
return
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index 99078c58105ba..528eef1675364 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -146,6 +146,84 @@
/turf/open/shuttle/dropship/fourteen
icon_state = "floor6"
+/turf/open/shuttle/dropship/fourteen
+ icon_state = "rasputin14"
+
+/turf/open/shuttle/dropship/fifteen
+ icon_state = "rasputin15"
+
+/turf/open/shuttle/dropship/sixteen
+ icon_state = "rasputin16"
+
+/turf/open/shuttle/dropship/seventeen
+ icon_state = "rasputin17"
+
+/turf/open/shuttle/dropship/eighteen
+ icon_state = "rasputin18"
+
+/turf/open/shuttle/dropship/nineteen
+ icon_state = "rasputin19"
+
+/turf/open/shuttle/dropship/twenty
+ icon_state = "rasputin20"
+
+/turf/open/shuttle/dropship/twentyone
+ icon_state = "rasputin21"
+
+/turf/open/shuttle/dropship/twentytwo
+ icon_state = "rasputin22"
+
+/turf/open/shuttle/dropship/twentythree
+ icon_state = "rasputin23"
+
+/turf/open/shuttle/dropship/twentyfour
+ icon_state = "rasputin24"
+
+/turf/open/shuttle/dropship/twentyfive
+ icon_state = "rasputin25"
+
+/turf/open/shuttle/dropship/twentysix
+ icon_state = "rasputin26"
+
+/turf/open/shuttle/dropship/twentyseven
+ icon_state = "rasputin27"
+
+/turf/open/shuttle/dropship/twentyeight
+ icon_state = "rasputin28"
+
+/turf/open/shuttle/dropship/twentynine
+ icon_state = "rasputin29"
+
+/turf/open/shuttle/dropship/thirty
+ icon_state = "rasputin30"
+
+/turf/open/shuttle/dropship/thirtyone
+ icon_state = "rasputin31"
+
+/turf/open/shuttle/dropship/thirtytwo
+ icon_state = "rasputin32"
+
+/turf/open/shuttle/dropship/thirtythree
+ icon_state = "rasputin33"
+
+/turf/open/shuttle/dropship/thirtyfour
+ icon_state = "rasputin34"
+
+/turf/open/shuttle/dropship/thirtyfive
+ icon_state = "rasputin35"
+
+/turf/open/shuttle/dropship/thirtysix
+ icon_state = "rasputin36"
+
+/turf/open/shuttle/dropship/thirtyseven
+ icon_state = "rasputin37"
+
+/turf/open/shuttle/dropship/thirtyeight
+ icon_state = "rasputin38"
+
+/turf/open/shuttle/dropship/thirtynine
+ icon_state = "rasputin39"
+
/turf/open/shuttle/dropship/grating
icon = 'icons/turf/elevator.dmi'
icon_state = "floor_grating"
@@ -295,20 +373,20 @@
/turf/open/lavaland/catwalk/built
var/deconstructing = FALSE
-/turf/open/lavaland/catwalk/built/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/turf/open/lavaland/catwalk/built/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- if(X.a_intent != INTENT_HARM)
+ if(xeno_attacker.a_intent != INTENT_HARM)
return
if(deconstructing)
return
deconstructing = TRUE
- if(!do_after(X, 10 SECONDS, NONE, src, BUSY_ICON_BUILD))
+ if(!do_after(xeno_attacker, 10 SECONDS, NONE, src, BUSY_ICON_BUILD))
deconstructing = FALSE
return
deconstructing = FALSE
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
var/turf/current_turf = get_turf(src)
if(current_turf)
- current_turf.flags_atom |= AI_BLOCKED
+ current_turf.atom_flags |= AI_BLOCKED
ChangeTurf(/turf/open/liquid/lava)
diff --git a/code/game/turfs/open_ground.dm b/code/game/turfs/open_ground.dm
index 679b0c6bf99d6..8854410f7e02a 100644
--- a/code/game/turfs/open_ground.dm
+++ b/code/game/turfs/open_ground.dm
@@ -8,9 +8,10 @@
var/icon_variants = 1
/turf/open/ground/update_icon_state()
+ . = ..()
if(icon_variants < 2)
- return initial(icon_state)
- return "[initial(icon_state)]_[rand(1, icon_variants)]"
+ icon_state = initial(icon_state)
+ icon_state = "[initial(icon_state)]_[rand(1, icon_variants)]"
/turf/open/ground/AfterChange()
. = ..()
diff --git a/code/game/turfs/plating.dm b/code/game/turfs/plating.dm
index d985d51b26c5d..e9ed80d4f2311 100644
--- a/code/game/turfs/plating.dm
+++ b/code/game/turfs/plating.dm
@@ -100,6 +100,8 @@
/turf/open/floor/plating/plating_catwalk/attackby(obj/item/I, mob/user)
. = ..()
+ if(.)
+ return
if(iscrowbar(I))
if(covered)
var/obj/item/stack/catwalk/R = new(user.loc)
@@ -114,8 +116,6 @@
covered = TRUE
update_turf_overlay()
return
- return ..()
-
/turf/open/floor/plating/plating_catwalk/prison
icon = 'icons/turf/prison.dmi'
diff --git a/code/game/turfs/snow.dm b/code/game/turfs/snow.dm
index 7aa17da86e9fa..8e87c8aae64b8 100644
--- a/code/game/turfs/snow.dm
+++ b/code/game/turfs/snow.dm
@@ -6,7 +6,7 @@
/turf/open/floor/plating/ground/snow
name = "snow layer"
icon = 'icons/turf/snow2.dmi'
- icon_state = "snow_0"
+ icon_state = "snow_0_1"
hull_floor = TRUE
shoefootstep = FOOTSTEP_SNOW
barefootstep = FOOTSTEP_SNOW
@@ -16,15 +16,17 @@
/turf/open/floor/plating/ground/snow/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ATOM_ACIDSPRAY_ACT, PROC_REF(acidspray_act))
- update_icon(TRUE,TRUE) //Update icon and sides on start, but skip nearby check for turfs.
+ update_appearance()
+ update_sides()
// Melting snow
/turf/open/floor/plating/ground/snow/fire_act(exposed_temperature, exposed_volume)
slayer = 0
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
//Xenos digging up snow
-/turf/open/floor/plating/ground/snow/attack_alien(mob/living/carbon/xenomorph/M, damage_amount = M.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/turf/open/floor/plating/ground/snow/attack_alien(mob/living/carbon/xenomorph/M, damage_amount = M.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
if(M.status_flags & INCORPOREAL)
return
@@ -46,11 +48,14 @@
M.visible_message(span_notice("\The [M] clears out \the [src]."), \
span_notice("We clear out \the [src]."), null, 5)
slayer = 0
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
//PLACING/REMOVING/BUILDING
/turf/open/floor/plating/ground/snow/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
//Light Stick
if(istype(I, /obj/item/lightstick))
var/obj/item/lightstick/L = I
@@ -79,14 +84,13 @@
var/mob/living/carbon/xenomorph/xeno = arrived
if(xeno.is_charging >= CHARGE_ON) // chargers = snow plows
slayer = 0
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
return ..()
-//Update icon
-/turf/open/floor/plating/ground/snow/update_icon(update_full, skip_sides)
- icon_state = "snow_[slayer]"
- setDir(pick(GLOB.alldirs))
+/turf/open/floor/plating/ground/snow/update_name(updates)
+ . = ..()
switch(slayer)
if(0)
name = "dirt floor"
@@ -97,48 +101,50 @@
if(3)
name = "very deep [initial(name)]"
- //Update the side overlays
- if(update_full)
- var/turf/open/T
- if(!skip_sides)
- for(var/dirn in GLOB.alldirs)
- var/turf/open/floor/plating/ground/snow/D = get_step(src,dirn)
- if(istype(D))
- //Update turfs that are near us, but only once
- D.update_icon(TRUE, TRUE)
-
- overlays.Cut()
-
- for(var/dirn in GLOB.alldirs)
- T = get_step(src, dirn)
- if(istype(T))
- if(slayer > T.slayer && T.slayer < 1)
- var/image/I = new('icons/turf/snow2.dmi', "snow_[(dirn & (dirn-1)) ? "outercorner" : pick("innercorner", "outercorner")]", dir = dirn)
- switch(dirn)
- if(NORTH)
- I.pixel_y = 32
- if(SOUTH)
- I.pixel_y = -32
- if(EAST)
- I.pixel_x = 32
- if(WEST)
- I.pixel_x = -32
- if(NORTHEAST)
- I.pixel_x = 32
- I.pixel_y = 32
- if(SOUTHEAST)
- I.pixel_x = 32
- I.pixel_y = -32
- if(NORTHWEST)
- I.pixel_x = -32
- I.pixel_y = 32
- if(SOUTHWEST)
- I.pixel_x = -32
- I.pixel_y = -32
-
- I.layer = layer + 0.001 + slayer * 0.0001
- overlays += I
+/turf/open/floor/plating/ground/snow/update_overlays()
+ . = ..()
+ for(var/dirn in GLOB.alldirs)
+ var/turf/open/T = get_step(src, dirn)
+ if(!isopenturf(T))
+ continue
+ if(slayer > T.slayer && T.slayer < 1)
+ var/image/I = new('icons/turf/snow2.dmi', "snow_[(dirn & (dirn-1)) ? "outercorner" : pick("innercorner", "outercorner")]", dir = dirn)
+ switch(dirn)
+ if(NORTH)
+ I.pixel_y = 32
+ if(SOUTH)
+ I.pixel_y = -32
+ if(EAST)
+ I.pixel_x = 32
+ if(WEST)
+ I.pixel_x = -32
+ if(NORTHEAST)
+ I.pixel_x = 32
+ I.pixel_y = 32
+ if(SOUTHEAST)
+ I.pixel_x = 32
+ I.pixel_y = -32
+ if(NORTHWEST)
+ I.pixel_x = -32
+ I.pixel_y = 32
+ if(SOUTHWEST)
+ I.pixel_x = -32
+ I.pixel_y = -32
+
+ I.layer = layer + 0.001 + slayer * 0.0001
+ . += I
+
+/turf/open/floor/plating/ground/snow/update_icon_state()
+ . = ..()
+ icon_state = "snow_[slayer]_[rand(1,8)]"
+///Fully update all the turfs around us
+/turf/open/floor/plating/ground/snow/proc/update_sides()
+ for(var/dirn in GLOB.alldirs)
+ var/turf/open/floor/plating/ground/snow/D = get_step(src,dirn)
+ if(istype(D))
+ //Update turfs that are near us, but only once
+ D.update_appearance(ALL)
/* RUTGMC DELETION
//Explosion act
@@ -154,7 +160,8 @@
if(slayer && prob(20))
slayer = max(slayer - 1, 0)
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
return ..()
*/
@@ -171,7 +178,8 @@
if(25 to INFINITY)
slayer = 0
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
/turf/open/floor/plating/ground/snow/proc/acidspray_act()
SIGNAL_HANDLER
@@ -180,25 +188,26 @@
return
slayer = max(0, slayer - 1) //Melt a layer
- update_icon(TRUE, FALSE)
+ update_appearance()
+ update_sides()
//SNOW LAYERS-----------------------------------//
/turf/open/floor/plating/ground/snow/layer0
- icon_state = "snow_0"
+ icon_state = "snow_0_1"
slayer = 0
minimap_color = MINIMAP_DIRT
/turf/open/floor/plating/ground/snow/layer1
- icon_state = "snow_1"
+ icon_state = "snow_1_1"
slayer = 1
/turf/open/floor/plating/ground/snow/layer2
- icon_state = "snow_2"
+ icon_state = "snow_2_1"
slayer = 2
/turf/open/floor/plating/ground/snow/layer3
- icon_state = "snow_3"
+ icon_state = "snow_3_1"
slayer = 3
diff --git a/code/game/turfs/space.dm b/code/game/turfs/space.dm
index 7cb0bdea06775..dc4d6f1ea1681 100644
--- a/code/game/turfs/space.dm
+++ b/code/game/turfs/space.dm
@@ -33,9 +33,9 @@
*/
/turf/open/space/Initialize(mapload, ...)
SHOULD_CALL_PARENT(FALSE) //prevent laggies
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("Warning: [src]([type]) initialized multiple times!")
- ENABLE_BITFIELD(flags_atom, INITIALIZED)
+ ENABLE_BITFIELD(atom_flags, INITIALIZED)
icon_state = SPACE_ICON_STATE(x, y, z)
return INITIALIZE_HINT_NORMAL
@@ -55,6 +55,8 @@
/turf/open/space/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/stack/rods))
var/obj/structure/lattice/L = locate(/obj/structure/lattice) in src
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 3b9250e8e1462..2e46ef3ffacb2 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -89,9 +89,11 @@
transform = turn(matrix(), get_transit_angle(src))
/turf/open/space/transit/update_icon_state()
+ . = ..()
icon_state = "speedspace_ns_[get_transit_state(src, available_icon_state_amounts)]"
/turf/open/space/transit/atmos/update_icon_state()
+ . = ..()
icon_state = "Cloud_[get_transit_state(src, available_icon_state_amounts)]"
/proc/get_transit_state(turf/T, available_icon_state_amounts)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 05495684ea185..a0386837b5c79 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -59,9 +59,9 @@
/turf/Initialize(mapload)
SHOULD_CALL_PARENT(FALSE) // anti laggies
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("Warning: [src]([type]) initialized multiple times!")
- ENABLE_BITFIELD(flags_atom, INITIALIZED)
+ ENABLE_BITFIELD(atom_flags, INITIALIZED)
// by default, vis_contents is inherited from the turf that was here before
vis_contents.Cut()
@@ -130,7 +130,7 @@
B.vars[I] = null
return QDEL_HINT_IWILLGC
visibilityChanged()
- DISABLE_BITFIELD(flags_atom, INITIALIZED)
+ DISABLE_BITFIELD(atom_flags, INITIALIZED)
soft_armor = null
hard_armor = null
QDEL_NULL(current_acid)
@@ -180,7 +180,7 @@
return TRUE //We've entered the tile and gotten entangled inside it.
if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed.
return FALSE
- else if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_atom & ON_BORDER) && !(firstbump.flags_atom & ON_BORDER)))
+ else if(!firstbump || ((thing.layer > firstbump.layer || thing.atom_flags & ON_BORDER) && !(firstbump.atom_flags & ON_BORDER)))
firstbump = thing
if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed.
return FALSE
@@ -219,7 +219,7 @@
/turf/proc/levelupdate()
for(var/obj/O in src)
- if(O.flags_atom & INITIALIZED)
+ if(O.atom_flags & INITIALIZED)
SEND_SIGNAL(O, COMSIG_OBJ_HIDE, intact_tile)
@@ -534,7 +534,7 @@
*/
/turf/proc/check_disallow_alien_fortification(mob/living/builder, silent = FALSE)
var/area/ourarea = loc
- if(ourarea.flags_area & DISALLOW_WEEDING)
+ if(ourarea.area_flags & DISALLOW_WEEDING)
if(!silent)
to_chat(builder, span_warning("We cannot build in this area before the talls are out!"))
return FALSE
@@ -574,6 +574,9 @@
if(P.chair_state != DROPSHIP_CHAIR_BROKEN)
has_obstacle = TRUE
break
+ if(istype(O, /obj/structure/bed/chair/dropship/doublewide))
+ has_obstacle = TRUE
+ break
else if(istype(O, /obj/structure/bed/nest)) //We don't care about other beds/chairs/whatever the fuck.
has_obstacle = TRUE
break
@@ -585,7 +588,7 @@
has_obstacle = TRUE
break
- if(O.density && !(O.flags_atom & ON_BORDER))
+ if(O.density && !(O.atom_flags & ON_BORDER))
has_obstacle = TRUE
break
@@ -684,7 +687,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/turf/newT
if(flags & CHANGETURF_SKIP) // We haven't been initialized
- if(flags_atom & INITIALIZED)
+ if(atom_flags & INITIALIZED)
stack_trace("CHANGETURF_SKIP was used in a PlaceOnTop call for a turf that's initialized. This is a mistake. [src]([type])")
assemble_baseturfs()
if(fake_turf_type)
@@ -781,7 +784,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
// Removes all signs of lattice on the pos of the turf -Donkieyo
/turf/proc/RemoveLattice()
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
- if(L && (L.flags_atom & INITIALIZED))
+ if(L && (L.atom_flags & INITIALIZED))
qdel(L)
// A proc in case it needs to be recreated or badmins want to change the baseturfs
@@ -897,25 +900,25 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.highMovAtom[thing_in_turf] += list(src)
- if(thing_in_turf.flags_atom & PREVENT_CONTENTS_EXPLOSION)
+ if(thing_in_turf.atom_flags & PREVENT_CONTENTS_EXPLOSION)
continue
for(var/a in thing_in_turf.contents)
SSexplosions.highMovAtom[a] += list(src)
if(EXPLODE_HEAVY)
SSexplosions.medMovAtom[thing_in_turf] += list(src)
- if(thing_in_turf.flags_atom & PREVENT_CONTENTS_EXPLOSION)
+ if(thing_in_turf.atom_flags & PREVENT_CONTENTS_EXPLOSION)
continue
for(var/a in thing_in_turf.contents)
SSexplosions.medMovAtom[a] += list(src)
if(EXPLODE_LIGHT)
SSexplosions.lowMovAtom[thing_in_turf] += list(src)
- if(thing_in_turf.flags_atom & PREVENT_CONTENTS_EXPLOSION)
+ if(thing_in_turf.atom_flags & PREVENT_CONTENTS_EXPLOSION)
continue
for(var/a in thing_in_turf.contents)
SSexplosions.lowMovAtom[a] += list(src)
if(EXPLODE_WEAK)
SSexplosions.weakMovAtom[thing_in_turf] += list(src)
- if(thing_in_turf.flags_atom & PREVENT_CONTENTS_EXPLOSION)
+ if(thing_in_turf.atom_flags & PREVENT_CONTENTS_EXPLOSION)
continue
for(var/a in thing_in_turf.contents)
SSexplosions.weakMovAtom[a] += list(src)
diff --git a/code/game/turfs/walls/r_wall.dm b/code/game/turfs/walls/r_wall.dm
index 670207fe4a80a..1b5d130234e2a 100644
--- a/code/game/turfs/walls/r_wall.dm
+++ b/code/game/turfs/walls/r_wall.dm
@@ -13,6 +13,8 @@
walltype = "rwall"
explosion_block = 4
+ soft_armor = list(MELEE = 0, BULLET = 80, LASER = 80, ENERGY = 100, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
+
/turf/closed/wall/r_wall/get_acid_delay()
return 10 SECONDS
diff --git a/code/game/turfs/walls/resin.dm b/code/game/turfs/walls/resin.dm
index 3f3d0e97fca59..b2e857ff65395 100644
--- a/code/game/turfs/walls/resin.dm
+++ b/code/game/turfs/walls/resin.dm
@@ -15,9 +15,13 @@
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = list(SMOOTH_GROUP_XENO_STRUCTURES)
canSmoothWith = list(SMOOTH_GROUP_XENO_STRUCTURES)
- soft_armor = list(MELEE = 0, BULLET = 70, LASER = 60, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
+ soft_armor = list(MELEE = 0, BULLET = 80, LASER = 75, ENERGY = 75, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
+ hard_armor = list(MELEE = 0, BULLET = 15, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
resistance_flags = UNACIDABLE
+ //Used for quickbuild refunding.
+ var/is_normal_resin_wall = TRUE
+
/turf/closed/wall/resin/add_debris_element()
AddElement(/datum/element/debris, null, -15, 8, 0.7)
@@ -86,21 +90,22 @@
take_damage(rand(30, 50), BRUTE, BOMB)
/* RUTGMC DELETION
-/turf/closed/wall/resin/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
- return
- if(CHECK_BITFIELD(SSticker.mode?.flags_round_type, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active)
- SSresinshaping.quickbuild_points_by_hive[X.hivenumber]++
- take_damage(max_integrity) // Ensure its destroyed
+/turf/closed/wall/resin/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- X.visible_message(span_xenonotice("\The [X] starts tearing down \the [src]!"), \
+ if(CHECK_BITFIELD(SSticker.mode?.round_type_flags, MODE_ALLOW_XENO_QUICKBUILD) && SSresinshaping.active)
+ if(is_normal_resin_wall)
+ SSresinshaping.quickbuild_points_by_hive[xeno_attacker.hivenumber]++
+ take_damage(max_integrity) // Ensure its destroyed
+ return
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] starts tearing down \the [src]!"), \
span_xenonotice("We start to tear down \the [src]."))
- if(!do_after(X, 1 SECONDS, NONE, X, BUSY_ICON_GENERIC))
+ if(!do_after(xeno_attacker, 1 SECONDS, NONE, xeno_attacker, BUSY_ICON_GENERIC))
return
if(!istype(src)) // Prevent jumping to other turfs if do_after completes with the wall already gone
return
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- X.visible_message(span_xenonotice("\The [X] tears down \the [src]!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] tears down \the [src]!"), \
span_xenonotice("We tear down \the [src]."))
playsound(src, "alien_resin_break", 25)
take_damage(max_integrity) // Ensure its destroyed
@@ -112,7 +117,7 @@
/turf/closed/wall/resin/attackby(obj/item/I, mob/living/user, params)
- if(I.flags_item & NOBLUDGEON || !isliving(user))
+ if(I.item_flags & NOBLUDGEON || !isliving(user))
return
user.changeNext_move(I.attack_speed)
@@ -122,8 +127,10 @@
var/multiplier = 1
if(I.damtype == BURN) //Burn damage deals extra vs resin structures (mostly welders).
multiplier += 1
+ else if(I.damtype == BRUTE)
+ multiplier += 0.75
- if(istype(I, /obj/item/tool/pickaxe/plasmacutter) && !user.do_actions)
+ if(isplasmacutter(I) && !user.do_actions)
var/obj/item/tool/pickaxe/plasmacutter/P = I
if(P.start_cut(user, name, src, PLASMACUTTER_BASE_COST * PLASMACUTTER_VLOW_MOD))
multiplier += PLASMACUTTER_RESIN_MULTIPLIER
@@ -152,14 +159,14 @@
* Regenerating walls that start with lower health, but grow to a much higher hp over time
*/
/turf/closed/wall/resin/regenerating
- max_integrity = 150
+ max_integrity = 75
/// Total health possible for a wall after regenerating at max health
var/max_upgradable_health = 300
/// How much the walls integrity heals per tick (5 seconds)
var/heal_per_tick = 25
/// How much the walls max_integrity increases per tick (5 seconds)
- var/max_upgrade_per_tick = 3
+ var/max_upgrade_per_tick = 6
/// How long should the wall stop healing for when taking dmg
var/cooldown_on_taking_dmg = 30 SECONDS
///Whether we have a timer already to stop from clogging up the timer ss
@@ -202,4 +209,27 @@
/* Hivelord walls, they start off stronger */
/turf/closed/wall/resin/regenerating/thick
- max_integrity = 250
+ max_integrity = 125
+
+/turf/closed/wall/resin/regenerating/special
+ name = "you shouldn't see this"
+ is_normal_resin_wall = FALSE
+
+/turf/closed/wall/resin/regenerating/special/bulletproof
+ name = "bulletproof resin wall"
+ desc = "Weird slime solidified into a wall. Looks shiny."
+ soft_armor = list(MELEE = 0, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0) //You aren't damaging this with bullets without alot of AP.
+ color = COLLOR_WALL_BULLETPROOF
+
+/turf/closed/wall/resin/regenerating/special/fireproof
+ name = "fireproof resin wall"
+ desc = "Weird slime solidified into a wall. Very red."
+ soft_armor = list(MELEE = 0, BULLET = 80, LASER = 75, ENERGY = 75, BOMB = 0, BIO = 0, FIRE = 200, ACID = 0)
+ color = COLOR_WALL_FIREPROOF
+
+/turf/closed/wall/resin/regenerating/special/hardy
+ name = "hardy resin wall"
+ desc = "Weird slime soldified into a wall. Looks very strong."
+ max_upgradable_health = 450
+ max_upgrade_per_tick = 12 //Upgrades faster, but if damaged at all it will be put on cooldown still to help against walling in combat.
+ color = COLOR_WALL_HARDY
diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm
index d33199e9f5a81..5805499cfd637 100644
--- a/code/game/turfs/walls/wall_types.dm
+++ b/code/game/turfs/walls/wall_types.dm
@@ -244,7 +244,7 @@
return
/turf/closed/wall/indestructible/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/tool/pickaxe/plasmacutter)) //needed for user feedback, if not included the user will not receive a message when trying plasma cutter wall/indestructible turfs
+ if(isplasmacutter(I)) //needed for user feedback, if not included the user will not receive a message when trying plasma cutter wall/indestructible turfs
var/obj/item/tool/pickaxe/plasmacutter/P = I
to_chat(user, span_warning("[P] can't cut through this!"))
return
diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm
index da7d61af4f36c..73de916a871c2 100644
--- a/code/game/turfs/walls/walls.dm
+++ b/code/game/turfs/walls/walls.dm
@@ -16,13 +16,8 @@
var/wall_integrity
var/max_integrity = 1000 //Wall will break down to girders if damage reaches this point
- var/damage_overlay
var/global/damage_overlays[8]
- var/current_bulletholes = 0
- var/bullethole_increment = 1
- var/bullethole_state = 0
- var/image/bullethole_overlay
base_icon_state = "metal"
var/max_temperature = 1800 //K, walls will take damage if they're next to a fire hotter than this
@@ -31,6 +26,18 @@
var/obj/effect/acid_hole/acided_hole //the acid hole inside the wall
+ ///The current number of bulletholes in this turf
+ var/current_bulletholes = 0
+ ///A reference to the current bullethole overlay image, this is added and deleted as needed
+ var/image/bullethole_overlay
+ /**
+ * The variation set we're using
+ * There are 10 sets and it gets picked randomly the first time a wall is shot
+ * It corresponds to the first number in the icon_state (bhole_[**bullethole_variation**]_[current_bulletholes])
+ * Gets reset to 0 if the wall reaches maximum health, so a new variation is picked when the wall gets shot again
+ */
+ var/bullethole_variation = 0
+
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = list(
SMOOTH_GROUP_CLOSED_TURFS,
@@ -59,6 +66,10 @@
visible_message(span_warning("\The [M] is sealed inside the wall as it is built"))
qdel(M)
+/turf/closed/wall/Destroy(force)
+ QDEL_NULL(acided_hole)
+ QDEL_NULL(bullethole_overlay)
+ return ..()
/turf/closed/wall/ChangeTurf(newtype)
if(acided_hole)
@@ -101,11 +112,11 @@
..()
-/turf/closed/wall/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/turf/closed/wall/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- if(acided_hole && (X.mob_size == MOB_SIZE_BIG || X.xeno_caste.caste_flags & CASTE_IS_STRONG)) //Strong and/or big xenos can tear open acided walls
- acided_hole.expand_hole(X)
+ if(acided_hole && (xeno_attacker.mob_size == MOB_SIZE_BIG || xeno_attacker.xeno_caste.caste_flags & CASTE_IS_STRONG)) //Strong and/or big xenos can tear open acided walls
+ acided_hole.expand_hole(xeno_attacker)
else
return ..()
@@ -150,81 +161,45 @@
if(7)
. += span_info("The inner sheath is gone. A blowtorch should finish off this wall.")
-#define BULLETHOLE_STATES 10 //How many variations of bullethole patterns there are
-#define BULLETHOLE_MAX 8 * 3 //Maximum possible bullet holes.
-//Formulas. These don't need to be defines, but helpful green. Should likely reuse these for a base 8 icon system.
-#define cur_increment(v) round((v-1)/8)+1
-#define base_dir(v,i) v-(i-1)*8
-#define cur_dir(v) round(v+round(v)/3)
+/turf/closed/wall/update_overlays()
+ . = ..()
+ if(wall_integrity == max_integrity)
+ current_bulletholes = 0
+ bullethole_variation = 0
+ QDEL_NULL(bullethole_overlay)
+ return
-/turf/closed/wall/update_icon()
if(!damage_overlays[1]) //list hasn't been populated
- generate_overlays()
-
- if(wall_integrity == max_integrity) //If the thing was healed for damage; otherwise update_icon() won't run at all, unless it was strictly damaged.
- overlays.Cut()
- damage_overlay = initial(damage_overlay)
- current_bulletholes = initial(current_bulletholes)
- bullethole_increment = initial(current_bulletholes)
- bullethole_state = initial(current_bulletholes)
- qdel(bullethole_overlay)
- bullethole_overlay = null
- return
+ var/alpha_inc = 256 / length(damage_overlays)
- var/overlay = round((max_integrity - wall_integrity) / max_integrity * length(damage_overlays)) + 1
- if(overlay > length(damage_overlays)) overlay = length(damage_overlays)
+ for(var/i = 1; i <= length(damage_overlays); i++)
+ var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage")
+ img.blend_mode = BLEND_MULTIPLY
+ img.alpha = (i * alpha_inc) - 1
+ damage_overlays[i] = img
- if(!damage_overlay || overlay != damage_overlay)
- overlays -= damage_overlays[damage_overlay]
- damage_overlay = overlay
- overlays += damage_overlays[damage_overlay]
+ var/overlay = round((max_integrity - wall_integrity) / max_integrity * length(damage_overlays)) + 1
+ if(overlay > length(damage_overlays))
+ overlay = length(damage_overlays)
- if(current_bulletholes > BULLETHOLE_MAX) //Could probably get away with a unique layer, but let's keep it standardized.
- overlays -= bullethole_overlay //We need this to be the top layer, no matter what, but only if the layer is at max bulletholes.
- overlays += bullethole_overlay
+ . += damage_overlays[overlay]
if(current_bulletholes && current_bulletholes <= BULLETHOLE_MAX)
- overlays -= bullethole_overlay
- if(!bullethole_overlay)
- bullethole_state = rand(1, BULLETHOLE_STATES)
- bullethole_overlay = image('icons/effects/bulletholes.dmi', src, "bhole_[bullethole_state]_[bullethole_increment]")
- //for(var/mob/M in view(7)) to_chat(M, bullethole_overlay)
- if(cur_increment(current_bulletholes) > bullethole_increment) bullethole_overlay.icon_state = "bhole_[bullethole_state]_[++bullethole_increment]"
-
- var/base_direction = base_dir(current_bulletholes,bullethole_increment)
- var/current_direction = cur_dir(base_direction)
- setDir(current_direction)
- /*Hack. Image overlays behave as the parent object, so that means they are also attached to it and follow its directional.
- Luckily, it doesn't matter what direction the walls are set to, they link together via icon_state it seems.
- But I haven't thoroughly tested it.*/
- overlays += bullethole_overlay
- //to_chat(world, span_debuginfo("Increment: [bullethole_increment], Direction: [current_direction]"))
-
-#undef BULLETHOLE_STATES
-#undef BULLETHOLE_MAX
-#undef cur_increment
-#undef base_dir
-#undef cur_dir
-
-/turf/closed/wall/proc/generate_overlays()
- var/alpha_inc = 256 / length(damage_overlays)
-
- for(var/i = 1; i <= length(damage_overlays); i++)
- var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage")
- img.blend_mode = BLEND_MULTIPLY
- img.alpha = (i * alpha_inc) - 1
- damage_overlays[i] = img
+ if(!bullethole_variation)
+ bullethole_variation = rand(1, BULLETHOLE_STATES)
+ bullethole_overlay = image('icons/effects/bulletholes.dmi', src, "bhole_[bullethole_variation]_[current_bulletholes]")
+ . += bullethole_overlay
///Applies damage to the wall
-/turf/closed/wall/proc/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", armour_penetration = 0)
+/turf/closed/wall/proc/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, armour_penetration = 0)
if(resistance_flags & INDESTRUCTIBLE) //Hull is literally invincible
return
if(!damage_amount)
return
- if(damage_flag)
- damage_amount = modify_by_armor(damage_amount, damage_flag, armour_penetration)
+ if(armor_type)
+ damage_amount = modify_by_armor(damage_amount, armor_type, armour_penetration)
wall_integrity = max(0, wall_integrity - damage_amount)
@@ -315,6 +290,8 @@
/turf/closed/wall/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!ishuman(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
@@ -353,7 +330,7 @@
else if(resistance_flags & INDESTRUCTIBLE)
to_chat(user, "[span_warning("[src] is much too tough for you to do anything to it with [I]")].")
- else if(istype(I, /obj/item/tool/pickaxe/plasmacutter) && !user.do_actions)
+ else if(isplasmacutter(I) && !user.do_actions)
return
else if(wall_integrity < max_integrity && iswelder(I))
@@ -522,3 +499,34 @@
/turf/closed/wall/dissolvability(acid_strength)
return 0.5
+
+/turf/closed/wall/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_WALL_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!isliving(grab.grabbed_thing))
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ step_towards(grabbed_mob, src)
+ var/damage = (user.skills.getRating(SKILL_CQC) * CQC_SKILL_DAMAGE_MOD)
+ var/state = user.grab_state
+ switch(state)
+ if(GRAB_PASSIVE)
+ damage += base_damage
+ grabbed_mob.visible_message(span_warning("[user] slams [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "slammed", "", "against [src]")
+ if(GRAB_AGGRESSIVE)
+ damage += base_damage * 1.5
+ grabbed_mob.visible_message(span_danger("[user] bashes [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "bashed", "", "against [src]")
+ if(prob(50))
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.drop_held_item()
+ if(GRAB_NECK)
+ damage += base_damage * 2
+ grabbed_mob.visible_message(span_danger("[user] crushes [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "crushed", "", "against [src]")
+ grabbed_mob.Paralyze(2 SECONDS)
+ user.drop_held_item()
+ grabbed_mob.apply_damage(damage, blocked = MELEE, updating_health = TRUE)
+ take_damage(damage, BRUTE, MELEE)
+ playsound(src, 'sound/weapons/heavyhit.ogg', 40)
+ return TRUE
diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm
index be8f8fb6b3253..9a5e144de5ab5 100644
--- a/code/modules/admin/admin_ranks.dm
+++ b/code/modules/admin/admin_ranks.dm
@@ -82,6 +82,8 @@
flag = R_DBRANKS
if("LOG")
flag = R_LOG
+ if("POLLS")
+ flag = R_POLLS
if("EVERYTHING")
flag = R_EVERYTHING
if("@")
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 5d136bb5acf61..9ca6f86458135 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -196,6 +196,14 @@
log_admin("[key_name(usr)] revived [key_name(L)].")
message_admins("[ADMIN_TPMONTY(usr)] revived [ADMIN_TPMONTY(L)].")
+/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list)
+ set category = "Debug"
+ set name = "Check Contents"
+
+ var/list/L = M.GetAllContents()
+ for(var/t in L)
+ to_chat(usr, "[t] [ADMIN_VV(t)] [ADMIN_TAG(t)]", confidential = TRUE)
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Contents") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
/datum/admins/proc/toggle_sleep(mob/living/L in GLOB.mob_living_list)
set category = null
@@ -615,6 +623,17 @@
else if(C.mob.stat == DEAD && (C.prefs.toggles_chat & CHAT_DEAD))
to_chat(C, msg)
+/client/proc/object_say(obj/O in world)
+ set category = "Admin"
+ set name = "OSay"
+ set desc = "Makes an object say something."
+ var/message = tgui_input_text(usr, "What do you want the message to be?", "Make Sound", encode = FALSE)
+ if(!message)
+ return
+ O.say(message, sanitize = FALSE)
+ log_admin("[key_name(usr)] made [O] at [AREACOORD(O)] say \"[message]\"")
+ message_admins(span_adminnotice("[key_name_admin(usr)] made [O] at [AREACOORD(O)]. say \"[message]\""))
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Object Say") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
/datum/admins/proc/jump()
set category = "Admin"
@@ -1213,11 +1232,11 @@
if(!check_rights(R_ADMIN))
return
- for(var/obj/vehicle/multitile/root/cm_armored/CA AS in GLOB.tank_list)
- CA.remove_all_players()
+ for(var/obj/vehicle/sealed/armored/armor AS in GLOB.tank_list)
+ armor.dump_mobs(TRUE)
- log_admin("[key_name(usr)] forcibly removed all players from [CA].")
- message_admins("[ADMIN_TPMONTY(usr)] forcibly removed all players from [CA].")
+ log_admin("[key_name(usr)] forcibly removed all players from [armor].")
+ message_admins("[ADMIN_TPMONTY(usr)] forcibly removed all players from [armor].")
/// Admin verb to delete a squad completely
/datum/admins/proc/delete_squad()
diff --git a/code/modules/admin/callproc.dm b/code/modules/admin/callproc.dm
index d17d109c55395..f26b0ee09e72e 100644
--- a/code/modules/admin/callproc.dm
+++ b/code/modules/admin/callproc.dm
@@ -86,185 +86,102 @@ GLOBAL_PROTECT(AdminProcCallHandler)
usr = lastusr
handler.remove_caller(user)
-GLOBAL_VAR(AdminProcCaller)
-GLOBAL_PROTECT(AdminProcCaller)
-GLOBAL_VAR_INIT(AdminProcCallCount, FALSE)
-GLOBAL_PROTECT(AdminProcCallCount)
-GLOBAL_VAR(LastAdminCalledTargetRef)
-GLOBAL_PROTECT(LastAdminCalledTargetRef)
-GLOBAL_VAR(LastAdminCalledTarget)
-GLOBAL_PROTECT(LastAdminCalledTarget)
-GLOBAL_VAR(LastAdminCalledProc)
-GLOBAL_PROTECT(LastAdminCalledProc)
-GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
-GLOBAL_PROTECT(AdminProcCallSpamPrevention)
-
-
-/datum/admins/proc/proccall_atom(datum/A as null|area|mob|obj|turf)
- set category = null
- set name = "Atom ProcCall"
- set waitfor = FALSE
-
- if(!check_rights(R_DEBUG))
- return
-
- /// Holds a reference to the client incase something happens to them
- var/client/starting_client = usr.client
-
- var/procname = input("Proc name, eg: attack_hand", "Proc:", null) as text|null
- if(!procname)
- return
-
- if(!hascall(A, procname))
- to_chat(starting_client, "Error: callproc_datum(): type [A.type] has no proc named [procname].")
- return
-
- var/list/lst = starting_client.holder.get_callproc_args()
- if(!lst)
- return
-
- if(!A || !IsValidSrc(A))
- to_chat(starting_client, span_warning("Error: callproc_datum(): owner of proc no longer exists."))
- return
-
- log_admin("[key_name(usr)] called [A]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- message_admins("[ADMIN_TPMONTY(usr)] called [A]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- admin_ticket_log(A, "[key_name_admin(usr)] called [A]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
-
- var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
- . = starting_client.holder.get_callproc_returnval(returnval, procname)
- if(.)
- to_chat(usr, .)
-
-
-/datum/admins/proc/proccall_advanced()
+/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
set waitfor = FALSE
+ callproc_blocking()
+/client/proc/callproc_blocking(list/get_retval)
if(!check_rights(R_DEBUG))
return
- var/datum/target = null
- var/targetselected = 0
- var/returnval = null
+ var/datum/target
+ var/targetselected = FALSE
+ var/returnval
- switch(alert("Proc owned by something?",, "Yes", "No"))
+ switch(tgui_alert(usr,"Proc owned by something?",,list("Yes","No")))
if("Yes")
targetselected = TRUE
- var/list/value = usr.client.vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT))
- if(!value["class"] || !value["value"])
+ var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT, VV_MARKED_DATUM, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL))
+ if (!value["class"] || !value["value"])
return
target = value["value"]
+ if(!istype(target))
+ to_chat(usr, span_danger("Invalid target."), confidential = TRUE)
+ return
if("No")
target = null
targetselected = FALSE
- var/procname = input("Proc path, eg: /proc/attack_hand(mob/living/user)")
- if(!procname)
+ var/procpath = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
+ if(!procpath)
return
//strip away everything but the proc name
- var/list/proclist = splittext(procname, "/")
- if(!length(proclist))
+ var/list/proclist = splittext(procpath, "/")
+ if (!length(proclist))
return
- procname = proclist[length(proclist)]
-
- var/proctype = "proc"
- if("verb" in proclist)
- proctype = "verb"
-
+ var/procname = proclist[proclist.len]
+ var/proctype = ("verb" in proclist) ? "verb" :"proc"
- var/procpath
- if(targetselected && !hascall(target, procname))
- to_chat(usr,
- type = MESSAGE_TYPE_DEBUG,
- html = "Error: callproc(): type [target.type] has no [proctype] named [procname].",)
- return
- else if(!targetselected)
- procpath = text2path("/[proctype]/[procname]")
- if(!procpath)
- to_chat(usr,
- type = MESSAGE_TYPE_DEBUG,
- html = "Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)")
+ if(targetselected)
+ if(!hascall(target, procname))
+ to_chat(usr, span_warning("Error: callproc(): type [target.type] has no [proctype] named [procpath]."), confidential = TRUE)
+ return
+ else
+ procpath = "/[proctype]/[procname]"
+ if(!text2path(procpath))
+ to_chat(usr, span_warning("Error: callproc(): [procpath] does not exist."), confidential = TRUE)
return
- var/list/lst = usr.client.holder.get_callproc_args()
+ var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
- to_chat(usr,
- type = MESSAGE_TYPE_DEBUG,
- html = "Error: callproc(): owner of proc no longer exists.")
+ to_chat(usr, "Error: callproc(): owner of proc no longer exists.", confidential = TRUE)
return
- log_admin("[key_name(usr)] called [target]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- message_admins("[ADMIN_TPMONTY(usr)] called [target]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- admin_ticket_log(target, "[key_name(usr)] called [target]'s [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
+ var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
+ log_admin(msg)
+ message_admins(msg) //Proccall announce removed.
+ admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
- log_admin("[key_name(usr)] called [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- message_admins("[ADMIN_TPMONTY(usr)] called [procname]() with [length(lst) ? "the arguments [list2params(lst)]" : "no arguments"].")
- returnval = WrapAdminProcCall(GLOBAL_PROC, procpath, lst) // Pass the lst as an argument list to the proc
-
- . = usr.client.holder.get_callproc_returnval(returnval, procname)
+ log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
+ message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
+ returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
+ if(get_retval)
+ get_retval += returnval
+ . = get_callproc_returnval(returnval, procname)
if(.)
- to_chat(usr, .)
-
-
-/datum/admins/proc/get_callproc_returnval(returnval, procname)
- . = ""
- if(islist(returnval))
- var/list/returnedlist = returnval
- . = ""
- if(length(returnedlist))
- var/assoc_check = returnedlist[1]
- if(istext(assoc_check) && (returnedlist[assoc_check] != null))
- . += "[procname] returned an associative list:"
- for(var/key in returnedlist)
- . += "\n[key] = [returnedlist[key]]"
+ to_chat(usr, ., confidential = TRUE)
- else
- . += "[procname] returned a list:"
- for(var/elem in returnedlist)
- . += "\n[elem]"
- else
- . = "[procname] returned an empty list"
- . += ""
-
- else
- . = "[procname] returned: [!isnull(returnval) ? returnval : "null"]"
-
-
-/datum/admins/proc/get_callproc_args()
- var/argnum = input("Number of arguments", "Number:", 0) as num|null
- if(isnull(argnum))
- return
-
- . = list()
- var/list/named_args = list()
- while(argnum--)
- var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
- var/value = usr.client.vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
- if (!value["class"])
- return
- if(named_arg)
- named_args[named_arg] = value["value"]
- else
- . += value["value"]
- if(LAZYLEN(named_args))
- . += named_args
+GLOBAL_VAR(AdminProcCaller)
+GLOBAL_PROTECT(AdminProcCaller)
+GLOBAL_VAR_INIT(AdminProcCallCount, FALSE)
+GLOBAL_PROTECT(AdminProcCallCount)
+GLOBAL_VAR(LastAdminCalledTargetRef)
+GLOBAL_PROTECT(LastAdminCalledTargetRef)
+GLOBAL_VAR(LastAdminCalledTarget)
+GLOBAL_PROTECT(LastAdminCalledTarget)
+GLOBAL_VAR(LastAdminCalledProc)
+GLOBAL_PROTECT(LastAdminCalledProc)
+GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
+GLOBAL_PROTECT(AdminProcCallSpamPrevention)
+/// Wrapper for proccalls where the datum is flagged as vareditted
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target && procname == "Del")
- to_chat(usr, "Calling Del() is not allowed")
+ to_chat(usr, "Calling Del() is not allowed", confidential = TRUE)
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
- to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
+ to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!", confidential = TRUE)
return
var/current_caller = GLOB.AdminProcCaller
var/user_identifier = usr ? usr.client?.ckey : GLOB.AdminProcCaller
@@ -276,7 +193,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(!is_remote_handler && current_caller && current_caller != user_identifier)
- to_chat(usr, span_adminnotice("Another set of admin called procs are still running. Try again later."))
+ to_chat(usr, span_adminnotice("Another set of admin called procs are still running. Try again later."), confidential = TRUE)
return
GLOB.LastAdminCalledProc = procname
@@ -293,15 +210,14 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
else
. = world.WrapAdminProcCall(target, procname, arguments)
-
+//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
- return call(procname)(arglist(arguments))
+ return call("/proc/[procname]")(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
- log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
-
+ log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
@@ -309,3 +225,77 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
#else
return (GLOB.AdminProcCaller && GLOB.AdminProcCaller == usr?.client?.ckey) || (GLOB.AdminProcCallHandler && usr == GLOB.AdminProcCallHandler)
#endif
+
+/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
+ set category = "Debug"
+ set name = "Atom ProcCall"
+ set waitfor = FALSE
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
+ if(!procname)
+ return
+ if(!hascall(A,procname))
+ to_chat(usr, "Error: callproc_datum(): type [A.type] has no proc named [procname].", confidential = TRUE)
+ return
+ var/list/lst = get_callproc_args()
+ if(!lst)
+ return
+
+ if(!A || !is_valid_src(A))
+ to_chat(usr, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE)
+ return
+ log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
+ var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
+ message_admins(msg)
+ admin_ticket_log(A, msg)
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
+
+ var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
+ . = get_callproc_returnval(returnval,procname)
+ if(.)
+ to_chat(usr, ., confidential = TRUE)
+
+/client/proc/get_callproc_args()
+ var/argnum = input("Number of arguments","Number:",0) as num|null
+ if(isnull(argnum))
+ return
+
+ . = list()
+ var/list/named_args = list()
+ while(argnum--)
+ var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
+ var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
+ if (!value["class"])
+ return
+ if(named_arg)
+ named_args[named_arg] = value["value"]
+ else
+ . += LIST_VALUE_WRAP_LISTS(value["value"])
+ if(LAZYLEN(named_args))
+ . += named_args
+
+/client/proc/get_callproc_returnval(returnval,procname)
+ . = ""
+ if(islist(returnval))
+ var/list/returnedlist = returnval
+ . = ""
+ if(returnedlist.len)
+ var/assoc_check = returnedlist[1]
+ if(istext(assoc_check) && (returnedlist[assoc_check] != null))
+ . += "[procname] returned an associative list:"
+ for(var/key in returnedlist)
+ . += "\n[key] = [returnedlist[key]]"
+
+ else
+ . += "[procname] returned a list:"
+ for(var/elem in returnedlist)
+ . += "\n[elem]"
+ else
+ . = "[procname] returned an empty list"
+ . += ""
+
+ else
+ . = "[procname] returned: [!isnull(returnval) ? html_encode(returnval) : "null"]"
diff --git a/code/modules/admin/debug_verbs.dm b/code/modules/admin/debug_verbs.dm
index 58a94264185ac..6112387515e61 100644
--- a/code/modules/admin/debug_verbs.dm
+++ b/code/modules/admin/debug_verbs.dm
@@ -158,7 +158,7 @@
else
for(var/i in 1 to amount)
var/atom/A = new chosen(T)
- A.flags_atom |= ADMIN_SPAWNED
+ A.atom_flags |= ADMIN_SPAWNED
log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -247,7 +247,7 @@
return
var/dat = " "
- for(var/i in L.get_contents())
+ for(var/i in L.GetAllContents())
var/atom/A = i
dat += "[A] [ADMIN_VV(A)] "
diff --git a/code/modules/admin/fun_verbs.dm b/code/modules/admin/fun_verbs.dm
index 9ac5cfc7413a9..26d9ccf0a5d57 100644
--- a/code/modules/admin/fun_verbs.dm
+++ b/code/modules/admin/fun_verbs.dm
@@ -54,16 +54,19 @@
if(!check_rights(R_FUN))
return
- var/customname = tgui_input_text(usr, "What do you want it to be called?.", "Queen Mother Report", "Queen Mother", encode = FALSE)
+ var/customname = tgui_input_text(usr, "What do you want the title of this report to be?", "Report Title", "Queen Mother Directive", encode = FALSE)
var/input = tgui_input_text(usr, "This should be a message from the ruler of the Xenomorph race.", "Queen Mother Report", "", multiline = TRUE, encode = FALSE)
if(!input || !customname)
return
- var/msg = "
[customname]
[span_warning("[input]")]
"
for(var/i in (GLOB.xeno_mob_list + GLOB.observer_list))
var/mob/M = i
- to_chat(M, msg)
+ to_chat(M, assemble_alert(
+ title = customname,
+ message = input,
+ color_override = "purple"
+ ))
log_admin("[key_name(usr)] created a Queen Mother report: [input]")
message_admins("[ADMIN_TPMONTY(usr)] created a Queen Mother report.")
@@ -79,7 +82,7 @@
for(var/mob/living/carbon/xenomorph/xenotorouny in GLOB.xeno_mob_list)
if(!isliving(xenotorouny))
return
- xenotorouny.is_a_rouny = !xenotorouny.is_a_rouny
+ xenotorouny.xeno_flags ^= XENO_ROUNY
/datum/admins/proc/hive_status()
@@ -137,7 +140,9 @@
var/customname = tgui_input_text(usr, "Pick a title for the report.", "Title", "TGMC Update", encode = FALSE)
+ var/customsubtitle = tgui_input_text(usr, "Pick a subtitle for the report.", "Subtitle", "", encode = FALSE)
var/input = tgui_input_text(usr, "Please enter anything you want. Anything. Serious.", "What?", "", multiline = TRUE, encode = FALSE)
+ var/override = tgui_input_list(usr, "Pick a color for the report.", "Color", faction_alert_colors - "default", default = "blue")
if(!input || !customname)
return
@@ -147,9 +152,9 @@
switch(tgui_alert(usr, "Should this be announced to the general population?", "Announce", list("Yes", "No", "Cancel")))
if("Yes")
- priority_announce(input, customname, sound = 'sound/AI/commandreport.ogg');
+ priority_announce(input, customname, customsubtitle, sound = 'sound/AI/commandreport.ogg', color_override = override);
if("No")
- priority_announce("New update available at all communication consoles.", type = ANNOUNCEMENT_COMMAND, sound = 'sound/AI/commandreport.ogg')
+ priority_announce("New update available at all communication consoles.", "Classified Transmission Received", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/commandreport.ogg')
else
return
@@ -284,8 +289,12 @@
GLOB.custom_info = new_info
- to_chat(world, "
Custom Information
")
- to_chat(world, span_alert("[GLOB.custom_info]"))
+ to_chat(world, assemble_alert(
+ title = "Custom Information",
+ subtitle = "The following custom information has been set for this round.",
+ message = GLOB.custom_info,
+ color_override = "red"
+ ))
log_admin("[key_name(usr)] has changed the custom event text: [GLOB.custom_info]")
message_admins("[ADMIN_TPMONTY(usr)] has changed the custom event text.")
@@ -299,8 +308,12 @@
to_chat(src, span_notice("There currently is no custom information set."))
return
- to_chat(src, "
Custom Information
")
- to_chat(src, span_alert("[GLOB.custom_info]"))
+ to_chat(src, assemble_alert(
+ title = "Custom Information",
+ subtitle = "The following custom information has been set for this round.",
+ message = GLOB.custom_info,
+ color_override = "red"
+ ))
/datum/admins/proc/sound_file(S as sound)
@@ -653,7 +666,7 @@
/proc/delayed_detonate_bomb_napalm(turf/impact)
impact.ceiling_debris_check(3)
explosion(impact, 2, 3, 4, 0, 6)
- flame_radius(5, impact, 60, 30)
+ flame_radius(5, impact, 30, 60)
/datum/admins/proc/drop_dynex_bomb()
@@ -742,10 +755,10 @@
if(!istype(H))
return
- var/hcolor = "#[num2hex(H.r_hair)][num2hex(H.g_hair)][num2hex(H.b_hair)]"
- var/fcolor = "#[num2hex(H.r_facial)][num2hex(H.g_facial)][num2hex(H.b_facial)]"
- var/ecolor = "#[num2hex(H.r_eyes)][num2hex(H.g_eyes)][num2hex(H.b_eyes)]"
- var/bcolor = "#[num2hex(H.r_skin)][num2hex(H.g_skin)][num2hex(H.b_skin)]"
+ var/hcolor = "#[num2hex(H.r_hair, 2)][num2hex(H.g_hair, 2)][num2hex(H.b_hair, 2)]"
+ var/fcolor = "#[num2hex(H.r_facial, 2)][num2hex(H.g_facial, 2)][num2hex(H.b_facial, 2)]"
+ var/ecolor = "#[num2hex(H.r_eyes, 2)][num2hex(H.g_eyes, 2)][num2hex(H.b_eyes, 2)]"
+ var/bcolor = "#[num2hex(H.r_skin, 2)][num2hex(H.g_skin, 2)][num2hex(H.b_skin, 2)]"
var/dat = " "
@@ -1093,15 +1106,15 @@
if("Low gravity")
to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity pull gently at you."))
for(var/mob/living/living_mob AS in GLOB.mob_living_list)
- living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 32, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_DEFENSIVE_STRUCTURE)
+ living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 32, pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_DEFENSIVE_STRUCTURE|PASS_TANK)
if("John Woo")
to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity grow weak, and the urge to fly."))
for(var/mob/living/living_mob AS in GLOB.mob_living_list)
- living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 48, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE)
+ living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 48, sound = "jump", flags = JUMP_SPIN, pass_flags = HOVERING|PASS_PROJECTILE|PASS_TANK)
if("Exceeding orbital velocity")
to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity fade to nothing. Will you even come back down?"))
for(var/mob/living/living_mob AS in GLOB.mob_living_list)
- living_mob.set_jump_component(duration = 4 SECONDS, cooldown = 6 SECONDS, cost = 0, height = 128, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE)
+ living_mob.set_jump_component(duration = 4 SECONDS, cooldown = 6 SECONDS, cost = 0, height = 128, sound = "jump", flags = JUMP_SPIN, pass_flags = HOVERING|PASS_PROJECTILE|PASS_TANK)
else
return
diff --git a/code/modules/admin/holder.dm b/code/modules/admin/holder.dm
index 1d9c8020673c7..9ee8dd76126af 100644
--- a/code/modules/admin/holder.dm
+++ b/code/modules/admin/holder.dm
@@ -22,7 +22,8 @@
var/ghost_interact = FALSE
///Whether this admin is invisiminning
var/invisimined = FALSE
-
+ /// A lazylist of tagged datums, for quick reference with the View Tags verb
+ var/list/tagged_datums
/datum/admins/New(datum/admin_rank/R, ckey, protected)
if(IsAdminAdvancedProcCall())
@@ -295,6 +296,10 @@ GLOBAL_PROTECT(admin_verbs_default)
/datum/admins/proc/toggle_adminhelp_sound,
/datum/admins/proc/toggle_prayers,
/datum/admins/proc/check_fingerprints,
+ /datum/admins/proc/display_tags,
+ /client/proc/mark_datum_mapview,
+ /client/proc/tag_datum_mapview,
+ /client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
/client/proc/smite,
/client/proc/show_traitor_panel,
/client/proc/cmd_select_equipment,
@@ -302,7 +307,8 @@ GLOBAL_PROTECT(admin_verbs_default)
/client/proc/private_message_panel,
/client/proc/private_message_context,
/client/proc/msay,
- /client/proc/dsay
+ /client/proc/dsay,
+ /client/proc/object_say,
)
//GLOBAL_LIST_INIT(admin_verbs_admin, world.AVadmin()) // moved to modular
//GLOBAL_PROTECT(admin_verbs_admin)
@@ -347,8 +353,8 @@ GLOBAL_PROTECT(admin_verbs_asay)
/world/proc/AVdebug()
return list(
- /datum/admins/proc/proccall_advanced,
- /datum/admins/proc/proccall_atom,
+ /client/proc/callproc,
+ /client/proc/callproc_datum,
/datum/admins/proc/delete_all,
/datum/admins/proc/generate_powernets,
/datum/admins/proc/debug_mob_lists,
@@ -460,7 +466,6 @@ GLOBAL_PROTECT(admin_verbs_server)
/world/proc/AVpermissions()
return list(
/client/proc/edit_admin_permissions,
- /client/proc/poll_panel,
)
GLOBAL_LIST_INIT(admin_verbs_permissions, world.AVpermissions())
GLOBAL_PROTECT(admin_verbs_permissions)
@@ -503,6 +508,13 @@ GLOBAL_PROTECT(admin_verbs_spawn)
GLOBAL_LIST_INIT(admin_verbs_log, world.AVlog())
GLOBAL_PROTECT(admin_verbs_log)
+/world/proc/AVpolls()
+ return list(
+ /client/proc/poll_panel,
+ )
+GLOBAL_LIST_INIT(admin_verbs_polls, world.AVpolls())
+GLOBAL_PROTECT(admin_verbs_polls)
+
/client/proc/add_admin_verbs()
if(holder)
var/rights = holder.rank.rights
@@ -537,6 +549,8 @@ GLOBAL_PROTECT(admin_verbs_log)
add_verb(src, GLOB.admin_verbs_spawn)
if(rights & R_LOG)
add_verb(src, GLOB.admin_verbs_log)
+ if(rights & R_POLLS)
+ add_verb(src, GLOB.admin_verbs_polls)
/client/proc/remove_admin_verbs()
diff --git a/code/modules/admin/panels/permission_panel.dm b/code/modules/admin/panels/permission_panel.dm
index ee85e8d7219ff..6a8976bb3e6b7 100644
--- a/code/modules/admin/panels/permission_panel.dm
+++ b/code/modules/admin/panels/permission_panel.dm
@@ -420,14 +420,14 @@
return
qdel(query_change_rank_flags)
var/log_message = "Permissions of [rank_name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]"
- var/datum/db_query/query_change_rank_flags_log = SSdbcore.NewQuery({"
+ var/datum/db_query/query_change_rank_log_flags = SSdbcore.NewQuery({"
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change rank flags', :rank_name, :log)
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "rank_name" = rank_name, "log" = log_message))
- if(!query_change_rank_flags_log.warn_execute())
- qdel(query_change_rank_flags_log)
+ if(!query_change_rank_log_flags.warn_execute())
+ qdel(query_change_rank_log_flags)
return
- qdel(query_change_rank_flags_log)
+ qdel(query_change_rank_log_flags)
for(var/datum/admin_rank/R in GLOB.admin_ranks)
if(R.name != D.rank.name)
continue
diff --git a/code/modules/admin/panels/poll_panel.dm b/code/modules/admin/panels/poll_panel.dm
index 065c72e2b6b0b..b6b8f104b895c 100644
--- a/code/modules/admin/panels/poll_panel.dm
+++ b/code/modules/admin/panels/poll_panel.dm
@@ -1,7 +1,7 @@
/client/proc/poll_panel()
set name = "Server Poll Management"
set category = "Admin"
- if(!check_rights(R_DBRANKS))
+ if(!check_rights(R_POLLS))
return
holder.poll_list_panel()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Server Poll Management") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/server_verbs.dm b/code/modules/admin/server_verbs.dm
index 39c2f35433c36..86d67a8a80c09 100644
--- a/code/modules/admin/server_verbs.dm
+++ b/code/modules/admin/server_verbs.dm
@@ -444,6 +444,9 @@
if(!check_rights(R_SERVER))
return
+ if(tgui_alert(usr, "Are you sure you want to reload admins?", "Reload admins", list("Yes", "No")) != "Yes")
+ return
+
load_admins()
log_admin("[key_name(src)] manually reloaded admins.")
diff --git a/code/modules/admin/smites/bloodless.dm b/code/modules/admin/smites/bloodless.dm
index 4effa3e1f7ce0..22833664bbf27 100644
--- a/code/modules/admin/smites/bloodless.dm
+++ b/code/modules/admin/smites/bloodless.dm
@@ -15,13 +15,13 @@
to_chat(target, span_userdanger("You feel your skin growing pale as your blood drains away..."), confidential = TRUE)
switch (bloodlossamount)
- if ("A little")
- target.blood_volume = BLOOD_VOLUME_NOT_IDEAL //80% blood
- if ("A lot")
- target.blood_volume = BLOOD_VOLUME_OKAY //60% blood
- if ("So fucking much")
- target.blood_volume = BLOOD_VOLUME_BAD //40% blood
- if ("FUCK THIS DUDE")
- target.blood_volume = BLOOD_VOLUME_SURVIVE //20% blood
+ if("A little")
+ target.set_blood_volume(BLOOD_VOLUME_NOT_IDEAL) //80% blood
+ if("A lot")
+ target.set_blood_volume(BLOOD_VOLUME_OKAY) //60% blood
+ if("So fucking much")
+ target.set_blood_volume(BLOOD_VOLUME_BAD) //40% blood
+ if("FUCK THIS DUDE")
+ target.set_blood_volume(BLOOD_VOLUME_SURVIVE) //20% blood
#undef BLOOD_VOLUME_NOT_IDEAL
diff --git a/code/modules/admin/tag.dm b/code/modules/admin/tag.dm
new file mode 100644
index 0000000000000..6e6fa7747cbfb
--- /dev/null
+++ b/code/modules/admin/tag.dm
@@ -0,0 +1,111 @@
+/**
+ * Inserts the target_datum into [/datum/admins/var/tagged_datums], for later reference.
+ *
+ * Arguments:
+ * * target_datum - The datum you want to create a tag for
+ */
+/datum/admins/proc/add_tagged_datum(datum/target_datum)
+ if(LAZYFIND(tagged_datums, target_datum))
+ to_chat(owner, span_warning("[target_datum] is already tagged!"))
+ return
+
+ LAZYADD(tagged_datums, target_datum)
+ RegisterSignal(target_datum, COMSIG_QDELETING, PROC_REF(handle_tagged_del), override = TRUE)
+ to_chat(owner, span_notice("[target_datum] has been tagged."))
+
+/// Get ahead of the curve with deleting
+/datum/admins/proc/handle_tagged_del(datum/source)
+ SIGNAL_HANDLER
+
+ if(owner)
+ to_chat(owner, span_boldnotice("Tagged datum [source] ([source.type]) has been deleted."))
+ remove_tagged_datum(source, silent = TRUE)
+
+/**
+ * Attempts to remove the specified datum from [/datum/admins/var/tagged_datums] if it exists
+ *
+ * Arguments:
+ * * target_datum - The datum you want to remove from the tagged_datums list
+ * * silent - If TRUE, won't print messages to the owner's chat
+ */
+/datum/admins/proc/remove_tagged_datum(datum/target_datum, silent=FALSE)
+ if(!istype(target_datum))
+ return
+
+ if(LAZYFIND(tagged_datums, target_datum))
+ LAZYREMOVE(tagged_datums, target_datum)
+ if(!silent)
+ to_chat(owner, span_notice("[target_datum] has been untagged."))
+ else if(!silent)
+ to_chat(owner, span_warning("[target_datum] was not already tagged."))
+
+/// Quick define for readability
+#define TAG_DEL(X) "(UNTAG)"
+#define TAG_MARK(X) "(MARK)"
+#define TAG_SIMPLE_HEALTH(X) "Health: [X.health]"
+#define TAG_CARBON_HEALTH(X) "Health: [X.health] (\
+ [X.getBruteLoss()] \
+ [X.getFireLoss()] \
+ [X.getToxLoss()] \
+ [X.getOxyLoss()]\
+ [X.getCloneLoss() ? " [X.getCloneLoss()]" : ""])"
+
+/// Display all of the tagged datums
+/datum/admins/proc/display_tags()
+ set category = "Debug"
+ set name = "View Tags"
+
+ var/datum/admins/holdersrc = src
+ if (!istype(holdersrc, /datum/admins))
+ holdersrc = usr.client.holder
+ if (!istype(holdersrc, /datum/admins))
+ to_chat(usr, "Error: you are not an admin!", confidential = TRUE)
+ return
+ holdersrc.index_tags()
+
+/datum/admins/proc/index_tags()
+ var/index = 0
+ var/list/dat = list("
Tag Menu
")
+
+ dat += " Refresh "
+ if(LAZYLEN(tagged_datums))
+ for(var/datum/iter_datum as anything in tagged_datums)
+ index++
+ var/specific_info
+
+ if(isnull(iter_datum))
+ dat += "\t[index]: Null reference - Check runtime logs!"
+ stack_trace("Null datum found in tagged datum menu! User: [usr]")
+ continue
+ else if(iscarbon(iter_datum))
+ var/mob/living/carbon/resolved_carbon = iter_datum
+ specific_info = "[TAG_CARBON_HEALTH(resolved_carbon)] | [AREACOORD(resolved_carbon)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
+ else if(isliving(iter_datum))
+ var/mob/living/resolved_living = iter_datum
+ specific_info = "[TAG_SIMPLE_HEALTH(resolved_living)] | [AREACOORD(resolved_living)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
+ else if(ismob(iter_datum))
+ var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
+ specific_info = "[AREACOORD(resolved_atom)] [ADMIN_PP(iter_datum)] [ADMIN_FLW(iter_datum)]"
+ else if(ismovable(iter_datum))
+ var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
+ specific_info = "[AREACOORD(resolved_atom)] [ADMIN_FLW(iter_datum)]"
+ else if(isatom(iter_datum))
+ var/atom/resolved_atom = iter_datum // needed for ADMIN_JMP
+ specific_info = "[AREACOORD(resolved_atom)] [ADMIN_JMP(resolved_atom)]"
+ else if(istype(iter_datum, /datum/controller/subsystem))
+ var/datum/controller/subsystem/resolved_subsystem = iter_datum
+ specific_info = "[resolved_subsystem.stat_entry()]"
+ // else, it's just a /datum
+
+ dat += "\t[index]: [iter_datum] | [specific_info] | [ADMIN_VV(iter_datum)] | [TAG_DEL(iter_datum)] | [iter_datum == marked_datum ? "Marked" : TAG_MARK(iter_datum)] "
+ dat += "\t([iter_datum.type])"
+ else
+ dat += "No datums tagged :("
+
+ dat = dat.Join(" ")
+ usr << browse(dat, "window=tag;size=800x480")
+
+#undef TAG_DEL
+#undef TAG_MARK
+#undef TAG_SIMPLE_HEALTH
+#undef TAG_CARBON_HEALTH
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 86bcc003ee04a..a772a0068b98a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1107,9 +1107,9 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
message_admins("[ADMIN_TPMONTY(usr)] canceled an evacuation.")
if("toggle_evac")
- SSevacuation.flags_scuttle ^= FLAGS_EVACUATION_DENY
- log_admin("[key_name(src)] has [SSevacuation.flags_scuttle & FLAGS_EVACUATION_DENY ? "forbidden" : "allowed"] ship-wide evacuation.")
- message_admins("[ADMIN_TPMONTY(usr)] has [SSevacuation.flags_scuttle & FLAGS_EVACUATION_DENY ? "forbidden" : "allowed"] ship-wide evacuation.")
+ SSevacuation.scuttle_flags ^= FLAGS_EVACUATION_DENY
+ log_admin("[key_name(src)] has [SSevacuation.scuttle_flags & FLAGS_EVACUATION_DENY ? "forbidden" : "allowed"] ship-wide evacuation.")
+ message_admins("[ADMIN_TPMONTY(usr)] has [SSevacuation.scuttle_flags & FLAGS_EVACUATION_DENY ? "forbidden" : "allowed"] ship-wide evacuation.")
if("force_evac")
if(!SSevacuation.begin_launch())
@@ -1147,9 +1147,9 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
message_admins("[ADMIN_TPMONTY(usr)] forced the self-destruct system, destroying the [SSmapping.configs[SHIP_MAP].map_name].")
if("toggle_dest")
- SSevacuation.flags_scuttle ^= FLAGS_SELF_DESTRUCT_DENY
- log_admin("[key_name(src)] has [SSevacuation.flags_scuttle & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.")
- message_admins("[ADMIN_TPMONTY(usr)] has [SSevacuation.flags_scuttle & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.")
+ SSevacuation.scuttle_flags ^= FLAGS_SELF_DESTRUCT_DENY
+ log_admin("[key_name(src)] has [SSevacuation.scuttle_flags & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.")
+ message_admins("[ADMIN_TPMONTY(usr)] has [SSevacuation.scuttle_flags & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.")
//RU TGMC EDIT
else if(href_list["admincancelpredsd"])
@@ -1802,7 +1802,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
var/dat
- for(var/i in L.get_contents())
+ for(var/i in L.GetAllContents())
var/atom/A = i
dat += "[A] [ADMIN_VV(A)] "
@@ -1844,7 +1844,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
change = input("Select the hair color.", "Edit Appearance") as null|color
if(!change || !istype(H))
return
- previous = "#[num2hex(H.r_hair)][num2hex(H.g_hair)][num2hex(H.b_hair)]"
+ previous = "#[num2hex(H.r_hair, 2)][num2hex(H.g_hair, 2)][num2hex(H.b_hair, 2)]"
H.r_hair = hex2num(copytext(change, 2, 4))
H.g_hair = hex2num(copytext(change, 4, 6))
H.b_hair = hex2num(copytext(change, 6, 8))
@@ -1858,7 +1858,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
change = input("Select the facial hair color.", "Edit Appearance") as null|color
if(!change || !istype(H))
return
- previous = "#[num2hex(H.r_facial)][num2hex(H.g_facial)][num2hex(H.b_facial)]"
+ previous = "#[num2hex(H.r_facial, 2)][num2hex(H.g_facial, 2)][num2hex(H.b_facial, 2)]"
H.r_facial = hex2num(copytext(change, 2, 4))
H.g_facial = hex2num(copytext(change, 4, 6))
H.b_facial = hex2num(copytext(change, 6, 8))
@@ -1866,7 +1866,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
change = input("Select the eye color.", "Edit Appearance") as null|color
if(!change || !istype(H))
return
- previous = "#[num2hex(H.r_eyes)][num2hex(H.g_eyes)][num2hex(H.b_eyes)]"
+ previous = "#[num2hex(H.r_eyes, 2)][num2hex(H.g_eyes, 2)][num2hex(H.b_eyes, 2)]"
H.r_eyes = hex2num(copytext(change, 2, 4))
H.g_eyes = hex2num(copytext(change, 4, 6))
H.b_eyes = hex2num(copytext(change, 6, 8))
@@ -1874,7 +1874,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
change = input("Select the body color.", "Edit Appearance") as null|color
if(!change || !istype(H))
return
- previous = "#[num2hex(H.r_skin)][num2hex(H.g_skin)][num2hex(H.b_skin)]"
+ previous = "#[num2hex(H.r_skin, 2)][num2hex(H.g_skin, 2)][num2hex(H.b_skin, 2)]"
H.r_skin = hex2num(copytext(change, 2, 4))
H.g_skin = hex2num(copytext(change, 4, 6))
H.b_skin = hex2num(copytext(change, 6, 8))
@@ -2153,7 +2153,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
else if(href_list["clearpollvotes"])
var/datum/poll_question/poll = locate(href_list["clearpollvotes"]) in GLOB.polls
- poll.cleaR_DBRANKS_votes()
+ poll.cleaR_POLLS_votes()
poll_management_panel(poll)
else if(href_list["addpolloption"])
@@ -2182,6 +2182,41 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"]
message_admins(logtext)
log_admin(logtext)
+ else if(href_list["cancelsummon"])
+ GLOB.active_summons.Cut()
+ var/logtext = "[key_name(usr)] has cancelled all psychic summons"
+ message_admins(logtext)
+ log_admin(logtext)
+
+ else if(href_list["tag_datum"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/datum/datum_to_tag = locate(href_list["tag_datum"])
+ if(!datum_to_tag)
+ return
+ return add_tagged_datum(datum_to_tag)
+
+ else if(href_list["del_tag"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/datum/datum_to_remove = locate(href_list["del_tag"])
+ if(!datum_to_remove)
+ return
+ return remove_tagged_datum(datum_to_remove)
+
+ else if(href_list["show_tags"])
+ if(!check_rights(R_ADMIN))
+ return
+ return display_tags()
+
+ else if(href_list["mark_datum"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/datum/datum_to_mark = locate(href_list["mark_datum"])
+ if(!datum_to_mark)
+ return
+ return usr.client?.mark_datum(datum_to_mark)
+
else if(href_list["adminunbanish"])
if(!check_rights(R_ADMIN))
return
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
index cd985279eda76..3e019efc78ce5 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
@@ -85,7 +85,10 @@
return min(arglist(args))
/proc/_new(type, arguments)
- return new type (arglist(arguments))
+ var/datum/result = new type(arglist(arguments))
+ if(istype(result))
+ result.datum_flags |= DF_VAR_EDITED
+ return result
/proc/_num2text(N, SigFig = 6)
return num2text(N, SigFig)
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 90020d5b28499..2cb79cbabe33a 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -430,6 +430,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
AddInteraction("Reopened by [key_name_admin(usr)]")
log_admin_private("Ticket (#[id]) reopened by [key_name(usr)].")
+ to_chat(initiator, span_adminhelp("Your ticket has been reopened."))
TicketPanel() //can only be done from here, so refresh it
@@ -451,11 +452,13 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
msg = "an admin ticket"
AddInteraction("Made admin ticket by: [key_name_admin(usr)].")
message_admins("Ticket [TicketHref("#[id]")] has been made [msg] by [ref].")
+ to_chat(initiator, span_adminhelp("Your ticket has been tiered to an adminhelp."))
else if(tier == TICKET_ADMIN)
tier = TICKET_MENTOR
msg = "a mentor ticket"
AddInteraction("Made mentor ticket by: [key_name_admin(usr)].")
message_staff("Ticket [TicketHref("#[id]")] has been made [msg] by [ref].")
+ to_chat(initiator, span_adminhelp("Your ticket has been tiered to a mentorhelp."))
if(!irc)
for(var/client/X in GLOB.admins)
if(!is_mentor(X))
@@ -483,6 +486,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
else if(tier == TICKET_ADMIN)
message_admins("Ticket [TicketHref("#[id]")] has been unmarked by [ADMIN_TPMONTY(usr)].")
log_admin_private("Ticket (#[id]) has been unmarked by [key_name(usr)].")
+ to_chat(initiator, span_adminhelp("Your ticket has been unmarked."))
return
else if(alert("This ticket has already been marked by [marked], do you want to replace them?", "Confirmation", "Yes", "No") != "Yes")
return
@@ -492,6 +496,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
message_admins("Ticket [TicketHref("#[id]")] has been re-marked by [ADMIN_TPMONTY(usr)].")
marked = usr.client.key
log_admin_private("Ticket (#[id]) has been re-marked by [key_name(usr)].")
+ to_chat(initiator, span_adminhelp("Your ticket has been marked by another admin."))
return
marked = usr.client.key
if(tier == TICKET_MENTOR)
@@ -499,6 +504,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
else if(tier == TICKET_ADMIN)
message_admins("Ticket [TicketHref("#[id]")] has been marked by [ADMIN_TPMONTY(usr)].")
log_admin_private("Ticket (#[id]) has been marked by [key_name(usr)].")
+ to_chat(initiator, span_adminhelp("Your ticket has been marked by an admin."))
//private
@@ -529,6 +535,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
AddInteraction("Closed by [key_name_admin(usr)].")
if(!silent)
log_admin_private("Ticket (#[id]) closed by [key_name(usr)].")
+ to_chat(initiator, span_adminhelp("Your ticket has been closed."))
if(tier == TICKET_MENTOR)
message_staff("Ticket [TicketHref("#[id]")] closed by [ref].")
else if(tier == TICKET_ADMIN)
diff --git a/code/modules/admin/verbs/centcom_podlauncher.dm b/code/modules/admin/verbs/centcom_podlauncher.dm
index 6af9f59582dff..55a780d31cf5b 100644
--- a/code/modules/admin/verbs/centcom_podlauncher.dm
+++ b/code/modules/admin/verbs/centcom_podlauncher.dm
@@ -498,7 +498,7 @@
numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time)
acceptableTurfs = list()
for (var/turf/T in orderedArea) //Go through the orderedArea list
- if (typecache_filter_list_reverse(T.contents, length(ignored_atoms)) != 0) //if there is something in this turf that isnt in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
+ if (length(typecache_filter_list_reverse(T.contents, ignored_atoms)) != 0) //if there is something in this turf that isnt in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
acceptableTurfs.Add(T) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well.
numTurfs ++
diff --git a/code/modules/admin/verbs/datumvars.dm b/code/modules/admin/verbs/datumvars.dm
index 7b0068eebfe15..74dfd40698dce 100644
--- a/code/modules/admin/verbs/datumvars.dm
+++ b/code/modules/admin/verbs/datumvars.dm
@@ -1,1212 +1,58 @@
-#define VV_MSG_MARKED " Marked Object"
-#define VV_MSG_EDITED " Var Edited"
-#define VV_MSG_DELETED " Deleted"
-
-
/datum/proc/CanProcCall(procname)
return TRUE
-
/datum/proc/can_vv_get(var_name)
return TRUE
-/client/can_vv_get(var_name)
- if(var_name != "address" && var_name != "computer_id" || check_rights(R_DEBUG))
- return TRUE
- return FALSE
-
-
-/datum/proc/vv_edit_var(var_name, var_value) //called whenever a var is edited
+/// Called when a var is edited with the new value to change to
+/datum/proc/vv_edit_var(var_name, var_value)
if(var_name == NAMEOF(src, vars))
return FALSE
vars[var_name] = var_value
datum_flags |= DF_VAR_EDITED
return TRUE
-
/datum/proc/vv_get_var(var_name)
switch(var_name)
- if("vars")
+ if (NAMEOF(src, vars))
return debug_variable(var_name, list(), 0, src)
return debug_variable(var_name, vars[var_name], 0, src)
+/datum/proc/can_vv_mark()
+ return TRUE
-/proc/get_all_of_type(T, subtypes = TRUE)
- var/list/typecache = list()
- typecache[T] = 1
- if(subtypes)
- typecache = typecacheof(typecache)
- . = list()
- if(ispath(T, /mob))
- for(var/mob/thing in GLOB.mob_list)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /obj/machinery/door))
- for(var/obj/machinery/door/thing in GLOB.machines)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /obj/machinery))
- for(var/obj/machinery/thing in GLOB.machines)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /obj))
- for(var/obj/thing in world)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /atom/movable))
- for(var/atom/movable/thing in world)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /turf))
- for(var/turf/thing in world)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /atom))
- for(var/atom/thing in world)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /client))
- for(var/client/thing in GLOB.clients)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else if(ispath(T, /datum))
- for(var/datum/thing)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
- else
- for(var/datum/thing in world)
- if(typecache[thing.type])
- . += thing
- CHECK_TICK
-
+/**
+ * Gets all the dropdown options in the vv menu.
+ * When overriding, make sure to call . = ..() first and appent to the result, that way parent items are always at the top and child items are further down.
+ * Add seperators by doing VV_DROPDOWN_OPTION("", "---")
+ */
+/datum/proc/vv_get_dropdown()
+ SHOULD_CALL_PARENT(TRUE)
-/proc/make_types_fancy(list/types)
- if(ispath(types))
- types = list(types)
. = list()
- for(var/type in types)
- var/typename = "[type]"
- var/static/list/TYPES_SHORTCUTS = list(
- /obj/effect/decal/cleanable = "CLEANABLE",
- /obj/item/radio/headset = "HEADSET",
- /obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
- /obj/item/reagent_containers/food = "FOOD",
- /obj/item/reagent_containers = "REAGENT_CONTAINERS",
- /obj/item/organ = "ORGAN",
- /obj/item = "ITEM",
- /obj/machinery = "MACHINERY",
- /obj/effect = "EFFECT",
- /obj = "O",
- /datum = "D",
- /turf/open = "OPEN",
- /turf/closed = "CLOSED",
- /turf = "T",
- /mob/living/carbon/human = "HUMAN",
- /mob/living/carbon = "CARBON",
- /mob/living/simple_animal = "SIMPLE",
- /mob/living = "LIVING",
- /mob = "M"
- )
- for (var/tn in TYPES_SHORTCUTS)
- if(copytext(typename, 1, length("[tn]/") + 1) == "[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
- typename = TYPES_SHORTCUTS[tn] + copytext(typename, length("[tn]/"))
- break
- .[typename] = type
-
-
-/proc/get_fancy_list_of_atom_types()
- var/static/list/pre_generated_list
- if(!pre_generated_list) //init
- pre_generated_list = make_types_fancy(typesof(/atom))
- return pre_generated_list
-
-
-/proc/get_fancy_list_of_datum_types()
- var/static/list/pre_generated_list
- if(!pre_generated_list) //init
- pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom)))
- return pre_generated_list
-
-
-/proc/filter_fancy_list(list/L, filter as text)
- var/list/matches = new
- for(var/key in L)
- var/value = L[key]
- if(findtext("[key]", filter) || findtext("[value]", filter))
- matches[key] = value
- return matches
-
+ VV_DROPDOWN_OPTION("", "---")
+ VV_DROPDOWN_OPTION(VV_HK_CALLPROC, "Call Proc")
+ VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object")
+ VV_DROPDOWN_OPTION(VV_HK_TAG, "Tag Datum")
+ VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete")
+ VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player")
+ VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element")
+ VV_DROPDOWN_OPTION(VV_HK_REMOVECOMPONENT, "Remove Component/Element")
+ VV_DROPDOWN_OPTION(VV_HK_MASS_REMOVECOMPONENT, "Mass Remove Component/Element")
+
+/**
+ * This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks!
+ * href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables!
+ * This proc is for "high level" actions like admin heal/set species/etc/etc. The low level debugging things should go in admin/view_variables/topic_basic.dm incase this runtimes.
+ */
+/datum/proc/vv_do_topic(list/href_list)
+ if(!usr || !usr.client || !usr.client.holder || !check_rights(NONE))
+ return FALSE //This is VV, not to be called by anything else.
+ if(SEND_SIGNAL(src, COMSIG_VV_TOPIC, usr, href_list) & COMPONENT_VV_HANDLED)
+ return FALSE
+ return TRUE
-//please call . = ..() first and append to the result, that way parent items are always at the top and child items are further down
-//add separaters by doing . += "---"
-/datum/proc/vv_get_dropdown()
+/datum/proc/vv_get_header()
. = list()
- . += "---"
- .["Call Proc"] = "?_src_=vars;[HrefToken()];[VV_HK_CALLPROC]=[REF(src)]"
- .["Mark Object"] = "?_src_=vars;[HrefToken()];[VV_HK_MARK]=[REF(src)]"
- .["Delete"] = "?_src_=vars;[HrefToken()];[VV_HK_DELETE]=[REF(src)]"
- .["Show VV To Player"] = "?_src_=vars;[HrefToken()];[VV_HK_EXPOSE]=[REF(src)]"
-
-
-/client/proc/debug_variables(datum/D in world)
- set category = "Debug"
- set name = "View Variables"
-
- if(!check_rights(R_VAREDIT))
- return
-
- var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
-
- if(!D)
- return
-
- var/islist = islist(D)
- if(!islist && !istype(D))
- return
-
- var/title = ""
- var/refid = REF(D)
- var/icon/sprite
- var/hash
-
- var/type = /list
- if(!islist)
- type = D.type
-
-
-
- if(istype(D, /atom))
- var/atom/AT = D
- if(AT.icon && AT.icon_state)
- sprite = new /icon(AT.icon, AT.icon_state)
- hash = md5(AT.icon)
- hash = md5(hash + AT.icon_state)
- src << browse_rsc(sprite, "vv[hash].png")
-
- title = "[D] ([REF(D)]) = [type]"
- var/formatted_type = replacetext("[type]", "/", "/")
-
- var/sprite_text
- if(sprite)
- sprite_text = "
-
-
- E - Edit, tries to determine the variable type by itself.
- C - Change, asks you for the var type first.
- M - Mass modify: changes this variable for all objects of this type.
-
-
-
-
-
-
- Search:
-
-
-
-
-
-
-
-
-
- [variable_html.Join()]
-
-
-
-
-"}
- src << browse(html, "window=variables[refid];size=475x650")
-
-
-/client/proc/vv_update_display(datum/D, span, content)
- src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
-
-
-#define VV_HTML_ENCODE(thing) (sanitize ? html_encode(thing) : thing)
-
-/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
- var/header
- if(DA)
- if(islist(DA))
- var/index = name
- if(value)
- name = DA[name] //name is really the index until this line
- else
- value = DA[name]
- header = "
+
+
+ E - Edit, tries to determine the variable type by itself.
+ C - Change, asks you for the var type first.
+ M - Mass modify: changes this variable for all objects of this type.
+
+
+
The following custom information has been set for this round:
")
- to_chat(src, span_alert("[GLOB.custom_info]"))
- to_chat(src, " ")
+ to_chat(src, assemble_alert(
+ title = "Custom Information",
+ subtitle = "The following custom information has been set for this round.",
+ message = GLOB.custom_info,
+ color_override = "red"
+ ))
connection_time = world.time
connection_realtime = world.realtime
diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm
index d8a346be36c8b..3aa83f85eb024 100644
--- a/code/modules/client/preferences_gear.dm
+++ b/code/modules/client/preferences_gear.dm
@@ -225,3 +225,21 @@ GLOBAL_LIST_INIT(gear_datums, populate_gear_list())
cost = 2
slot = SLOT_R_HAND
+/datum/gear/rosary
+ display_name = "Rosary"
+ path = /obj/item/rosary
+ cost = 1
+ slot = SLOT_R_HAND
+
+/datum/gear/card/ace/hearts
+ display_name = "Old Ace of Hearts card"
+ path = /obj/item/toy/card/ace/hearts
+ cost = 1
+ slot = SLOT_R_HAND
+
+/datum/gear/card/ace/spades
+ display_name = "Old Ace of Spades card"
+ path = /obj/item/toy/card/ace/spades
+ cost = 1
+ slot = SLOT_R_HAND
+
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index 782551b9a460f..048a2a86de9c3 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -157,7 +157,7 @@
to_chat(src, span_notice("You will now hear ambient sounds."))
else
to_chat(src, span_notice("You will no longer hear ambient sounds."))
- mob.stop_sound_channel(CHANNEL_AMBIENT)
+ mob.stop_sound_channel(CHANNEL_AMBIENCE)
usr.client.update_ambience_pref()
@@ -203,7 +203,7 @@ GLOBAL_LIST_INIT(ghost_forms, list("Default" = GHOST_DEFAULT_FORM, "Ghost Ian 1"
return
var/mob/dead/observer/O = mob
- O.update_icon(GLOB.ghost_forms[new_form])
+ O.pick_form(GLOB.ghost_forms[new_form])
GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE, GHOST_ORBIT_TRIANGLE, GHOST_ORBIT_SQUARE, GHOST_ORBIT_HEXAGON, GHOST_ORBIT_PENTAGON))
@@ -293,7 +293,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
usr.client.prefs.toggles_sound ^= SOUND_WEATHER
prefs.save_preferences()
- to_chat(usr, span_notice("You will [(usr.client.prefs.toggles_sound & SOUND_WEATHER) ? "no longer" : "now"] hear weather."))
+ to_chat(usr, span_notice("You will [(usr.client.prefs.toggles_sound & SOUND_WEATHER) ? "now" : "no longer"] hear weather."))
/client/verb/toggle_gas_mask_sound()
set category = "Preferences"
diff --git a/code/modules/client/preferences_ui.dm b/code/modules/client/preferences_ui.dm
index d6d79fc57ce14..e23464c70cd10 100644
--- a/code/modules/client/preferences_ui.dm
+++ b/code/modules/client/preferences_ui.dm
@@ -152,6 +152,7 @@
data["radialstackspref"] = !!(toggles_gameplay & RADIAL_STACKS)
data["radiallasersgunpref"] = !!(toggles_gameplay & RADIAL_LASERGUNS)
data["autointeractdeployablespref"] = !!(toggles_gameplay & AUTO_INTERACT_DEPLOYABLES)
+ data["directional_attacks"] = !!(toggles_gameplay & DIRECTIONAL_ATTACKS)
data["scaling_method"] = scaling_method
data["pixel_size"] = pixel_size
data["parallax"] = parallax
@@ -974,6 +975,9 @@
if("autointeractdeployablespref")
toggles_gameplay ^= AUTO_INTERACT_DEPLOYABLES
+ if("directional_attacks")
+ toggles_gameplay ^= DIRECTIONAL_ATTACKS
+
if("pixel_size")
switch(pixel_size)
if(PIXEL_SCALING_AUTO)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index a22c884344fb2..5bbdf8d9be306 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -3,7 +3,7 @@
// Resets the armor on clothing since by default /objs get 100 bio armor
soft_armor = list()
- flags_inventory = NOQUICKEQUIP
+ inventory_flags = NOQUICKEQUIP
///Assoc list of available slots. Since this keeps track of all currently equiped attachments per object, this cannot be a string_list()
var/list/attachments_by_slot = list()
@@ -16,7 +16,7 @@
var/list/starting_attachments = list()
/// Bitflags used to determine the state of the armor (light on, overlay used, or reinfornced), currently support flags are in [equipment.dm:100]
- var/flags_armor_features = NONE
+ var/armor_features_flags = NONE
/// used for headgear, masks, and glasses, to see how much they protect eyes from bright lights.
var/eye_protection = 0
@@ -35,26 +35,26 @@
/obj/item/clothing/equipped(mob/user, slot)
. = ..()
- if(!(flags_equip_slot & slotdefine2slotbit(slot)))
+ if(!(equip_slot_flags & slotdefine2slotbit(slot)))
return
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(accuracy_mod)
human_user.adjust_mob_accuracy(accuracy_mod)
- if(flags_armor_features & ARMOR_FIRE_RESISTANT)
+ if(armor_features_flags & ARMOR_FIRE_RESISTANT)
ADD_TRAIT(human_user, TRAIT_NON_FLAMMABLE, src)
/obj/item/clothing/unequipped(mob/unequipper, slot)
- if(!(flags_equip_slot & slotdefine2slotbit(slot)))
+ if(!(equip_slot_flags & slotdefine2slotbit(slot)))
return ..()
if(!ishuman(unequipper))
return ..()
var/mob/living/carbon/human/human_unequipper = unequipper
if(accuracy_mod)
human_unequipper.adjust_mob_accuracy(-accuracy_mod)
- if(flags_armor_features & ARMOR_FIRE_RESISTANT)
+ if(armor_features_flags & ARMOR_FIRE_RESISTANT)
REMOVE_TRAIT(human_unequipper, TRAIT_NON_FLAMMABLE, src)
return ..()
@@ -121,7 +121,7 @@
)
w_class = WEIGHT_CLASS_TINY
throwforce = 2
- flags_equip_slot = ITEM_SLOT_EARS
+ equip_slot_flags = ITEM_SLOT_EARS
/obj/item/clothing/ears/update_clothing_icon()
if (ismob(src.loc))
@@ -134,7 +134,7 @@
desc = "Protects your hearing from loud noises, and quiet ones as well."
icon_state = "earmuffs"
item_state = "earmuffs"
- flags_equip_slot = ITEM_SLOT_EARS
+ equip_slot_flags = ITEM_SLOT_EARS
/obj/item/clothing/ears/earmuffs/green
icon_state = "earmuffs2"
@@ -151,10 +151,10 @@
slot_r_hand_str = 'icons/mob/inhands/clothing/suits_right.dmi',
)
name = "suit"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
allowed = list(/obj/item/tank/emergency_oxygen)
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
- flags_equip_slot = ITEM_SLOT_OCLOTHING
+ equip_slot_flags = ITEM_SLOT_OCLOTHING
siemens_coefficient = 0.9
w_class = WEIGHT_CLASS_NORMAL
attachments_by_slot = list(ATTACHMENT_SLOT_BADGE)
@@ -185,10 +185,9 @@
if(. != CHECKS_PASSED)
return
set_light_on(toggle_on)
- flags_armor_features ^= ARMOR_LAMP_ON
+ armor_features_flags ^= ARMOR_LAMP_ON
playsound(src, 'sound/items/flashlight.ogg', 15, TRUE)
- update_icon(user)
- update_action_button_icons()
+ update_icon()
/obj/item/clothing/suit/update_clothing_icon()
if(ismob(loc))
@@ -222,8 +221,8 @@
var/clipped = 0
var/transfer_prints = TRUE
blood_sprite_state = "bloodyhands"
- flags_armor_protection = HANDS
- flags_equip_slot = ITEM_SLOT_GLOVES
+ armor_protection_flags = HANDS
+ equip_slot_flags = ITEM_SLOT_GLOVES
attack_verb = list("challenged")
@@ -239,9 +238,7 @@
cell.charge -= 1000 / severity
if (cell.charge < 0)
cell.charge = 0
- if(cell.reliability != 100 && prob(50/severity))
- cell.reliability -= 10 / severity
- ..()
+ return ..()
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity)
@@ -249,6 +246,8 @@
/obj/item/clothing/gloves/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswirecutter(I) || istype(I, /obj/item/tool/surgery/scalpel))
if(clipped)
to_chat(user, span_notice("The [src] have already been clipped!"))
@@ -274,8 +273,8 @@
slot_l_hand_str = 'icons/mob/inhands/clothing/masks_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/clothing/masks_right.dmi',
)
- flags_equip_slot = ITEM_SLOT_MASK
- flags_armor_protection = FACE|EYES
+ equip_slot_flags = ITEM_SLOT_MASK
+ armor_protection_flags = FACE|EYES
blood_sprite_state = "maskblood"
var/anti_hug = 0
var/toggleable = FALSE
@@ -303,8 +302,8 @@
desc = "Comfortable-looking shoes."
gender = PLURAL //Carn: for grammarically correct text-parsing
siemens_coefficient = 0.9
- flags_armor_protection = FEET
- flags_equip_slot = ITEM_SLOT_FEET
+ armor_protection_flags = FEET
+ equip_slot_flags = ITEM_SLOT_FEET
permeability_coefficient = 0.50
slowdown = SHOES_SLOWDOWN
blood_sprite_state = "shoeblood"
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 4f180cd016492..3354d41d8d9c3 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -10,9 +10,9 @@
var/prescription = FALSE
var/toggleable = FALSE
active = TRUE
- flags_inventory = COVEREYES
- flags_equip_slot = ITEM_SLOT_EYES
- flags_armor_protection = EYES
+ inventory_flags = COVEREYES
+ equip_slot_flags = ITEM_SLOT_EYES
+ armor_protection_flags = EYES
var/deactive_state = "degoggles"
var/vision_flags = NONE
var/darkness_view = 2 //Base human is 2
@@ -83,10 +83,12 @@
desc = "Yarr."
icon_state = "eyepatch"
item_state = "eyepatch"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/eyepatch/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/clothing/glasses/hud/health))
var/obj/item/clothing/glasses/hud/medpatch/P = new
@@ -101,14 +103,14 @@
qdel(src)
user.put_in_hands(P)
- update_icon(user)
+ update_icon()
/obj/item/clothing/glasses/monocle
name = "monocle"
desc = "Such a dapper eyepiece!"
icon_state = "monocle"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/material
name = "optical material scanner"
@@ -128,6 +130,8 @@
/obj/item/clothing/glasses/regular/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/clothing/glasses/hud/health))
var/obj/item/clothing/glasses/hud/medglasses/P = new
@@ -136,7 +140,7 @@
qdel(src)
user.put_in_hands(P)
- update_icon(user)
+ update_icon()
/obj/item/clothing/glasses/regular/hipster
name = "prescription glasses"
@@ -149,14 +153,14 @@
name = "3D glasses"
icon_state = "3d"
item_state = "3d"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/gglasses
name = "green glasses"
desc = "Forest green glasses, like the kind you'd wear when hatching a nasty scheme."
icon_state = "gglasses"
item_state = "gglasses"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/mgoggles
name = "marine ballistic goggles"
@@ -164,7 +168,7 @@
icon_state = "mgoggles"
item_state = "mgoggles"
soft_armor = list(MELEE = 40, BULLET = 40, LASER = 0, ENERGY = 15, BOMB = 35, BIO = 10, FIRE = 30, ACID = 30)
- flags_equip_slot = ITEM_SLOT_EYES|ITEM_SLOT_MASK
+ equip_slot_flags = ITEM_SLOT_EYES|ITEM_SLOT_MASK
goggles = TRUE
w_class = WEIGHT_CLASS_TINY
@@ -176,6 +180,8 @@
/obj/item/clothing/glasses/mgoggles/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/clothing/glasses/hud/health))
if(prescription)
@@ -204,7 +210,7 @@
qdel(src)
user.put_in_hands(S)
- update_icon(user)
+ update_icon()
/obj/item/clothing/glasses/m42_goggles
name = "\improper M42 scout sight"
@@ -226,8 +232,8 @@
icon_state = "welding-g"
item_state = "welding-g"
actions_types = list(/datum/action/item_action/toggle)
- flags_inventory = COVEREYES
- flags_inv_hide = HIDEEYES
+ inventory_flags = COVEREYES
+ inv_hide_flags = HIDEEYES
eye_protection = 2
activation_sound = null
deactivation_sound = null
@@ -256,9 +262,9 @@
///Toggle the welding goggles on
/obj/item/clothing/glasses/welding/proc/flip_up(mob/user)
- DISABLE_BITFIELD(flags_inventory, COVEREYES)
- DISABLE_BITFIELD(flags_inv_hide, HIDEEYES)
- DISABLE_BITFIELD(flags_armor_protection, EYES)
+ DISABLE_BITFIELD(inventory_flags, COVEREYES)
+ DISABLE_BITFIELD(inv_hide_flags, HIDEEYES)
+ DISABLE_BITFIELD(armor_protection_flags, EYES)
eye_protection = 0
update_icon()
if(user)
@@ -266,9 +272,9 @@
///Toggle the welding goggles off
/obj/item/clothing/glasses/welding/proc/flip_down(mob/user)
- ENABLE_BITFIELD(flags_inventory, COVEREYES)
- ENABLE_BITFIELD(flags_inv_hide, HIDEEYES)
- ENABLE_BITFIELD(flags_armor_protection, EYES)
+ ENABLE_BITFIELD(inventory_flags, COVEREYES)
+ ENABLE_BITFIELD(inv_hide_flags, HIDEEYES)
+ ENABLE_BITFIELD(armor_protection_flags, EYES)
eye_protection = initial(eye_protection)
update_icon()
if(user)
@@ -336,6 +342,8 @@
/obj/item/clothing/glasses/sunglasses/fake/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/clothing/glasses/hud/health))
var/obj/item/clothing/glasses/hud/medsunglasses/P = new
@@ -356,7 +364,7 @@
qdel(src)
user.put_in_hands(P)
- update_icon(user)
+ update_icon()
/obj/item/clothing/glasses/sunglasses/fake/prescription
name = "prescription sunglasses"
@@ -371,22 +379,6 @@
name = "prescription sunglasses"
prescription = TRUE
-/obj/item/clothing/glasses/sunglasses/sa
- name = "spatial agent's sunglasses"
- desc = "Glasses worn by a spatial agent."
- eye_protection = 2
- darkness_view = 8
- vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
- lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
-
-/obj/item/clothing/glasses/sunglasses/sa/Initialize(mapload)
- . = ..()
- AddComponent(/datum/component/clothing_tint, TINT_NONE)
-
-/obj/item/clothing/glasses/sunglasses/sa/nodrop
- desc = "Glasses worn by a spatial agent. cannot be dropped"
- flags_item = DELONDROP
-
/obj/item/clothing/glasses/sunglasses/sechud
name = "HUDSunglasses"
desc = "Sunglasses with a HUD."
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index bfc452db57ac9..a6f32ebfa090c 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -1,8 +1,10 @@
/obj/item/clothing/glasses/hud
name = "HUD"
desc = "A heads-up display that provides important info in (almost) real time."
- flags_atom = null //doesn't protect eyes because it's a monocle, duh
+ atom_flags = null //doesn't protect eyes because it's a monocle, duh
+ ///The hud type(s) to give this type of glasses
var/hud_type
+ ///The user wearing the glasses
var/mob/living/carbon/human/affected_user
@@ -19,13 +21,13 @@
if(active)
activate_hud(user)
else if(affected_user)
- deactivate_hud()
+ deactivate_hud(user)
return ..()
/obj/item/clothing/glasses/hud/dropped(mob/user)
if(affected_user)
- deactivate_hud()
+ deactivate_hud(user)
return ..()
@@ -47,14 +49,24 @@
///Activates the hud(s) these glasses have
/obj/item/clothing/glasses/hud/proc/activate_hud(mob/living/carbon/human/user)
- var/datum/atom_hud/hud_datum = GLOB.huds[hud_type]
- hud_datum.add_hud_to(user)
affected_user = user
-
-
-/obj/item/clothing/glasses/hud/proc/deactivate_hud()
- var/datum/atom_hud/hud_datum = GLOB.huds[hud_type]
- hud_datum.remove_hud_from(affected_user)
+ if(islist(hud_type))
+ for(var/hud in hud_type)
+ var/datum/atom_hud/hud_datum = GLOB.huds[hud]
+ hud_datum.add_hud_to(affected_user)
+ else
+ var/datum/atom_hud/hud_datum = GLOB.huds[hud_type]
+ hud_datum.add_hud_to(affected_user)
+
+///Deactivates the hud(s) these glasses have
+/obj/item/clothing/glasses/hud/proc/deactivate_hud(mob/user)
+ if(islist(hud_type))
+ for(var/hud in hud_type)
+ var/datum/atom_hud/hud_datum = GLOB.huds[hud]
+ hud_datum.remove_hud_from(affected_user)
+ else
+ var/datum/atom_hud/hud_datum = GLOB.huds[hud_type]
+ hud_datum.remove_hud_from(affected_user)
affected_user = null
@@ -63,7 +75,7 @@
desc = "A heads-up display that scans the humans in view and provides accurate data about their health status. The projector can be attached to compatable eyewear."
icon_state = "healthhud"
deactive_state = "degoggles_med"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
toggleable = TRUE
hud_type = DATA_HUD_MEDICAL_ADVANCED
actions_types = list(/datum/action/item_action/toggle)
@@ -93,7 +105,7 @@
"Hammerhead Combat Robot" = 'icons/mob/species/robot/glasses_alpharii.dmi',
"Ratcher Combat Robot" = 'icons/mob/species/robot/glasses_deltad.dmi')
soft_armor = list(MELEE = 40, BULLET = 40, LASER = 0, ENERGY = 15, BOMB = 35, BIO = 10, FIRE = 30, ACID = 30)
- flags_equip_slot = ITEM_SLOT_EYES
+ equip_slot_flags = ITEM_SLOT_EYES
goggles = TRUE
/obj/item/clothing/glasses/hud/medgoggles/prescription
@@ -166,7 +178,7 @@
icon_state = "securityhud"
deactive_state = "degoggles_sec"
toggleable = 1
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
hud_type = DATA_HUD_SECURITY_ADVANCED
actions_types = list(/datum/action/item_action/toggle)
var/global/list/jobs[0]
@@ -192,7 +204,7 @@
"Chilvaris Combat Robot" = 'icons/mob/species/robot/glasses_charlit.dmi',
"Hammerhead Combat Robot" = 'icons/mob/species/robot/glasses_alpharii.dmi',
"Ratcher Combat Robot" = 'icons/mob/species/robot/glasses_deltad.dmi')
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
toggleable = TRUE
hud_type = DATA_HUD_XENO_STATUS
actions_types = list(/datum/action/item_action/toggle)
@@ -232,4 +244,4 @@
/obj/item/clothing/glasses/hud/sa/nodrop
desc = "Glasses worn by a spatial agent. They delete themselves if you take them off!"
- flags_item = DELONDROP
+ item_flags = DELONDROP
diff --git a/code/modules/clothing/glasses/meson.dm b/code/modules/clothing/glasses/meson.dm
index b6b73450b5ac7..3e7f07f8095d2 100644
--- a/code/modules/clothing/glasses/meson.dm
+++ b/code/modules/clothing/glasses/meson.dm
@@ -31,7 +31,7 @@
icon_state = "enggoggles"
item_state = "enggoggles"
deactive_state = "degoggles_enggoggles"
- flags_equip_slot = ITEM_SLOT_EYES
+ equip_slot_flags = ITEM_SLOT_EYES
goggles = TRUE
/obj/item/clothing/glasses/meson/enggoggles/prescription
diff --git a/code/modules/clothing/glasses/night.dm b/code/modules/clothing/glasses/night.dm
index 5bd664a56f205..f33bcfabc2222 100644
--- a/code/modules/clothing/glasses/night.dm
+++ b/code/modules/clothing/glasses/night.dm
@@ -54,7 +54,7 @@
item_state = "alien_lens"
darkness_view = 7
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
- flags_item = DELONDROP
+ item_flags = DELONDROP
/obj/item/clothing/glasses/night/sectoid/Initialize(mapload)
. = ..()
@@ -100,7 +100,7 @@
"Chilvaris Combat Robot" = 'icons/mob/species/robot/glasses_charlit.dmi',
"Hammerhead Combat Robot" = 'icons/mob/species/robot/glasses_alpharii.dmi',
"Ratcher Combat Robot" = 'icons/mob/species/robot/glasses_deltad.dmi')
- flags_equip_slot = ITEM_SLOT_EYES
+ equip_slot_flags = ITEM_SLOT_EYES
goggles = TRUE
/obj/item/clothing/glasses/night/optgoggles/prescription
diff --git a/code/modules/clothing/glasses/thermal.dm b/code/modules/clothing/glasses/thermal.dm
index 5e22a6488ce3a..1dd808c8b8e98 100644
--- a/code/modules/clothing/glasses/thermal.dm
+++ b/code/modules/clothing/glasses/thermal.dm
@@ -36,9 +36,9 @@
name = "Thermoncle"
desc = "A monocle thermal."
icon_state = "thermoncle"
- flags_atom = null //doesn't protect eyes because it's a monocle, duh
+ atom_flags = null //doesn't protect eyes because it's a monocle, duh
toggleable = 0
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/thermal/eyepatch
name = "Optical Thermal Eyepatch"
@@ -46,7 +46,7 @@
icon_state = "eyepatch"
item_state = "eyepatch"
toggleable = 0
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/glasses/thermal/jensen
name = "Optical Thermal Implants"
diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm
index 8314781bb0b51..0e2c5dbc7a51f 100644
--- a/code/modules/clothing/gloves/color.dm
+++ b/code/modules/clothing/gloves/color.dm
@@ -4,9 +4,9 @@
icon_state = "insulated"
siemens_coefficient = 0
permeability_coefficient = 0.05
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/yellow //Cheap Chinese Crap
@@ -24,9 +24,9 @@
desc = "These gloves are fire-resistant."
name = "black gloves"
icon_state = "black"
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
@@ -80,7 +80,7 @@
desc = "A field of invisible energy, it protects the wearer but prevents any clothing from being worn."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-blue"
- flags_item = DELONDROP
+ item_flags = DELONDROP
soft_armor = list(MELEE = 25, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 25)
/obj/item/clothing/gloves/sectoid/Initialize(mapload)
diff --git a/code/modules/clothing/gloves/marine_gloves.dm b/code/modules/clothing/gloves/marine_gloves.dm
index c4401c6f97be8..8db71f2cad1b8 100644
--- a/code/modules/clothing/gloves/marine_gloves.dm
+++ b/code/modules/clothing/gloves/marine_gloves.dm
@@ -9,11 +9,11 @@
icon_state = "gloves_marine"
siemens_coefficient = 0.6
permeability_coefficient = 0.05
- flags_cold_protection = HANDS
- flags_heat_protection = HANDS
+ cold_protection_flags = HANDS
+ heat_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
- flags_armor_protection = HANDS
+ armor_protection_flags = HANDS
soft_armor = list(MELEE = 25, BULLET = 15, LASER = 10, ENERGY = 15, BOMB = 15, BIO = 5, FIRE = 15, ACID = 15)
/obj/item/clothing/gloves/marine/black
@@ -84,7 +84,7 @@
name = "\improper B18 defensive gauntlets"
desc = "A pair of heavily armored gloves."
icon_state = "armored"
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 35, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 25, BIO = 15, FIRE = 15, ACID = 20)
resistance_flags = UNACIDABLE
@@ -93,13 +93,13 @@
desc = "Armored gloves used in special operations. They are also insulated against electrical shock."
icon_state = "black"
siemens_coefficient = 0
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 15)
/obj/item/clothing/gloves/marine/veteran/pmc/commando
name = "\improper PMC commando gloves"
desc = "A pair of heavily armored, insulated, acid-resistant gloves."
- icon_state = "armored"
+ icon_state = "death_squad"
soft_armor = list(MELEE = 40, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 25)
resistance_flags = UNACIDABLE
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index 59850ced7de9c..c06991148f71a 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -2,9 +2,9 @@
desc = "Regal blue gloves, with a nice gold trim. Swanky."
name = "captain's gloves"
icon_state = "captain"
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/swat
@@ -14,9 +14,9 @@
siemens_coefficient = 0.6
permeability_coefficient = 0.05
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/combat //Combined effect of SWAT gloves and insulated gloves
@@ -25,9 +25,9 @@
icon_state = "black"
siemens_coefficient = 0
permeability_coefficient = 0.05
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/gloves/ruggedgloves
@@ -36,9 +36,9 @@
icon_state = "black"
siemens_coefficient = 0
permeability_coefficient = 0.05
- flags_cold_protection = HANDS
+ cold_protection_flags = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = HANDS
+ heat_protection_flags = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
soft_armor = list(MELEE = 10, BULLET = 10, LASER = 15, ENERGY = 10, BOMB = 10, BIO = 10, FIRE = 10, ACID = 10)
diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm
index f6c6f00908b75..23cde0b164760 100644
--- a/code/modules/clothing/head/collectable.dm
+++ b/code/modules/clothing/head/collectable.dm
@@ -14,13 +14,13 @@
name = "collectable slime cap!"
desc = "It just latches right in place!"
icon_state = "slime"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/xenom
name = "collectable xenomorph helmet!"
desc = "Hiss hiss hiss!"
icon_state = "xenom"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/collectable/chef
name = "collectable chef's hat"
@@ -32,40 +32,40 @@
name = "collectable paper hat"
desc = "What looks like an ordinary paper hat, is actually a rare and valuable collector's edition paper hat. Keep away from water, fire and Librarians."
icon_state = "paper"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/tophat
name = "collectable top hat"
desc = "A top hat worn by only the most prestigious hat collectors."
icon_state = "tophat"
item_state = "that"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/captain
name = "collectable captain's hat"
desc = "A Collectable Hat that'll make you look just like a real comdom!"
icon_state = "captain"
item_state = "caphat"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/police
name = "collectable police officer's hat"
desc = "A Collectable Police Officer's Hat. This hat emphasizes that you are THE LAW."
icon_state = "policehelm"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/beret
name = "collectable beret"
desc = "A Collectable red Beret. It smells faintly of Garlic."
icon_state = "beret"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/welding
name = "collectable welding helmet"
desc = "A Collectable Welding Helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this Helmet is done so at the owner's own risk!"
icon_state = "welding"
item_state = "welding"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/collectable/slime
name = "collectable slime hat"
@@ -84,14 +84,14 @@
desc = "You'd make a great Dread Syndie Roberts!"
icon_state = "pirate"
item_state = "pirate"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/rabbitears
name = "collectable rabbit ears"
desc = "Not as lucky as the feet!"
icon_state = "bunny"
item_state = "bunny"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/wizard
name = "collectable wizard's hat"
@@ -103,13 +103,13 @@
desc = "WARNING! Offers no real protection, or luminosity, but it is damn fancy!"
icon_state = "hardhat0_yellow"
item_state = "hardhat0_yellow"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/HoS
name = "collectable HoS hat"
desc = "Now you can beat prisoners, set silly sentences and arrest for no reason too!"
icon_state = "hoscap"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/collectable/thunderdome
name = "collectable Thunderdome helmet"
diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm
index 859d238dc30d4..872f25b1a20ba 100644
--- a/code/modules/clothing/head/hardhat.dm
+++ b/code/modules/clothing/head/hardhat.dm
@@ -6,7 +6,7 @@
soft_armor = list(MELEE = 30, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, FIRE = 10, ACID = 10)
actions_types = list(/datum/action/item_action/toggle)
siemens_coefficient = 0.9
- flags_inventory = BLOCKSHARPOBJ
+ inventory_flags = BLOCKSHARPOBJ
light_range = 4
light_power = 2
var/hardhat_color = "yellow" //Determines used sprites: hardhat[on]_[hardhat_color]
@@ -37,14 +37,14 @@
update_action_button_icons()
update_icon()
-/obj/item/clothing/head/hardhat/attack_alien(mob/living/carbon/xenomorph/X, isrightclick = FALSE)
- if(turn_light(X, FALSE) != CHECKS_PASSED)
+/obj/item/clothing/head/hardhat/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(turn_light(xeno_attacker, FALSE) != CHECKS_PASSED)
return
playsound(loc, "alien_claw_metal", 25, 1)
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- to_chat(X, span_warning("We disable the metal thing's lights.") )
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ to_chat(xeno_attacker, span_warning("We disable the metal thing's lights.") )
-/obj/item/clothing/head/hardhat/update_icon()
+/obj/item/clothing/head/hardhat/update_icon_state()
. = ..()
icon_state = "hardhat[light_on]_[hardhat_color]"
item_state = "hardhat[light_on]_[hardhat_color]"
@@ -57,15 +57,15 @@
icon_state = "hardhat0_red"
hardhat_color = "red"
name = "firefighter helmet"
- flags_inventory = NOPRESSUREDMAGE|BLOCKSHARPOBJ
- flags_heat_protection = HEAD
+ inventory_flags = NOPRESSUREDMAGE|BLOCKSHARPOBJ
+ heat_protection_flags = HEAD
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/head/hardhat/white
icon_state = "hardhat0_white"
hardhat_color = "white"
- flags_inventory = NOPRESSUREDMAGE|BLOCKSHARPOBJ
- flags_heat_protection = HEAD
+ inventory_flags = NOPRESSUREDMAGE|BLOCKSHARPOBJ
+ heat_protection_flags = HEAD
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/head/hardhat/dblue
diff --git a/code/modules/clothing/head/head.dm b/code/modules/clothing/head/head.dm
index c503b4bbd0d4e..950a0078e4d20 100644
--- a/code/modules/clothing/head/head.dm
+++ b/code/modules/clothing/head/head.dm
@@ -5,8 +5,8 @@
slot_l_hand_str = 'icons/mob/inhands/clothing/hats_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/clothing/hats_right.dmi',
)
- flags_armor_protection = HEAD
- flags_equip_slot = ITEM_SLOT_HEAD
+ armor_protection_flags = HEAD
+ equip_slot_flags = ITEM_SLOT_HEAD
w_class = WEIGHT_CLASS_SMALL
blood_sprite_state = "helmetblood"
attachments_by_slot = list(ATTACHMENT_SLOT_BADGE)
@@ -39,10 +39,11 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "beanie_cargo"
- flags_inv_hide = HIDETOPHAIR
+ inv_hide_flags = HIDETOPHAIR
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
@@ -52,66 +53,67 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "beret"
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
- flags_item_map_variant = NONE
- flags_armor_features = ARMOR_NO_DECAP
+ item_map_variant_flags = NONE
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/tgmcberet/tan
name = "\improper Tan beret"
icon_state = "berettan"
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
/obj/item/clothing/head/tgmcberet/red
name = "\improper Red badged beret"
icon_state = "beretred"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/red2
name = "\improper Red beret"
icon_state = "beretred2"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/bloodred
name = "\improper Blood red beret"
icon_state = "bloodred_beret"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/blueberet
name = "\improper Blue beret"
icon_state = "blue_beret"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/darkgreen
name = "\improper Dark green beret"
icon_state = "darkgreen_beret"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/green
name = "\improper Green beret"
icon_state = "beretgreen"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/snow
name = "\improper White beret"
icon_state = "beretsnow"
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/wo
name = "\improper Command Master at Arms beret"
desc = "A beret with the lieutenant insignia emblazoned on it. It shines with the glow of corrupt authority and a smudge of doughnut."
icon_state = "beretwo"
soft_armor = list(MELEE = 15, BULLET = 50, LASER = 50, ENERGY = 15, BOMB = 50, BIO = 5, FIRE = 50, ACID = 5)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmcberet/fc
name = "\improper Field Commander beret"
desc = "A beret with the field commander insignia emblazoned on it. It commands loyalty and bravery in all who gaze upon it."
icon_state = "beretfc"
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 5, FIRE = 50, ACID = 50)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/head/tgmccap
@@ -121,12 +123,13 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
var/flipped_cap = FALSE
var/base_cap_icon
- flags_item_map_variant = (ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_ICE_VARIANT)
/obj/item/clothing/head/tgmccap/verb/fliphat()
@@ -163,7 +166,7 @@
name = "\improper TGMC requisition cap"
desc = "It's a fancy hat for a not-so-fancy military supply clerk."
icon_state = "cargocap"
- flags_item_map_variant = null
+ item_map_variant_flags = null
/obj/item/clothing/head/boonie
@@ -179,9 +182,10 @@
icon_state = "ornamented_cap"
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
- slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',)
+ slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi'
+ )
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
- flags_armor_features = ARMOR_NO_DECAP
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/slouch
name = "\improper TGMC slouch hat"
@@ -199,11 +203,12 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "headband"
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
- flags_armor_features = ARMOR_NO_DECAP
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/headband/red
name = "\improper Red headband"
@@ -227,8 +232,9 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
/obj/item/clothing/head/cmo
name = "\improper Chief Medical hat"
@@ -244,7 +250,7 @@
desc = "A beret with the TGMC insignia emblazoned on it. It radiates respect and authority."
icon_state = "hosberet"
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
- flags_inventory = BLOCKSHARPOBJ
+ inventory_flags = BLOCKSHARPOBJ
/obj/item/clothing/head/beret/marine/captain
name = "captain's beret"
@@ -279,10 +285,10 @@
icon_state = "ushankadown"
item_state = "ushankadown"
soft_armor = list(MELEE = 35, BULLET = 35, LASER = 20, ENERGY = 10, BOMB = 10, BIO = 0, FIRE = 10, ACID = 10)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDETOPHAIR
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDETOPHAIR
anti_hug = 1
/obj/item/clothing/head/ushanka/attack_self(mob/user as mob)
@@ -303,12 +309,12 @@
icon_state = "bearpelt"
siemens_coefficient = 2
anti_hug = 4
- flags_armor_protection = HEAD|CHEST|ARMS
+ armor_protection_flags = HEAD|CHEST|ARMS
soft_armor = list(MELEE = 90, BULLET = 70, LASER = 45, ENERGY = 55, BOMB = 45, BIO = 10, FIRE = 55, ACID = 55)
- flags_cold_protection = HEAD|CHEST|ARMS
+ cold_protection_flags = HEAD|CHEST|ARMS
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDETOPHAIR
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDETOPHAIR
/obj/item/clothing/head/uppcap
@@ -318,17 +324,18 @@
icon_state = "upp_cap"
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
siemens_coefficient = 2
//anti_hug = 2
- flags_armor_protection = HEAD
+ armor_protection_flags = HEAD
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 55, BOMB = 50, BIO = 50, FIRE = 55, ACID = 55)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS
- flags_armor_features = ARMOR_NO_DECAP
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/uppcap/beret
name = "\improper armored USL beret"
@@ -340,17 +347,18 @@
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "freelancer_helmet"
siemens_coefficient = 2
- flags_armor_protection = HEAD
+ armor_protection_flags = HEAD
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 55, BOMB = 50, BIO = 50, FIRE = 55, ACID = 55)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS
- flags_armor_features = ARMOR_NO_DECAP
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS
+ armor_features_flags = ARMOR_NO_DECAP
attachments_by_slot = list(
ATTACHMENT_SLOT_STORAGE,
ATTACHMENT_SLOT_HEAD_MODULE,
@@ -380,49 +388,52 @@
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "rebel_hood"
siemens_coefficient = 2
- flags_armor_protection = HEAD|CHEST
+ armor_protection_flags = HEAD|CHEST
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, FIRE = 50, ACID = 50)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDETOPHAIR
- flags_armor_features = ARMOR_NO_DECAP
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDETOPHAIR
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/admiral
name = "\improper armored admiral cap"
desc = "A sturdy admiral's cap. More protective than it seems. Please don't ditch this for a helmet like a punk."
icon_state = "admiral_helmet"
siemens_coefficient = 2
- flags_armor_protection = HEAD
+ armor_protection_flags = HEAD
soft_armor = list(MELEE = 60, BULLET = 60, LASER = 45, ENERGY = 55, BOMB = 55, BIO = 10, FIRE = 55, ACID = 55)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS
/obj/item/clothing/head/commissar
name = "\improper commissar cap"
desc = "A cap worn by commissars of the Imperial Army. This one seems to radiate authority."
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
icon_state = "commissar_cap"
soft_armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 15, BIO = 10, FIRE = 20, ACID = 20)
- flags_armor_features = ARMOR_NO_DECAP
+ armor_features_flags = ARMOR_NO_DECAP
/obj/item/clothing/head/strawhat
name = "\improper straw hat"
desc = "A hat lined with durathread on the outside, has the usual iconic look of a straw hat. A common hat across the bubble."
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
icon_state = "straw_hat"
soft_armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 15, BIO = 10, FIRE = 20, ACID = 20)
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 6dfdb9f2f144c..9bdd311fb7315 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -6,37 +6,37 @@
item_state = "helmet"
accuracy_mod = 0
soft_armor = list(MELEE = 50, BULLET = 15, LASER = 50, ENERGY = 10, BOMB = 25, BIO = 0, FIRE = 10, ACID = 10)
- flags_atom = CONDUCT
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES
- flags_cold_protection = HEAD
- flags_heat_protection = HEAD
+ atom_flags = CONDUCT
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES
+ cold_protection_flags = HEAD
+ heat_protection_flags = HEAD
min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
siemens_coefficient = 0.7
w_class = WEIGHT_CLASS_NORMAL
- flags_armor_features = ARMOR_NO_DECAP
- flags_item = SYNTH_RESTRICTED
+ armor_features_flags = ARMOR_NO_DECAP
+ item_flags = SYNTH_RESTRICTED
/obj/item/clothing/head/helmet/riot
name = "riot helmet"
desc = "It's a helmet specifically designed to protect against close range attacks. It covers your ears."
icon_state = "riot"
soft_armor = list(MELEE = 82, BULLET = 15, LASER = 5, ENERGY = 5, BOMB = 5, BIO = 2, FIRE = 5, ACID = 5)
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDETOPHAIR
- flags_item = SYNTH_RESTRICTED
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDETOPHAIR
+ item_flags = SYNTH_RESTRICTED
/obj/item/clothing/head/helmet/HoS
name = "Head of Security Hat"
desc = "The hat of the Head of Security. For showing the officers who's in charge."
icon_state = "hoscap"
soft_armor = list(MELEE = 80, BULLET = 60, LASER = 50, ENERGY = 10, BOMB = 25, BIO = 10, FIRE = 10, ACID = 10)
- flags_inventory = COVEREYES
- flags_inv_hide = HIDEEARS
- flags_armor_protection = NONE
+ inventory_flags = COVEREYES
+ inv_hide_flags = HIDEEARS
+ armor_protection_flags = NONE
siemens_coefficient = 0.8
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
/obj/item/clothing/head/helmet/HoS/dermal
name = "Dermal Armour Patch"
@@ -49,25 +49,25 @@
name = "warden's hat"
desc = "It's a special helmet issued to the Warden of a securiy force. Protects the head from impacts."
icon_state = "policehelm"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = NONE
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/helmet/hop
name = "crew resource's hat"
desc = "A stylish hat that both protects you from enraged former-crewmembers and gives you a false sense of authority."
icon_state = "hopcap"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = NONE
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/helmet/formalcaptain
name = "parade hat"
desc = "No one in a commanding position should be without a perfect, white hat of ultimate authority."
icon_state = "officercap"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = NONE
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/helmet/swat
name = "\improper SWAT helmet"
@@ -75,23 +75,23 @@
icon_state = "swat"
item_state = "swat"
soft_armor = list(MELEE = 80, BULLET = 60, LASER = 50, ENERGY = 25, BOMB = 50, BIO = 10, FIRE = 25, ACID = 25)
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES
- flags_cold_protection = HEAD
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES
+ cold_protection_flags = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.5
anti_hug = 1
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
/obj/item/clothing/head/helmet/thunderdome
name = "\improper Thunderdome helmet"
desc = "'Let the battle commence!'"
icon_state = "thunderdome"
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES
item_state = "thunderdome"
soft_armor = list(MELEE = 80, BULLET = 60, LASER = 50, ENERGY = 10, BOMB = 25, BIO = 10, FIRE = 10, ACID = 10)
- flags_cold_protection = HEAD
+ cold_protection_flags = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 1
@@ -100,8 +100,8 @@
desc = "Ave, Imperator, morituri te salutant."
icon_state = "gladiator"
item_state = "gladiator"
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEALLHAIR
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEALLHAIR
siemens_coefficient = 1
/*===========================MARINES HELMETS=================================
@@ -114,14 +114,15 @@
icon = 'icons/obj/clothing/headwear/marine_helmets.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_helmets.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "helmet"
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, FIRE = 50, ACID = 50)
max_integrity = 5
var/list/helmet_overlays
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS
attachments_by_slot = list(
ATTACHMENT_SLOT_STORAGE,
)
@@ -130,7 +131,7 @@
)
starting_attachments = list(/obj/item/armor_module/storage/helmet)
///marine helmet behaviour flags
- var/flags_marine_helmet = HELMET_GARB_OVERLAY|HELMET_STORE_GARB
+ var/marine_helmet_flags = HELMET_GARB_OVERLAY|HELMET_STORE_GARB
/// items that fit in the helmet: strict type = iconstate to show
var/static/list/allowed_helmet_items = list(
/obj/item/tool/lighter/random = "helmet_lighter_",
@@ -161,14 +162,23 @@
. = ..()
helmet_overlays = list("damage","band","item") //To make things simple.
-/obj/item/clothing/head/helmet/marine/update_icon()
+/obj/item/clothing/head/helmet/marine/on_pocket_insertion()
+ . = ..()
+ update_helmet_overlays()
+
+/obj/item/clothing/head/helmet/marine/on_pocket_removal()
+ . = ..()
+ update_helmet_overlays()
+
+///Updates the helmet_overlays list, inserting and removing images from it as necesarry
+/obj/item/clothing/head/helmet/marine/proc/update_helmet_overlays()
if(!attachments_by_slot[ATTACHMENT_SLOT_STORAGE])
return
if(!istype(attachments_by_slot[ATTACHMENT_SLOT_STORAGE], /obj/item/armor_module/storage))
return
var/obj/item/armor_module/storage/armor_storage = attachments_by_slot[ATTACHMENT_SLOT_STORAGE]
- if(length(armor_storage.storage.contents) && (flags_marine_helmet & HELMET_GARB_OVERLAY))
+ if(length(armor_storage.storage.contents) && (marine_helmet_flags & HELMET_GARB_OVERLAY))
if(!helmet_overlays["band"])
var/image/I = image('icons/obj/clothing/headwear/marine_hats.dmi', src, "helmet_band")
helmet_overlays["band"] = I
@@ -200,32 +210,34 @@
var/mutable_appearance/M
for(var/i in helmet_overlays)
M = helmet_overlays[i]
- if(M)
- M = mutable_appearance('icons/mob/modular/modular_helmet_storage.dmi',M.icon_state)
- standing.overlays += M
+ if(!M)
+ continue
+
+ M = mutable_appearance('icons/mob/modular/modular_helmet_storage.dmi', M.icon_state)
+ standing.overlays += M
/obj/item/clothing/head/helmet/marine/specialist
name = "\improper B18 helmet"
desc = "The B18 Helmet that goes along with the B18 Defensive Armor. It's heavy, reinforced, and protects more of the face."
icon_state = "minigunner_helmet"
soft_armor = list(MELEE = 75, BULLET = 80, LASER = 75, ENERGY = 65, BOMB = 70, BIO = 65, FIRE = 65, ACID = 65)
- flags_inv_hide = HIDEALLHAIR|HIDEEARS
- flags_item = SYNTH_RESTRICTED
+ inv_hide_flags = HIDEALLHAIR|HIDEEARS
+ item_flags = SYNTH_RESTRICTED
resistance_flags = UNACIDABLE
anti_hug = 6
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT|ITEM_ICE_PROTECTION)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT|ITEM_ICE_PROTECTION)
/obj/item/clothing/head/helmet/marine/grenadier
name = "\improper B17 helmet"
desc = "A heavy duty helmet created to complement the B17 marine armor. Practically explosive proof. Unless you stand next to a nuke or something like that."
icon_state = "grenadier_helmet"
soft_armor = list(MELEE = 75, BULLET = 70, LASER = 60, ENERGY = 65, BOMB = 100, BIO = 60, FIRE = 65, ACID = 60)
- flags_inv_hide = HIDEALLHAIR|HIDEEARS
+ inv_hide_flags = HIDEALLHAIR|HIDEEARS
max_heat_protection_temperature = HEAVYARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
resistance_flags = UNACIDABLE
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
anti_hug = 4
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT|ITEM_ICE_PROTECTION)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT|ITEM_ICE_PROTECTION)
/obj/item/clothing/head/helmet/marine/pilot
name = "\improper M30 tactical helmet"
@@ -233,10 +245,10 @@
icon_state = "helmetp2"
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, FIRE = 50, ACID = 50)
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDETOPHAIR
- flags_marine_helmet = NONE
- flags_item_map_variant = null
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDETOPHAIR
+ marine_helmet_flags = NONE
+ item_map_variant_flags = null
/obj/item/clothing/head/helmet/marine/pilot/green
name = "\improper M30 tactical helmet"
@@ -249,14 +261,26 @@
desc = "A lightweight helmet with a small port in the back. Offers lower response times for TGMC mech pilots by integrating them directly into their mech suit's systems, though it certainly doesn't make them smarter."
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
+/obj/item/clothing/head/helmet/marine/assault_crewman
+ name = "\improper M12B pattern tanker helmet"
+ icon_state = "assault_crewman_helmet"
+ desc = "A lightweight helmet. Offers the user protection from being hit in the hell by ejected shell casings, mostly."
+ min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
+
+/obj/item/clothing/head/helmet/marine/transport_crewman
+ name = "\improper M12A pattern transport helmet"
+ icon_state = "transport_crewman_helmet"
+ desc = "A lightweight helmet with a small port in the back. Offers decent protection against reckless driving."
+ min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
+
/obj/item/clothing/head/helmet/marine/riot
name = "M8 riot helmet"
desc = "It's a modified version of the widely used Riot Helmets for use against angry jarheads. Boasts high ballistic protection"
icon_state = "marine_riot"
soft_armor = list(MELEE = 65, BULLET = 110, LASER = 110, ENERGY = 5, BOMB = 50, BIO = 50, FIRE = 50, ACID = 30)
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDETOPHAIR
- flags_item = SYNTH_RESTRICTED
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDETOPHAIR
+ item_flags = SYNTH_RESTRICTED
/*=============================PMCS==================================
=======================================================================*/
@@ -265,9 +289,10 @@
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
- flags_item = SYNTH_RESTRICTED
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
+ item_flags = SYNTH_RESTRICTED
/obj/item/clothing/head/helmet/marine/veteran/pmc
name = "\improper PMC tactical helmet"
@@ -275,9 +300,9 @@
icon_state = "pmc_helmet"
soft_armor = list(MELEE = 65, BULLET = 65, LASER = 60, ENERGY = 55, BOMB = 60, BIO = 50, FIRE = 55, ACID = 55)
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = NONE
- flags_marine_helmet = NONE
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = NONE
+ marine_helmet_flags = NONE
/obj/item/clothing/head/helmet/marine/veteran/pmc/leader
name = "\improper PMC beret"
@@ -289,28 +314,28 @@
name = "\improper PMC sniper helmet"
desc = "A helmet worn by PMC Marksmen"
icon_state = "pmc_sniper_hat"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 65, BULLET = 75, LASER = 55, ENERGY = 60, BOMB = 70, BIO = 50, FIRE = 60, ACID = 60)
- flags_inventory = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
+ inventory_flags = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
/obj/item/clothing/head/helmet/marine/veteran/pmc/gunner
name = "\improper PMC gunner helmet"
desc = "A modification of the standard helmet used by a lot of security firms, has a visor for added protection."
icon_state = "pmc_heavyhelmet"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 75, BULLET = 85, LASER = 80, ENERGY = 65, BOMB = 80, BIO = 50, FIRE = 65, ACID = 65)
- flags_inventory = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
+ inventory_flags = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
/obj/item/clothing/head/helmet/marine/veteran/pmc/commando
name = "\improper PMC commando helmet"
desc = "A fully enclosed, armored helmet made for Nanotrasen elite commandos."
icon_state = "commando_helmet"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 95, BULLET = 120, LASER = 200, ENERGY = 200, BOMB = 90, BIO = 100, FIRE = 90, ACID = 95)
- flags_inventory = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ|BLOCKGASEFFECT
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
+ inventory_flags = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ|BLOCKGASEFFECT
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
eye_protection = 2
anti_hug = 50
resistance_flags = UNACIDABLE
@@ -327,10 +352,11 @@
icon_state = "guardhelm"
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
item_state = "guardhelm"
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 85, BULLET = 75, LASER = 70, ENERGY = 70, BOMB = 60, BIO = 50, FIRE = 50, ACID = 50)
/obj/item/clothing/head/helmet/marine/imperial/sergeant
@@ -351,10 +377,11 @@
icon = 'icons/obj/clothing/headwear/ert_headwear.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "upp_helmet1"
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 70, BULLET = 55, LASER = 40, ENERGY = 35, BOMB = 35, BIO = 5, FIRE = 35, ACID = 35)
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
@@ -373,12 +400,13 @@
icon = 'icons/obj/clothing/headwear/marine_hats.dmi'
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/marine_hats.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
icon_state = "spec"
soft_armor = list(MELEE = 35, BULLET = 35, LASER = 35, ENERGY = 15, BOMB = 10, BIO = 0, FIRE = 15, ACID = 15)
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS
/*===========================HELGHAST - MERCENARY================================
=====================================================================*/
@@ -387,17 +415,17 @@
name = "\improper K12 ceramic helmet"
desc = "A sturdy helmet worn by an unknown mercenary group."
icon_state = "mercenary_heavy_helmet"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 70, BIO = 10, FIRE = 60, ACID = 60)
- flags_inventory = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
- flags_marine_helmet = NONE
+ inventory_flags = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK|HIDEALLHAIR
+ marine_helmet_flags = NONE
/obj/item/clothing/head/helmet/marine/veteran/mercenary/miner
name = "\improper Y8 miner helmet"
desc = "A sturdy helmet worn by an unknown mercenary group."
icon_state = "mercenary_miner_helmet"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 55, BULLET = 55, LASER = 45, ENERGY = 55, BOMB = 55, BIO = 10, FIRE = 55, ACID = 55)
@@ -405,7 +433,7 @@
name = "\improper Z7 engineer helmet"
desc = "A sturdy helmet worn by an unknown mercenary group."
icon_state = "mercenary_engineer_helmet"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 55, BULLET = 60, LASER = 45, ENERGY = 55, BOMB = 60, BIO = 10, FIRE = 55, ACID = 55)
@@ -417,14 +445,15 @@
icon_state = "som_helmet"
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
item_state = "som_helmet"
soft_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, FIRE = 50, ACID = 50)
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = NONE
- flags_marine_helmet = NONE
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = NONE
+ marine_helmet_flags = NONE
/obj/item/clothing/head/helmet/marine/som/veteran
@@ -447,7 +476,7 @@
desc = "A field of invisible energy, it protects the wearer but prevents any clothing from being worn."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-blue"
- flags_item = DELONDROP
+ item_flags = DELONDROP
soft_armor = list(MELEE = 65, BULLET = 60, LASER = 30, ENERGY = 20, BOMB = 25, BIO = 40, FIRE = 20, ACID = 20)
anti_hug = 5
@@ -462,8 +491,9 @@
icon_state = "icc"
item_icons = list(
slot_head_str = 'icons/mob/clothing/headwear/ert_headwear.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',)
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
+ )
item_state = "icc"
soft_armor = list(MELEE = 50, BULLET = 60, LASER = 50, ENERGY = 60, BOMB = 70, BIO = 10, FIRE = 60, ACID = 50)
@@ -473,3 +503,10 @@
icon_state = "icc_guard"
item_state = "icc_guard"
soft_armor = list(MELEE = 60, BULLET = 65, LASER = 40, ENERGY = 60, BOMB = 80, BIO = 10, FIRE = 55, ACID = 40)
+
+/obj/item/clothing/head/helmet/marine/icc/guard/heavy
+ name = "\improper Modelle/22 combat helmet"
+ desc = "A high-quality ICCGF helmet, mostly seen worn by the ICC's highest quality troops, better well known as 'Guardsmen'. Like most helmets of the ICC it is made to fit a utility and combat role with noticeably high resistance to explosions and bullets, this one is heavily reinforced."
+ icon_state = "icc_guard_heavy"
+ item_state = "icc_guard_heavy"
+ soft_armor = list(MELEE = 65, BULLET = 70, LASER = 40, ENERGY = 60, BOMB = 85, BIO = 10, FIRE = 55, ACID = 40)
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 54acc577bce85..dc7590ddd23d1 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -22,31 +22,31 @@
name = "captain's cap"
desc = "You fear to wear it for the negligence it brings."
icon_state = "capcap"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = NONE
- flags_cold_protection = HEAD
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = NONE
+ cold_protection_flags = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
//Chaplain
/obj/item/clothing/head/chaplain_hood
name = "chaplain's hood"
desc = "It's hood that covers the head. It keeps you warm during the space winters."
icon_state = "chaplain_hood"
- flags_inventory = COVEREYES
- flags_inv_hide = HIDEEARS|HIDEALLHAIR
+ inventory_flags = COVEREYES
+ inv_hide_flags = HIDEEARS|HIDEALLHAIR
siemens_coefficient = 0.9
- flags_armor_protection = HEAD|EYES
+ armor_protection_flags = HEAD|EYES
//Chaplain
/obj/item/clothing/head/nun_hood
name = "nun hood"
desc = "Maximum piety in this star system."
icon_state = "nun_hood"
- flags_inventory = COVEREYES
- flags_inv_hide = HIDEEARS|HIDEALLHAIR
+ inventory_flags = COVEREYES
+ inv_hide_flags = HIDEEARS|HIDEALLHAIR
siemens_coefficient = 0.9
//Mime
@@ -56,7 +56,7 @@
icon_state = "beret"
siemens_coefficient = 0.9
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 10, BIO = 5, FIRE = 5, ACID = 5)
- flags_armor_features = ARMOR_NO_DECAP
+ armor_features_flags = ARMOR_NO_DECAP
//Security
/obj/item/clothing/head/beret/sec
@@ -91,7 +91,7 @@
name = "surgical cap"
desc = "A cap surgeons wear during operations. Keeps their hair from tickling your internal organs."
icon_state = "surgcap_blue"
- flags_inv_hide = HIDETOPHAIR
+ inv_hide_flags = HIDETOPHAIR
/obj/item/clothing/head/surgery/purple
desc = "A cap surgeons wear during operations. Keeps their hair from tickling your internal organs. This one is deep purple."
@@ -116,7 +116,7 @@
allowed = list(/obj/item/reagent_containers/food/snacks/candy_corn, /obj/item/tool/pen)
soft_armor = list(MELEE = 50, BULLET = 5, LASER = 25, ENERGY = 10, BOMB = 0, BIO = 0, FIRE = 10, ACID = 10)
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/det_hat/black
icon_state = "detective2"
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index e42e6667a54c4..c4cbb90011136 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -6,14 +6,14 @@
desc = "It's good to be emperor."
item_state = "centhat"
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/hairflower
name = "hair flower pin"
icon_state = "hairflower"
desc = "Smells nice."
item_state = "hairflower"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
w_class = WEIGHT_CLASS_TINY
/obj/item/clothing/head/powdered_wig
@@ -28,13 +28,13 @@
icon_state = "tophat"
item_state = "that"
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/redcoat
name = "redcoat's hat"
icon_state = "redcoat"
desc = "'I guess it's a redhead.'"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/plaguedoctorhat
name = "plague doctor's hat"
@@ -42,69 +42,69 @@
icon_state = "plaguedoctor"
permeability_coefficient = 0.01
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/hasturhood
name = "hastur's hood"
desc = "It's unspeakably stylish"
icon_state = "hasturhood"
- flags_inventory = COVEREYES
- flags_inv_hide = HIDEEARS|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVEREYES
+ inv_hide_flags = HIDEEARS|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/nursehat
name = "nurse's hat"
desc = "It allows quick identification of trained medical personnel."
icon_state = "nursehat"
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/syndicatefake
name = "red space-helmet replica"
icon_state = "syndicate"
item_state = "syndicate"
desc = "A plastic replica of a syndicate agent's space helmet, you'll look just like a real murderous syndicate agent in this! This is a toy, it is not made for use in space!"
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
siemens_coefficient = 2
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
anti_hug = 1
/obj/item/clothing/head/cueball
name = "cueball helmet"
desc = "A large, featureless white orb mean to be worn on your head. How do you even see out of this thing?"
icon_state = "cueball"
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
item_state="cueball"
- flags_inventory = NONE
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = NONE
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/greenbandanna
name = "green bandanna"
desc = "It's a green bandanna with some fine nanotech lining."
icon_state = "greenbandanna"
item_state = "greenbandanna"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = NONE
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/cardborg
name = "cardborg helmet"
desc = "A helmet made out of a box."
icon_state = "cardborg_h"
item_state = "cardborg_h"
- flags_inventory = COVERMOUTH|COVEREYES
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVERMOUTH|COVEREYES
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/justice
name = "justice hat"
desc = "fight for what's righteous!"
icon_state = "justicered"
item_state = "justicered"
- flags_inventory = COVERMOUTH|COVEREYES
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ inventory_flags = COVERMOUTH|COVEREYES
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
/obj/item/clothing/head/flatcap
name = "flat cap"
@@ -118,15 +118,15 @@
desc = "Yarr."
icon_state = "pirate"
item_state = "pirate"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/hgpiratecap
name = "pirate hat"
desc = "Yarr."
icon_state = "hgpiratecap"
item_state = "hgpiratecap"
- flags_armor_protection = NONE
- flags_item = SYNTH_RESTRICTED
+ armor_protection_flags = NONE
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 50, BULLET = 80, LASER = 50, ENERGY = 10, BOMB = 50, BIO = 0, FIRE = 10, ACID = 10)
/obj/item/clothing/head/bandanna/brown
@@ -152,7 +152,7 @@
desc = "Gentleman, elite aboard!"
icon_state = "bowler"
item_state = "bowler"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
//stylish bs12 hats
@@ -161,7 +161,7 @@
icon_state = "bowler_hat"
item_state = "bowler_hat"
desc = "For the gentleman of distinction."
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/beaverhat
name = "beaver hat"
@@ -200,8 +200,8 @@
desc = "Eeeee~heheheheheheh!"
icon_state = "witch"
item_state = "witch"
- flags_inventory = NONE
- flags_inv_hide = HIDEALLHAIR
+ inventory_flags = NONE
+ inv_hide_flags = HIDEALLHAIR
siemens_coefficient = 2
/obj/item/clothing/head/chicken
@@ -209,20 +209,20 @@
desc = "Bkaw!"
icon_state = "chickenhead"
item_state = "chickensuit"
- flags_inventory = NONE
- flags_inv_hide = HIDEALLHAIR
+ inventory_flags = NONE
+ inv_hide_flags = HIDEALLHAIR
siemens_coefficient = 2
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/xenos
name = "xenos helmet"
icon_state = "xenos"
item_state = "xenos_helm"
desc = "A helmet made out of chitinous alien hide."
- flags_inventory = COVERMOUTH|COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ inventory_flags = COVERMOUTH|COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
siemens_coefficient = 2
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
anti_hug = 10 //Lel
/obj/item/clothing/head/white_dress
@@ -266,5 +266,5 @@
desc = "Praise the Omnissiah!"
icon_state = "tp_hood"
item_state = "tp_hood"
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 17dfb785f911c..1501d989906d1 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -17,10 +17,10 @@
item_state = "welding"
var/up = FALSE
soft_armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
- flags_atom = CONDUCT
- flags_inventory = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE
- flags_armor_protection = HEAD|FACE|EYES
+ atom_flags = CONDUCT
+ inventory_flags = COVEREYES|COVERMOUTH|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDEFACE
+ armor_protection_flags = HEAD|FACE|EYES
actions_types = list(/datum/action/item_action/toggle)
siemens_coefficient = 0.9
w_class = WEIGHT_CLASS_NORMAL
@@ -44,16 +44,16 @@
toggle_item_state(usr)
/obj/item/clothing/head/welding/proc/flip_up()
- DISABLE_BITFIELD(flags_inventory, COVEREYES|COVERMOUTH|BLOCKSHARPOBJ)
- DISABLE_BITFIELD(flags_inv_hide, HIDEEARS|HIDEEYES|HIDEFACE)
+ DISABLE_BITFIELD(inventory_flags, COVEREYES|COVERMOUTH|BLOCKSHARPOBJ)
+ DISABLE_BITFIELD(inv_hide_flags, HIDEEARS|HIDEEYES|HIDEFACE)
eye_protection = 0
hug_memory = anti_hug
anti_hug = 0
icon_state = "[initial(icon_state)]up"
/obj/item/clothing/head/welding/proc/flip_down()
- ENABLE_BITFIELD(flags_inventory, COVEREYES|COVERMOUTH|BLOCKSHARPOBJ)
- ENABLE_BITFIELD(flags_inv_hide, HIDEEARS|HIDEEYES|HIDEFACE)
+ ENABLE_BITFIELD(inventory_flags, COVEREYES|COVERMOUTH|BLOCKSHARPOBJ)
+ ENABLE_BITFIELD(inv_hide_flags, HIDEEARS|HIDEEYES|HIDEFACE)
eye_protection = initial(eye_protection)
anti_hug = hug_memory
icon_state = initial(icon_state)
@@ -88,11 +88,11 @@
name = "cake-hat"
desc = "It's tasty looking!"
icon_state = "cake0"
- flags_inventory = COVEREYES
+ inventory_flags = COVEREYES
var/onfire = 0
var/status = 0
var/processing = 0 //I dont think this is used anywhere.
- flags_armor_protection = EYES
+ armor_protection_flags = EYES
/obj/item/clothing/head/cakehat/process()
if(!onfire)
@@ -123,9 +123,9 @@
desc = "A jack o' lantern! Believed to ward off evil spirits."
icon_state = "hardhat0_pumpkin"//Could stand to be renamed
item_state = "hardhat0_pumpkin"
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
- flags_armor_protection = HEAD|EYES
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ armor_protection_flags = HEAD|EYES
w_class = WEIGHT_CLASS_NORMAL
anti_hug = 1
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index 3280889ddc896..86d6b25fcc413 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -3,11 +3,11 @@
desc = "It's a baseball hat in a tasteless yellow color."
icon_state = "cargosoft"
item_state = "cargosoft"
- flags_inventory = COVEREYES
+ inventory_flags = COVEREYES
var/cap_color = "cargo"
var/flipped = 0
siemens_coefficient = 0.9
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/soft/dropped()
icon_state = "[cap_color]soft"
@@ -104,7 +104,7 @@
icon_state = "greysoft"
cap_color = "grey"
soft_armor = list(MELEE = 35, BULLET = 35, LASER = 35, ENERGY = 15, BOMB = 10, BIO = 0, FIRE = 15, ACID = 15)
- flags_inventory = BLOCKSHARPOBJ
+ inventory_flags = BLOCKSHARPOBJ
/obj/item/clothing/head/soft/marine/alpha
name = "alpha squad sergeant cap"
diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm
index 6782a60a09518..9c023f2ada7a6 100644
--- a/code/modules/clothing/masks/breath.dm
+++ b/code/modules/clothing/masks/breath.dm
@@ -3,8 +3,8 @@
name = "breath mask"
icon_state = "breath"
item_state = "breath"
- flags_inventory = COVERMOUTH
- flags_armor_protection = NONE
+ inventory_flags = COVERMOUTH
+ armor_protection_flags = NONE
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.10
permeability_coefficient = 0.50
@@ -20,14 +20,14 @@
if(!src.hanging)
src.hanging = !src.hanging
gas_transfer_coefficient = 1 //gas is now escaping to the turf and vice versa
- flags_inventory &= ~(COVERMOUTH)
+ inventory_flags &= ~(COVERMOUTH)
icon_state = "breathdown"
to_chat(usr, "Your mask is now hanging on your neck.")
else
src.hanging = !src.hanging
gas_transfer_coefficient = 0.10
- flags_inventory |= COVERMOUTH
+ inventory_flags |= COVERMOUTH
icon_state = "breath"
to_chat(usr, "You pull the mask up to cover your face.")
update_clothing_icon()
@@ -48,9 +48,9 @@
desc = "A close-fitting device that instantly heats or cools down air when you inhale so it doesn't damage your lungs."
icon_state = "rebreather"
item_state = "rebreather"
- flags_armor_protection = NONE
- flags_inventory = COVERMOUTH|COVEREYES|BLOCKGASEFFECT
- flags_inv_hide = HIDELOWHAIR
+ armor_protection_flags = NONE
+ inventory_flags = COVERMOUTH|COVEREYES|BLOCKGASEFFECT
+ inv_hide_flags = HIDELOWHAIR
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
@@ -59,8 +59,8 @@
desc = "A close-fitting cap that covers the top, back, and sides of the head. Can also be adjusted to cover the lower part of the face so it keeps the user warm in harsh conditions."
icon_state = "coif"
item_state = "coif"
- flags_inv_hide = HIDEALLHAIR|HIDEEARS
- flags_cold_protection = HEAD
+ inv_hide_flags = HIDEALLHAIR|HIDEEARS
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
/obj/item/clothing/mask/rebreather/scarf/freelancer
@@ -71,9 +71,9 @@
desc = "A colored, resilient, and insulating cloth to cover your face from the elements. This one is Desert Tan"
icon_state = "bandanna"
item_state = "bandanna"
- flags_armor_protection = FACE
- flags_inv_hide = HIDEFACE
- flags_inventory = COVERMOUTH|BLOCKGASEFFECT
+ armor_protection_flags = FACE
+ inv_hide_flags = HIDEFACE
+ inventory_flags = COVERMOUTH|BLOCKGASEFFECT
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
@@ -87,9 +87,9 @@
active = !active
icon_state = "[initial(icon_state)][!active ? "_down" : ""]"
- flags_armor_protection ^= initial(flags_armor_protection)
- flags_inv_hide ^= initial(flags_inv_hide)
- flags_inventory ^= initial(flags_inventory)
+ armor_protection_flags ^= initial(armor_protection_flags)
+ inv_hide_flags ^= initial(inv_hide_flags)
+ inventory_flags ^= initial(inventory_flags)
to_chat(usr, "You [active ? "pull [src] up to cover your face" : "pull [src] off your face"].")
update_clothing_icon()
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 57f195bfadb14..07abd5d1da542 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -5,15 +5,14 @@
desc = "A face-covering mask that can be connected to an air supply. Filters harmful gases from the air."
icon_state = "gas_alt"
item_state = "gas_alt"
- flags_inventory = COVERMOUTH | COVEREYES | BLOCKGASEFFECT
- flags_inv_hide = HIDEEARS|HIDEFACE|HIDELOWHAIR
- flags_cold_protection = HEAD
+ inventory_flags = COVERMOUTH | COVEREYES | BLOCKGASEFFECT
+ inv_hide_flags = HIDEEARS|HIDEFACE|HIDELOWHAIR
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
siemens_coefficient = 0.9
- voice_filter = "lowpass=f=750,volume=2"
var/gas_filter_strength = 1 //For gas mask filters
var/list/filtered_gases = list(/datum/reagent/toxin/phoron, "sleeping_agent", "carbon_dioxide")
///Does this particular mask have breath noises
@@ -40,12 +39,13 @@
/obj/item/clothing/mask/gas/tactical
name = "Tactical gas mask"
icon_state = "gas_alt_tactical"
+ voice_filter = "lowpass=f=750,volume=2"
/obj/item/clothing/mask/gas/tactical/coif
name = "Tactical coifed gas mask"
desc = "A face-covering coifed mask that can be connected to an air supply. Filters harmful gases from the air."
icon_state = "gascoif"
- flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR
+ inv_hide_flags = HIDEEARS|HIDEFACE|HIDEALLHAIR
/obj/item/clothing/mask/gas/pmc
name = "\improper M8 pattern armored balaclava"
@@ -53,10 +53,10 @@
icon_state = "pmc_mask"
item_state = "helmet"
anti_hug = 3
- flags_inventory = COVERMOUTH|BLOCKGASEFFECT
- flags_inv_hide = HIDEEARS|HIDEFACE|HIDEALLHAIR
+ inventory_flags = COVERMOUTH|BLOCKGASEFFECT
+ inv_hide_flags = HIDEEARS|HIDEFACE|HIDEALLHAIR
breathy = FALSE
- voice_filter = null
+ voice_filter = "lowpass=f=750,volume=2"
/obj/item/clothing/mask/gas/pmc/damaged
name = "damaged M8 pattern armored balaclava"
@@ -77,7 +77,6 @@
icon_state = "wolf_mask"
anti_hug = 2
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/icc
name = "\improper Modelle/60 gas mask"
@@ -91,7 +90,7 @@
icon_state = "plaguedoctor"
item_state = "gas_mask"
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 2, ENERGY = 2, BOMB = 0, BIO = 75, FIRE = 2, ACID = 2)
- flags_armor_protection = HEAD|FACE
+ armor_protection_flags = HEAD|FACE
/obj/item/clothing/mask/gas/swat
name = "\improper SWAT mask"
@@ -99,7 +98,20 @@
icon_state = "swat"
anti_hug = 1
siemens_coefficient = 0.7
- flags_armor_protection = FACE|EYES
+ armor_protection_flags = FACE|EYES
+ voice_filter = "lowpass=f=750,volume=2"
+
+/obj/item/clothing/mask/gas/specops
+ name = "Special Operations gasmask"
+ desc = "A close-fitting tactical mask that can be connected to an air supply. Based off an old design of gas masks."
+ icon = 'icons/mob/clothing/mask.dmi'
+ item_icons = list(
+ slot_wear_suit_str = 'icons/mob/clothing/mask.dmi'
+ )
+ icon_state = "specop"
+ item_state = "specop"
+ siemens_coefficient = 0.7
+ voice_filter = "lowpass=f=750,volume=2"
/obj/item/clothing/mask/gas/syndicate
name = "syndicate mask"
@@ -128,7 +140,6 @@
icon_state = "clown"
item_state = "clown_hat"
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/sexyclown
name = "sexy-clown wig and mask"
@@ -136,7 +147,6 @@
icon_state = "sexyclown"
item_state = "sexyclown"
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/mime
name = "mime mask"
@@ -144,16 +154,14 @@
icon_state = "mime"
item_state = "mime"
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
desc = "A mask used when acting as a monkey."
icon_state = "monkeymask"
item_state = "monkeymask"
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/sexymime
name = "sexy mime mask"
@@ -161,7 +169,6 @@
icon_state = "sexymime"
item_state = "sexymime"
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/death_commando
name = "Death Commando Mask"
@@ -174,7 +181,6 @@
desc = "Beep boop"
icon_state = "death"
breathy = FALSE
- voice_filter = null
/obj/item/clothing/mask/gas/owl_mask
name = "owl mask"
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 020be3d630b4e..696b7b4b1ad27 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -3,8 +3,8 @@
desc = "To stop that awful noise."
icon_state = "muzzle"
item_state = "muzzle"
- flags_inventory = COVERMOUTH
- flags_armor_protection = NONE
+ inventory_flags = COVERMOUTH
+ armor_protection_flags = NONE
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.90
@@ -14,8 +14,8 @@
icon_state = "sterile"
item_state = "sterile"
w_class = WEIGHT_CLASS_SMALL
- flags_inventory = COVERMOUTH
- flags_armor_protection = NONE
+ inventory_flags = COVERMOUTH
+ armor_protection_flags = NONE
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.01
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 25, FIRE = 0, ACID = 0)
@@ -24,15 +24,15 @@
name = "fake moustache"
desc = "Warning: moustache is fake."
icon_state = "fake-moustache"
- flags_inv_hide = HIDEFACE
- flags_armor_protection = NONE
+ inv_hide_flags = HIDEFACE
+ armor_protection_flags = NONE
/obj/item/clothing/mask/snorkel
name = "Snorkel"
desc = "For the Swimming Savant."
icon_state = "snorkel"
- flags_inv_hide = HIDEFACE
- flags_armor_protection = NONE
+ inv_hide_flags = HIDEFACE
+ armor_protection_flags = NONE
//scarves (fit in in mask slot)
@@ -41,7 +41,7 @@
desc = "A blue neck scarf."
icon_state = "blueneckscarf"
item_state = "blueneckscarf"
- flags_inventory = COVERMOUTH
+ inventory_flags = COVERMOUTH
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.90
@@ -50,7 +50,7 @@
desc = "A red and white checkered neck scarf."
icon_state = "redwhite_scarf"
item_state = "redwhite_scarf"
- flags_inventory = COVERMOUTH
+ inventory_flags = COVERMOUTH
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.90
@@ -59,7 +59,7 @@
desc = "A green neck scarf."
icon_state = "green_scarf"
item_state = "green_scarf"
- flags_inventory = COVERMOUTH
+ inventory_flags = COVERMOUTH
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.90
@@ -68,7 +68,7 @@
desc = "A stealthy, dark scarf."
icon_state = "ninja_scarf"
item_state = "ninja_scarf"
- flags_inventory = COVERMOUTH
+ inventory_flags = COVERMOUTH
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.90
siemens_coefficient = 0
@@ -78,20 +78,20 @@
desc = "A rubber pig mask."
icon_state = "pig"
item_state = "pig"
- flags_inventory = COVERMOUTH|COVEREYES
- flags_inv_hide = HIDEFACE|HIDEALLHAIR|HIDEEYES|HIDEEARS
+ inventory_flags = COVERMOUTH|COVEREYES
+ inv_hide_flags = HIDEFACE|HIDEALLHAIR|HIDEEYES|HIDEEARS
w_class = WEIGHT_CLASS_SMALL
siemens_coefficient = 0.9
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/mask/horsehead
name = "horse head mask"
desc = "A mask made of soft vinyl and latex, representing the head of a horse."
icon_state = "horsehead"
item_state = "horsehead"
- flags_inventory = COVERMOUTH|COVEREYES
- flags_inv_hide = HIDEFACE|HIDEALLHAIR|HIDEEYES|HIDEEARS
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVERMOUTH|COVEREYES
+ inv_hide_flags = HIDEFACE|HIDEALLHAIR|HIDEEYES|HIDEEARS
+ armor_protection_flags = HEAD|FACE|EYES
w_class = WEIGHT_CLASS_SMALL
var/voicechange = 0
siemens_coefficient = 0.9
@@ -102,8 +102,8 @@
desc = "LOADSAMONEY"
icon_state = "balaclava"
item_state = "balaclava"
- flags_inv_hide = HIDEFACE|HIDEALLHAIR
- flags_armor_protection = FACE
+ inv_hide_flags = HIDEFACE|HIDEALLHAIR
+ armor_protection_flags = FACE
w_class = WEIGHT_CLASS_SMALL
/obj/item/clothing/mask/balaclava/tactical
@@ -118,11 +118,11 @@
desc = "Worn by robust fighters, flying high to defeat their foes!"
icon_state = "luchag"
item_state = "luchag"
- flags_inv_hide = HIDEFACE|HIDEALLHAIR
- flags_cold_protection = HEAD
+ inv_hide_flags = HIDEFACE|HIDEALLHAIR
+ cold_protection_flags = HEAD
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_armor_protection = HEAD|FACE
- flags_inventory = COVERMOUTH
+ armor_protection_flags = HEAD|FACE
+ inventory_flags = COVERMOUTH
w_class = WEIGHT_CLASS_SMALL
siemens_coefficient = 3
diff --git a/code/modules/clothing/modular_armor/attachments.dm b/code/modules/clothing/modular_armor/attachments.dm
index 3a78e5c120428..35441d9cd371d 100644
--- a/code/modules/clothing/modular_armor/attachments.dm
+++ b/code/modules/clothing/modular_armor/attachments.dm
@@ -26,7 +26,7 @@
///Pixel shift for the item overlay on the Y axis.
var/pixel_shift_y = 0
///Bitfield flags of various features.
- var/flags_attach_features = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB
+ var/attach_features_flags = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB
///Time it takes to attach.
var/attach_delay = 1.5 SECONDS
///Time it takes to detach.
@@ -65,7 +65,7 @@
/obj/item/armor_module/Initialize(mapload)
. = ..()
- AddElement(/datum/element/attachment, slot, attach_icon, on_attach, on_detach, null, can_attach, pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, mob_overlay_icon = mob_overlay_icon, mob_pixel_shift_x = mob_pixel_shift_x, mob_pixel_shift_y = mob_pixel_shift_y, attachment_layer = attachment_layer)
+ AddElement(/datum/element/attachment, slot, attach_icon, on_attach, on_detach, null, can_attach, pixel_shift_x, pixel_shift_y, attach_features_flags, attach_delay, detach_delay, mob_overlay_icon = mob_overlay_icon, mob_pixel_shift_x = mob_pixel_shift_x, mob_pixel_shift_y = mob_pixel_shift_y, attachment_layer = attachment_layer)
AddComponent(/datum/component/attachment_handler, attachments_by_slot, attachments_allowed, starting_attachments = starting_attachments)
update_icon()
@@ -81,7 +81,7 @@
parent.hard_armor = parent.hard_armor.attachArmor(hard_armor)
parent.soft_armor = parent.soft_armor.attachArmor(soft_armor)
parent.slowdown += slowdown
- if(CHECK_BITFIELD(flags_attach_features, ATTACH_ACTIVATION))
+ if(CHECK_BITFIELD(attach_features_flags, ATTACH_ACTIVATION))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(handle_actions))
base_icon = icon_state
if(length(variants_by_parent_type))
@@ -107,7 +107,7 @@
///Adds or removes actions based on whether the parent is in the correct slot.
/obj/item/armor_module/proc/handle_actions(datum/source, mob/user, slot)
SIGNAL_HANDLER
- if(prefered_slot && (slot != prefered_slot) || !CHECK_BITFIELD(flags_attach_features, ATTACH_ACTIVATION))
+ if(prefered_slot && (slot != prefered_slot) || !CHECK_BITFIELD(attach_features_flags, ATTACH_ACTIVATION))
LAZYREMOVE(actions_types, /datum/action/item_action/toggle)
var/datum/action/item_action/toggle/old_action = locate(/datum/action/item_action/toggle) in actions
old_action?.remove_action(user)
@@ -121,7 +121,6 @@
/obj/item/armor_module/ui_action_click(mob/user, datum/action/item_action/toggle/action)
action.set_toggle(activate(user))
- action.update_button_icon()
///Called on ui_action_click. Used for activating the module.
/obj/item/armor_module/proc/activate(mob/living/user)
@@ -145,9 +144,9 @@
greyscale_config = null
greyscale_colors = ARMOR_PALETTE_DRAB
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT
///If TRUE, this armor piece can be recolored when its parent is right clicked by facepaint.
var/secondary_color = FALSE
diff --git a/code/modules/clothing/modular_armor/attachments/arm_plates.dm b/code/modules/clothing/modular_armor/attachments/arm_plates.dm
index 80a98f32ae2bd..03ecc155768f0 100644
--- a/code/modules/clothing/modular_armor/attachments/arm_plates.dm
+++ b/code/modules/clothing/modular_armor/attachments/arm_plates.dm
@@ -54,28 +54,11 @@
desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Trooper armor piece."
greyscale_config = /datum/greyscale_config/armor_mk1/trooper
-/obj/item/armor_module/armor/arms/marine/kabuto
- name = "\improper Style Pattern Kabuto arm plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Kabuto armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/kabuto
-
-/obj/item/armor_module/armor/arms/marine/hotaru
- name = "\improper Style Pattern Hotaru arm plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Hotaru armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/hotaru
-
-/obj/item/armor_module/armor/arms/marine/dashe
- name = "\improper Style Pattern Dashe arm plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Dashe armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/dashe
-
// Hardsuit Arm Plates
/obj/item/armor_module/armor/arms/marine/hardsuit_arms
name = "\improper FleckTex Base arm plates"
desc = "Designed for use with the FleckTex WY-01 Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Base armor piece."
starting_attachments = list(/obj/item/armor_module/armor/secondary_color/arm)
- attachments_allowed = list(/obj/item/armor_module/armor/secondary_color/arm)
- attachments_by_slot = list(ATTACHMENT_SLOT_ARM_SECONDARY_COLOR)
greyscale_config = /datum/greyscale_config/hardsuit_variant
/obj/item/armor_module/armor/arms/marine/hardsuit_arms/syndicate_markfive
diff --git a/code/modules/clothing/modular_armor/attachments/badges.dm b/code/modules/clothing/modular_armor/attachments/badges.dm
index 47de6414d3b0b..68e0107d30b01 100644
--- a/code/modules/clothing/modular_armor/attachments/badges.dm
+++ b/code/modules/clothing/modular_armor/attachments/badges.dm
@@ -4,11 +4,11 @@
greyscale_config = /datum/greyscale_config/badge/shield
icon_state = "in_hand"
slot = ATTACHMENT_SLOT_BADGE
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB|ATTACH_NO_HANDS|ATTACH_SAME_ICON
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB|ATTACH_NO_HANDS|ATTACH_SAME_ICON
colorable_allowed = COLOR_WHEEL_ALLOWED
greyscale_colors = COLOR_RED
secondary_color = TRUE
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
///List of selectable styles for where the badge is worn.
var/list/style_list = list(
@@ -89,10 +89,10 @@
icon_state = "beret_badge"
greyscale_config = /datum/greyscale_config/style_hat/badge
slot = ATTACHMENT_SLOT_CAPE_HIGHLIGHT
- flags_attach_features = ATTACH_APPLY_ON_MOB|ATTACH_DIFFERENT_MOB_ICON_STATE
+ attach_features_flags = ATTACH_APPLY_ON_MOB|ATTACH_DIFFERENT_MOB_ICON_STATE
secondary_color = TRUE
greyscale_colors = COLOR_RED
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
colorable_allowed = COLOR_WHEEL_ALLOWED
/obj/item/armor_module/armor/stylehat_badge/classic
@@ -108,10 +108,10 @@
icon_state = "skull"
greyscale_config = /datum/greyscale_config/visors/glyphs
slot = ATTACHMENT_SLOT_CAPE_HIGHLIGHT
- flags_attach_features = ATTACH_APPLY_ON_MOB|ATTACH_SAME_ICON
+ attach_features_flags = ATTACH_APPLY_ON_MOB|ATTACH_SAME_ICON
secondary_color = TRUE
greyscale_colors = COLOR_WHITE
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
colorable_allowed = COLOR_WHEEL_ALLOWED
/obj/item/armor_module/armor/visor_glyph/old
diff --git a/code/modules/clothing/modular_armor/attachments/cape.dm b/code/modules/clothing/modular_armor/attachments/cape.dm
index 21ed11c30d46c..2179af483dbdd 100644
--- a/code/modules/clothing/modular_armor/attachments/cape.dm
+++ b/code/modules/clothing/modular_armor/attachments/cape.dm
@@ -9,7 +9,7 @@
attachment_layer = CAPE_LAYER
prefered_slot = SLOT_W_UNIFORM
greyscale_config = /datum/greyscale_config/cape
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB|ATTACH_ACTIVATION|ATTACH_NO_HANDS
attach_delay = 0 SECONDS
detach_delay = 0 SECONDS
secondary_color = TRUE
@@ -126,27 +126,6 @@
"none",
),
),
- "overlord" = list(
- HOOD = FALSE,
- HIGHLIGHT_VARIANTS = list(
- "overlord",
- "none",
- ),
- ),
- "overlord (alt 1)" = list(
- HOOD = FALSE,
- HIGHLIGHT_VARIANTS = list(
- "overlord (alt)",
- "none",
- ),
- ),
- "overlord (alt 2)" = list(
- HOOD = FALSE,
- HIGHLIGHT_VARIANTS = list(
- "overlord (alt 2)",
- "none",
- ),
- ),
"shoal" = list(
HOOD = FALSE,
HIGHLIGHT_VARIANTS = list(
@@ -168,13 +147,6 @@
"none",
),
),
- "star" = list(
- HOOD = FALSE,
- HIGHLIGHT_VARIANTS = list(
- "star",
- "none",
- ),
- ),
"rapier (right)" = list(
HOOD = FALSE,
HIGHLIGHT_VARIANTS = list(
@@ -189,19 +161,13 @@
"none",
),
),
- "jacket" = list(
- HOOD = FALSE,
- HIGHLIGHT_VARIANTS = list(
- "jacket",
- "none",
- ),
- ),
)
///True if the hood is up, false if not.
var/hood = FALSE
/obj/item/armor_module/armor/cape/update_icon_state()
+ . = ..()
var/obj/item/armor_module/highlight = attachments_by_slot[ATTACHMENT_SLOT_CAPE_HIGHLIGHT]
if(hood)
icon_state = initial(icon_state) + "_[current_variant]_h"
@@ -228,8 +194,8 @@
return
if(parent)
UnregisterSignal(parent, COMSIG_ITEM_EQUIPPED)
- icon_state_variants[current_variant][HOOD] ? ENABLE_BITFIELD(flags_attach_features, ATTACH_ACTIVATION) : DISABLE_BITFIELD(flags_attach_features, ATTACH_ACTIVATION)
- if(CHECK_BITFIELD(flags_attach_features, ATTACH_ACTIVATION) && parent)
+ icon_state_variants[current_variant][HOOD] ? ENABLE_BITFIELD(attach_features_flags, ATTACH_ACTIVATION) : DISABLE_BITFIELD(attach_features_flags, ATTACH_ACTIVATION)
+ if(CHECK_BITFIELD(attach_features_flags, ATTACH_ACTIVATION) && parent)
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(handle_actions))
var/obj/item/armor_module/highlight = attachments_by_slot[ATTACHMENT_SLOT_CAPE_HIGHLIGHT]
if(!icon_state_variants[current_variant][HOOD])
@@ -260,7 +226,7 @@
desc = "A chromatic kama to improve on the design of the 7E badge, this kama is capable of two colors, for all your fashion needs. Hanged from the belt, it serves to flourish the lower extremities. \n Interact with facepaint to color. Attaches onto a uniform."
slot = ATTACHMENT_SLOT_KAMA
attachment_layer = KAMA_LAYER
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB|ATTACH_NO_HANDS
starting_attachments = list(/obj/item/armor_module/armor/cape_highlight/kama)
greyscale_config = /datum/greyscale_config/cape
icon_state_variants = list(
@@ -291,12 +257,12 @@
desc = "A cape to improve on the design of the 7E badge, this cape is capable of six colors, for all your fashion needs. This variation of the cape functions more as a scarf. \n Interact with facepaint to color. Attaches onto a uniform. Activate it to toggle the hood."
icon_state = "highlight"
slot = ATTACHMENT_SLOT_CAPE_HIGHLIGHT
- flags_attach_features = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB|ATTACH_NO_HANDS
colorable_allowed = PRESET_COLORS_ALLOWED|ICON_STATE_VARIANTS_ALLOWED|COLOR_WHEEL_ALLOWED
greyscale_config = /datum/greyscale_config/cape_highlight
secondary_color = TRUE
greyscale_colors = VISOR_PALETTE_GOLD
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
colorable_colors = VISOR_PALETTES_LIST
current_variant = "none"
icon_state_variants = list(
@@ -306,6 +272,7 @@
)
/obj/item/armor_module/armor/cape_highlight/update_icon_state()
+ . = ..()
if(!parent)
return
var/obj/item/armor_module/armor/cape/cape_parent = parent
diff --git a/code/modules/clothing/modular_armor/attachments/chest_plates.dm b/code/modules/clothing/modular_armor/attachments/chest_plates.dm
index ca25651b55a00..1fd46f4c484f7 100644
--- a/code/modules/clothing/modular_armor/attachments/chest_plates.dm
+++ b/code/modules/clothing/modular_armor/attachments/chest_plates.dm
@@ -59,21 +59,6 @@
desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. This armor appears to be marked as a Ranger armor piece."
greyscale_config = /datum/greyscale_config/armor_mk1/ranger
-/obj/item/armor_module/armor/chest/marine/kabuto
- name = "\improper Style Pattern Kabuto chestplates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. This armor appears to be marked as a Kabuto armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/kabuto
-
-/obj/item/armor_module/armor/chest/marine/hotaru
- name = "\improper Style Pattern Hotaru chestplates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. This armor appears to be marked as a Hotaru armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/hotaru
-
-/obj/item/armor_module/armor/chest/marine/dashe
- name = "\improper Style Pattern Dashe chestplates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. This armor appears to be marked as a Dashe armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/dashe
-
// Hardsuit Chest Plates
/obj/item/armor_module/armor/chest/marine/hardsuit
icon_state_variants = list(
@@ -85,8 +70,6 @@
colorable_colors = ARMOR_PALETTES_LIST
colorable_allowed = ICON_STATE_VARIANTS_ALLOWED|PRESET_COLORS_ALLOWED
starting_attachments = list(/obj/item/armor_module/armor/secondary_color/chest/webbing)
- attachments_allowed = list(/obj/item/armor_module/armor/secondary_color/chest/webbing)
- attachments_by_slot = list(ATTACHMENT_SLOT_CHEST_SECONDARY_COLOR)
/obj/item/armor_module/armor/chest/marine/hardsuit/syndicate_markfive
name = "\improper FleckTex Mark V Breacher chestplates"
diff --git a/code/modules/clothing/modular_armor/attachments/leg_plates.dm b/code/modules/clothing/modular_armor/attachments/leg_plates.dm
index 55ea2e5cb4268..a4b968b53731b 100644
--- a/code/modules/clothing/modular_armor/attachments/leg_plates.dm
+++ b/code/modules/clothing/modular_armor/attachments/leg_plates.dm
@@ -54,21 +54,6 @@
desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All leg plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Trooper armor piece."
greyscale_config = /datum/greyscale_config/armor_mk1/trooper
-/obj/item/armor_module/armor/legs/marine/kabuto
- name = "\improper Style Pattern Kabuto leg plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All leg plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Kabuto armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/kabuto
-
-/obj/item/armor_module/armor/legs/marine/hotaru
- name = "\improper Style Pattern Hotaru leg plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All leg plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Hotaru armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/hotaru
-
-/obj/item/armor_module/armor/legs/marine/dashe
- name = "\improper Style Pattern Dashe leg plates"
- desc = "Designed for use with the Jaeger Combat Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. This armor appears to be marked as a Dashe armor piece."
- greyscale_config = /datum/greyscale_config/armor_mk1/dashe
-
// Hardsuit Leg Plates
// Base Hardsuit Legs
@@ -76,8 +61,6 @@
name = "\improper FleckTex Base leg plates"
desc = "Designed for use with the FleckTex WY-01 Exoskeleton. It provides high protection and encumbrance when attached and is fairly easy to attach and remove from armor. Click on the armor frame to attach it. All arm plates have the same armor and slowdown, meaning that only changing the chestplate makes significant armor difference. This armor appears to be marked as a Base armor piece."
starting_attachments = list(/obj/item/armor_module/armor/secondary_color/leg)
- attachments_allowed = list(/obj/item/armor_module/armor/secondary_color/leg)
- attachments_by_slot = list(ATTACHMENT_SLOT_KNEE_SECONDARY_COLOR)
greyscale_config = /datum/greyscale_config/hardsuit_variant
/obj/item/armor_module/armor/legs/marine/hardsuit_legs/syndicate_markfive
diff --git a/code/modules/clothing/modular_armor/attachments/modules.dm b/code/modules/clothing/modular_armor/attachments/modules.dm
index fbd769166a856..1b61df1a06603 100644
--- a/code/modules/clothing/modular_armor/attachments/modules.dm
+++ b/code/modules/clothing/modular_armor/attachments/modules.dm
@@ -18,6 +18,7 @@
icon_state = "pt_belt"
item_state = "pt_belt_a"
slot = ATTACHMENT_SLOT_BELT
+ attach_features_flags = ATTACH_NO_HANDS
/**
* Shoulder lamp strength module
@@ -82,11 +83,11 @@
/obj/item/armor_module/module/fire_proof/on_attach(obj/item/attaching_to, mob/user)
. = ..()
parent.max_heat_protection_temperature += FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE
- parent.flags_armor_features |= ARMOR_FIRE_RESISTANT
+ parent.armor_features_flags |= ARMOR_FIRE_RESISTANT
/obj/item/armor_module/module/fire_proof/on_detach(obj/item/detaching_from, mob/user)
parent.max_heat_protection_temperature -= FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE
- parent.flags_armor_features &= ~ARMOR_FIRE_RESISTANT
+ parent.armor_features_flags &= ~ARMOR_FIRE_RESISTANT
return ..()
/obj/item/armor_module/module/fire_proof/som
@@ -134,9 +135,7 @@
icon_state = "lorica_armor"
item_state = "lorica_armor_a"
attachment_layer = null
- soft_armor = list(MELEE = 10, BULLET = 10, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 5, FIRE = 10, ACID = 5)
- slowdown = 0.2
- slot = ATTACHMENT_SLOT_MODULE
+ soft_armor = list(MELEE = 10, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 5, FIRE = 10, ACID = 5)
/obj/item/armor_module/module/tyr_head
name = "Tyr Helmet System"
@@ -270,6 +269,7 @@
parent.update_icon()
/obj/item/armor_module/module/chemsystem/update_icon_state()
+ . = ..()
if(chemsystem_is_active)
icon_state = "mod_chemsystem_active"
return
@@ -330,12 +330,14 @@
return ..()
///Called to give extra info on parent examine.
-/obj/item/armor_module/module/eshield/proc/parent_examine(datum/source, mob/examiner)
+/obj/item/armor_module/module/eshield/proc/parent_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
- to_chat(examiner, span_notice("Recharge Rate: [recharge_rate/2] health per second\nCurrent Shield Health: [shield_health]\nMaximum Shield Health: [max_shield_health]\n"))
+ examine_list += span_notice("Recharge Rate: [recharge_rate/2] health per second")
+ examine_list += span_notice("Current Shield Health: [shield_health]")
+ examine_list += span_notice("Maximum Shield Health: [max_shield_health]")
if(!recharge_timer)
return
- to_chat(examiner, span_warning("Charging is delayed! It will start recharging again in [timeleft(recharge_timer) / 10] seconds!"))
+ examine_list += span_warning("Charging is delayed! It will start recharging again in [timeleft(recharge_timer) / 10] seconds!")
///Handles starting the shield when the parent is equiped to the correct slot.
/obj/item/armor_module/module/eshield/proc/handle_equip(datum/source, mob/equipper, slot)
@@ -423,11 +425,25 @@
affected.remove_filter("eshield")
affected.add_filter("eshield", 2, outline_filter(1, new_color))
+/obj/item/armor_module/module/eshield/overclocked
+ max_shield_health = 75
+ damaged_shield_cooldown = 5 SECONDS
+ shield_color_low = COLOR_MAROON
+ shield_color_mid = LIGHT_COLOR_RED_ORANGE
+ shield_color_full = LIGHT_COLOR_ELECTRIC_CYAN
+
//original Martian design, donutsteel
/obj/item/armor_module/module/eshield/som
name = "Aegis Energy Dispersion Module"
desc = "A sophisticated shielding unit, designed to disperse the energy of incoming impacts, rendering them harmless to the user. If it sustains too much it will deactivate, and leave the user vulnerable. It is unclear if this was a purely SOM designed module, or whether it was reverse engineered from the TGMC's 'Svalinn' shield system which was developed around the same time."
+/obj/item/armor_module/module/eshield/som/overclocked
+ max_shield_health = 75
+ damaged_shield_cooldown = 5 SECONDS
+ shield_color_low = COLOR_MAROON
+ shield_color_mid = LIGHT_COLOR_RED_ORANGE
+ shield_color_full = LIGHT_COLOR_ELECTRIC_CYAN
+
/obj/item/armor_module/module/style
name = "\improper Armor Equalizer"
desc = "Designed for mounting on conventional clothing, this grants it a level of reinforcement against attacks."
@@ -475,7 +491,7 @@
icon_state = "welding_head"
item_state = "welding_head_a"
slot = ATTACHMENT_SLOT_HEAD_MODULE
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
active = FALSE
prefered_slot = SLOT_HEAD
toggle_signal = COMSIG_KB_HELMETMODULE
@@ -498,14 +514,14 @@
/obj/item/armor_module/module/welding/activate(mob/living/user)
if(active)
- DISABLE_BITFIELD(parent.flags_inventory, COVEREYES)
- DISABLE_BITFIELD(parent.flags_inv_hide, HIDEEYES)
- DISABLE_BITFIELD(parent.flags_armor_protection, EYES)
+ DISABLE_BITFIELD(parent.inventory_flags, COVEREYES)
+ DISABLE_BITFIELD(parent.inv_hide_flags, HIDEEYES)
+ DISABLE_BITFIELD(parent.armor_protection_flags, EYES)
parent.eye_protection -= eye_protection_mod // reset to the users base eye
else
- ENABLE_BITFIELD(parent.flags_inventory, COVEREYES)
- ENABLE_BITFIELD(parent.flags_inv_hide, HIDEEYES)
- ENABLE_BITFIELD(parent.flags_armor_protection, EYES)
+ ENABLE_BITFIELD(parent.inventory_flags, COVEREYES)
+ ENABLE_BITFIELD(parent.inv_hide_flags, HIDEEYES)
+ ENABLE_BITFIELD(parent.armor_protection_flags, EYES)
parent.eye_protection += eye_protection_mod
active = !active
@@ -522,7 +538,7 @@
icon = 'icons/mob/modular/modular_armor_modules.dmi'
icon_state = "welding_head_som"
item_state = "welding_head_som_a"
- flags_attach_features = ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
/obj/item/armor_module/module/welding/superior
name = "Superior Welding Helmet Module"
@@ -531,7 +547,7 @@
icon_state = "welding_head"
item_state = "welding_head_a"
slot = ATTACHMENT_SLOT_HEAD_MODULE
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
active = FALSE
prefered_slot = SLOT_HEAD
@@ -546,10 +562,10 @@
icon_state = "binocular_head"
item_state = "binocular_head_a"
active = FALSE
- flags_item = DOES_NOT_NEED_HANDS
+ item_flags = DOES_NOT_NEED_HANDS
zoom_tile_offset = 11
zoom_viewsize = 15 //RU TGMC EDIT
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
slot = ATTACHMENT_SLOT_HEAD_MODULE
prefered_slot = SLOT_HEAD
toggle_signal = COMSIG_KB_HELMETMODULE
@@ -593,57 +609,85 @@
icon_state = "artemis_head"
item_state = "artemis_head_a"
slot = ATTACHMENT_SLOT_HEAD_MODULE
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB
prefered_slot = SLOT_HEAD
/obj/item/armor_module/module/artemis/on_attach(obj/item/attaching_to, mob/user)
. = ..()
parent.AddComponent(/datum/component/blur_protection)
+#define COMMS_OFF 0
+#define COMMS_SETTING 1
+#define COMMS_SETUP 2
+
/obj/item/armor_module/module/antenna
name = "Antenna helmet module"
- desc = "Designed for mounting on a modular Helmet. This module is able to provide a readout of the user's coordinates and connect to the shipside supply console."
+ desc = "Designed for mounting on a modular Helmet. This module is able to shield against the interference of caves, allowing for normal messaging in shallow caves, and only minor interference when deep."
icon = 'icons/mob/modular/modular_armor_modules.dmi'
icon_state = "antenna_head"
item_state = "antenna_head_a"
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_APPLY_ON_MOB
slot = ATTACHMENT_SLOT_HEAD_MODULE
prefered_slot = SLOT_HEAD
toggle_signal = COMSIG_KB_HELMETMODULE
- /// Reference to the datum used by the supply drop console
- var/datum/supply_beacon/beacon_datum
-
-/obj/item/armor_module/module/antenna/Destroy()
- if(beacon_datum)
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
+ ///If the comms system is configured.
+ var/comms_setup = FALSE
+ ///ID of the startup timer
+ var/startup_timer_id
+
+/obj/item/armor_module/module/antenna/handle_actions(datum/source, mob/user, slot)
+ if(slot != prefered_slot)
+ UnregisterSignal(user, COMSIG_CAVE_INTERFERENCE_CHECK)
+ comms_setup = COMMS_OFF
+ if(startup_timer_id)
+ deltimer(startup_timer_id)
+ startup_timer_id = null
+ else
+ RegisterSignal(user, COMSIG_CAVE_INTERFERENCE_CHECK, PROC_REF(on_interference_check))
+ start_sync(user)
return ..()
+///Handles interacting with caves checking for if anything is reducing (or increasing) interference.
+/obj/item/armor_module/module/antenna/proc/on_interference_check(source, list/inplace_interference)
+ SIGNAL_HANDLER
+ if(comms_setup != COMMS_SETUP)
+ return
+ inplace_interference[1] = max(0, inplace_interference[1] - 1)
+
/obj/item/armor_module/module/antenna/activate(mob/living/user)
- var/turf/location = get_turf(src)
- if(beacon_datum)
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
- user.show_message(span_warning("The [src] beeps and states, \"Your last position is no longer accessible by the supply console"), EMOTE_AUDIBLE, span_notice("The [src] vibrates but you can not hear it!"))
+ if(comms_setup == COMMS_SETTING)
+ to_chat(user, span_notice("Your Antenna module is still in the process of starting up!"))
return
- if(!is_ground_level(user.z))
- to_chat(user, span_warning("You have to be on the planet to use this or it won't transmit."))
- return FALSE
- beacon_datum = new /datum/supply_beacon(user.name, user.loc, user.faction, 4 MINUTES)
- RegisterSignal(beacon_datum, COMSIG_QDELETING, PROC_REF(clean_beacon_datum))
- user.show_message(span_notice("The [src] beeps and states, \"Your current coordinates were registered by the supply console. LONGITUDE [location.x]. LATITUDE [location.y]. Area ID: [get_area(src)]\""), EMOTE_AUDIBLE, span_notice("The [src] vibrates but you can not hear it!"))
-
-/// Signal handler to nullify beacon datum
-/obj/item/armor_module/module/antenna/proc/clean_beacon_datum()
- SIGNAL_HANDLER
- beacon_datum = null
+ if(comms_setup == COMMS_SETUP)
+ var/turf/location = get_turf(user)
+ user.show_message(span_notice("The [src] beeps and states, \"Uplink data: LONGITUDE [location.x]. LATITUDE [location.y]. Area ID: [get_area(src)]\""), EMOTE_AUDIBLE, span_notice("The [src] vibrates but you can not hear it!"))
+ return
+
+///Begins the startup sequence.
+/obj/item/armor_module/module/antenna/proc/start_sync(mob/living/user)
+ if(comms_setup != COMMS_OFF) //Guh?
+ return
+ to_chat(user, span_notice("Setting up Antenna communication relay. Please wait."))
+ comms_setup = COMMS_SETTING
+ startup_timer_id = addtimer(CALLBACK(src, PROC_REF(finish_startup), user), ANTENNA_SYNCING_TIME, TIMER_STOPPABLE)
+
+///Finishes startup, rendering the module effective.
+/obj/item/armor_module/module/antenna/proc/finish_startup(mob/living/user)
+ comms_setup = COMMS_SETUP
+ user.show_message(span_notice("[src] beeps twice and states: \"Antenna configuration complete. Relay system active.\""), EMOTE_AUDIBLE, span_notice("[src] vibrates twice."))
+ startup_timer_id = null
+
+
+#undef COMMS_OFF
+#undef COMMS_SETTING
+#undef COMMS_SETUP
/obj/item/armor_module/module/night_vision
name = "\improper BE-35 night vision kit"
desc = "Installation kit for the BE-35 night vision system. Slightly impedes movement."
icon = 'icons/mob/modular/modular_armor_modules.dmi'
icon_state = "night_vision"
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_NO_HANDS
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_NO_HANDS
slot = ATTACHMENT_SLOT_HEAD_MODULE
prefered_slot = SLOT_HEAD
slowdown = 0.1
diff --git a/code/modules/clothing/modular_armor/attachments/secondary_color.dm b/code/modules/clothing/modular_armor/attachments/secondary_color.dm
index 9504129c43f6b..d35d4f411bd1d 100644
--- a/code/modules/clothing/modular_armor/attachments/secondary_color.dm
+++ b/code/modules/clothing/modular_armor/attachments/secondary_color.dm
@@ -1,9 +1,9 @@
//A module you can use to add yet another color layer to your modular armor sets. icon name format is [prefix]_[bodypart]_secondary_color_[variant] , exclude _variant if you do not use it
/obj/item/armor_module/armor/secondary_color
- flags_attach_features = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB|ATTACH_BYPASS_ALLOWED_LIST|ATTACH_GREYSCALE_PARENT_COPY
secondary_color = TRUE
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/armor_module/armor/secondary_color/update_greyscale()
if(!parent)
@@ -12,14 +12,24 @@
/obj/item/armor_module/armor/secondary_color/on_attach(obj/item/attaching_to, mob/user)
. = ..()
+ if(!attaching_to)
+ return
+ RegisterSignal(attaching_to, COMSIG_ITEM_VARIANT_CHANGE, PROC_REF(on_variant_change))
+ if(greyscale_config)
+ return
greyscale_config = attaching_to.greyscale_config
name = "[attaching_to.name] secondary color"
update_icon()
update_greyscale()
- RegisterSignal(attaching_to, COMSIG_ITEM_VARIANT_CHANGE, PROC_REF(on_variant_change))
-/obj/item/armor_module/armor/secondary_color/proc/on_variant_change(mob/user, variant)
+/obj/item/armor_module/armor/secondary_color/on_detach(obj/item/detaching_from, mob/user)
+ . = ..()
+ if(!detaching_from)
+ return
+ UnregisterSignal(detaching_from, COMSIG_ITEM_VARIANT_CHANGE)
+
+/obj/item/armor_module/armor/secondary_color/proc/on_variant_change(obj/item/parent, mob/user, variant)
SIGNAL_HANDLER
if(variant in icon_state_variants)
current_variant = variant
@@ -27,7 +37,7 @@
update_greyscale()
/obj/item/armor_module/armor/secondary_color/chest
- name = "chest secondary_color"
+ name = "chest secondary color"
icon_state = "chest_secondary_color"
slot = ATTACHMENT_SLOT_CHEST_SECONDARY_COLOR
@@ -40,16 +50,16 @@
)
/obj/item/armor_module/armor/secondary_color/leg
- name = "leg secondary_color"
+ name = "leg secondary color"
icon_state = "leg_secondary_color"
slot = ATTACHMENT_SLOT_KNEE_SECONDARY_COLOR
/obj/item/armor_module/armor/secondary_color/arm
- name = "arm secondary_color"
+ name = "arm secondary color"
icon_state = "arm_secondary_color"
slot = ATTACHMENT_SLOT_ARM_SECONDARY_COLOR
/obj/item/armor_module/armor/secondary_color/helm
- name = "helm secondary_color"
+ name = "helm secondary color"
icon_state = "helm_secondary_color"
slot = ATTACHMENT_SLOT_HELM_SECONDARY_COLOR
diff --git a/code/modules/clothing/modular_armor/attachments/storage.dm b/code/modules/clothing/modular_armor/attachments/storage.dm
index 65003ad088982..f86f5dbc350e4 100644
--- a/code/modules/clothing/modular_armor/attachments/storage.dm
+++ b/code/modules/clothing/modular_armor/attachments/storage.dm
@@ -115,7 +115,7 @@
/obj/item/armor_module/storage/pocket
icon_state = ""
item_state = ""
- flags_attach_features = ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_APPLY_ON_MOB
storage = /obj/item/storage/internal/pocket
/obj/item/storage/internal/pocket
@@ -131,6 +131,7 @@
/obj/item/ammo_magazine/sniper,
/obj/item/ammo_magazine/handful,
)
+ cant_hold = list(/obj/item/cell/lasgun/volkite/powerpack)
/obj/item/storage/internal/pocket/insertion_message(obj/item/item, mob/user)
var/visidist = item.w_class >= WEIGHT_CLASS_NORMAL ? 3 : 1
@@ -183,7 +184,9 @@
/obj/item/ammo_magazine/revolver,
/obj/item/ammo_magazine/sniper,
/obj/item/ammo_magazine/handful,
+ /obj/item/cell/lasgun/plasma,
)
+ cant_hold = list(/obj/item/cell/lasgun/volkite/powerpack)
/obj/item/armor_module/storage/general/som
name = "General Purpose Storage module"
@@ -269,7 +272,7 @@
/obj/item/tool/multitool,
/obj/item/binoculars/tactical/range,
/obj/item/explosive/plastique,
- /obj/item/explosive/grenade/chem_grenade/razorburn_smol,
+ /obj/item/explosive/grenade/chem_grenade/razorburn_small,
/obj/item/explosive/grenade/chem_grenade/razorburn_large,
/obj/item/cell/apc,
/obj/item/cell/high,
@@ -388,7 +391,7 @@
desc = "A small set of straps to hold something in your boot."
icon_state = ""
storage = /obj/item/storage/internal/shoes/boot_knife
- flags_attach_features = ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_APPLY_ON_MOB
/obj/item/storage/internal/shoes/boot_knife
max_storage_space = 3
@@ -421,7 +424,7 @@
icon_state = ""
storage = /obj/item/storage/internal/marinehelmet
show_storage = TRUE
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/storage/internal/marinehelmet
max_storage_space = 3
diff --git a/code/modules/clothing/modular_armor/attachments/uniform.dm b/code/modules/clothing/modular_armor/attachments/uniform.dm
index fa800cf2b8add..acbc24eb3a08b 100644
--- a/code/modules/clothing/modular_armor/attachments/uniform.dm
+++ b/code/modules/clothing/modular_armor/attachments/uniform.dm
@@ -3,7 +3,7 @@
/obj/item/armor_module/storage/uniform
slot = ATTACHMENT_SLOT_UNIFORM
w_class = WEIGHT_CLASS_BULKY
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB|ATTACH_SEPERATE_MOB_OVERLAY|ATTACH_NO_HANDS
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB|ATTACH_SEPERATE_MOB_OVERLAY|ATTACH_NO_HANDS
icon = 'icons/obj/clothing/ties.dmi'
attach_icon = 'icons/obj/clothing/ties_overlay.dmi'
mob_overlay_icon = 'icons/mob/ties.dmi'
diff --git a/code/modules/clothing/modular_armor/attachments/visors.dm b/code/modules/clothing/modular_armor/attachments/visors.dm
index 303764d46124f..6e4c502be38a7 100644
--- a/code/modules/clothing/modular_armor/attachments/visors.dm
+++ b/code/modules/clothing/modular_armor/attachments/visors.dm
@@ -8,12 +8,12 @@
name = "standard visor"
icon_state = "visor"
slot = ATTACHMENT_SLOT_VISOR
- flags_attach_features = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
+ attach_features_flags = ATTACH_SAME_ICON|ATTACH_APPLY_ON_MOB
greyscale_config = /datum/greyscale_config/visors
greyscale_colors = VISOR_PALETTE_GOLD
colorable_colors = VISOR_PALETTES_LIST
secondary_color = TRUE
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
///whether this helmet should be using its emissive overlay or not
var/visor_emissive_on = TRUE
@@ -92,21 +92,6 @@
icon_state = "trooper_visor"
colorable_allowed = COLOR_WHEEL_ALLOWED|PRESET_COLORS_ALLOWED
-/obj/item/armor_module/armor/visor/marine/kabuto
- name = "\improper Style Pattern Kabuto visor"
- desc = "The visor attachment of the Jaeger modular helmets. This one is designed for the Kabuto class of helmet."
- icon_state = "kabuto_visor"
-
-/obj/item/armor_module/armor/visor/marine/hotaru
- name = "\improper Style Pattern Hotaru visor"
- desc = "The visor attachment of the Jaeger modular helmets. This one is designed for the Hotaru class of helmet."
- icon_state = "hotaru_visor"
-
-/obj/item/armor_module/armor/visor/marine/dashe
- name = "\improper Style Pattern Dashe visor"
- desc = "The visor attachment of the Jaeger modular helmets. This one is designed for the Dashe class of helmet."
- icon_state = "dashe_visor"
-
/obj/item/armor_module/armor/visor/marine/eva
name = "\improper Jaeger Pattern EVA visor"
desc = "The visor attachment of the Jaeger modular helmets. This one is designed for the EVA class of helmet."
diff --git a/code/modules/clothing/modular_armor/combat_robot.dm b/code/modules/clothing/modular_armor/combat_robot.dm
index fdba31604e71a..30925cfba730b 100644
--- a/code/modules/clothing/modular_armor/combat_robot.dm
+++ b/code/modules/clothing/modular_armor/combat_robot.dm
@@ -39,7 +39,7 @@
allowed_uniform_type = /obj/item/clothing/under/marine/robotic
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
/obj/item/clothing/suit/modular/robot/mob_can_equip(mob/user, slot, warning = TRUE, override_nodrop = FALSE, bitslot = FALSE)
. = ..()
@@ -78,13 +78,13 @@
name = "XN-1 upper armor plating"
desc = "Medium armor plating designed for self mounting on the upper half of TerraGov combat robotics. It has self-sealing bolts for mounting on robotic owners inside."
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "helmet"
item_state = "helmet"
species_exception = list(/datum/species/robot)
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
soft_armor = list(MELEE = 50, BULLET = 70, LASER = 70, ENERGY = 60, BOMB = 55, BIO = 55, FIRE = 55, ACID = 60)
colorable_colors = ARMOR_PALETTES_LIST
@@ -111,7 +111,7 @@
//RUTGMC EDIT ADDITION END
)
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/armor/visor/marine/robot)
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
/obj/item/clothing/head/modular/robot/mob_can_equip(mob/user, slot, warning = TRUE, override_nodrop = FALSE, bitslot = FALSE)
diff --git a/code/modules/clothing/modular_armor/jaeger.dm b/code/modules/clothing/modular_armor/jaeger.dm
index b65584f73c26d..809c40359f85d 100644
--- a/code/modules/clothing/modular_armor/jaeger.dm
+++ b/code/modules/clothing/modular_armor/jaeger.dm
@@ -35,7 +35,7 @@
/obj/item/armor_module/armor/badge,
)
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
greyscale_config = /datum/greyscale_config/armor_mk2/infantry
colorable_allowed = PRESET_COLORS_ALLOWED
@@ -60,11 +60,6 @@
desc = "A Ranger-pattern Jaeger combat exoskeleton made to work with modular attachments for the ability to function in many enviroments. This one seems to have a moderate amount of armor plating. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
greyscale_config = /datum/greyscale_config/armor_mk2/ranger
-/obj/item/clothing/suit/modular/jaeger/hotaru
- name = "\improper Style Pattern Hotaru medium exoskeleton"
- desc = "A Ranger-pattern Hotaru combat exoskeleton made to work with modular attachments for the ability to function in many enviroments. This one seems to have a moderate amount of armor plating. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
- greyscale_config = /datum/greyscale_config/armor_mk2/hotaru
-
// Light
/obj/item/clothing/suit/modular/jaeger/light
@@ -107,8 +102,8 @@
name = "Jaeger Pattern Infantry Helmet"
desc = "Usually paired with the Jaeger Combat Exoskeleton. Can mount utility functions on the helmet hard points. Has Infantry markings."
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "helmet"
item_state = "helmet"
@@ -148,13 +143,9 @@
/obj/item/armor_module/armor/visor/marine/ranger,
/obj/item/armor_module/armor/visor/marine/traditional,
/obj/item/armor_module/armor/visor/marine/trooper,
- /obj/item/armor_module/armor/visor/marine/kabuto,
- /obj/item/armor_module/armor/visor/marine/hotaru,
- /obj/item/armor_module/armor/visor/marine/dashe,
/obj/item/armor_module/armor/visor/marine/fourvisor,
/obj/item/armor_module/armor/visor/marine/foureyevisor,
/obj/item/armor_module/armor/visor/marine/markonevisor,
- /obj/item/armor_module/armor/secondary_color/helm,
//RUTGMC EDIT ADDITION BEGIN - MOTION_DETECTOR
/obj/item/armor_module/module/motion_detector,
//RUTGMC EDIT ADDITION END
@@ -162,7 +153,7 @@
starting_attachments = list(/obj/item/armor_module/armor/visor/marine, /obj/item/armor_module/storage/helmet)
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
/obj/item/clothing/head/modular/marine/eva
name = "Jaeger Pattern EVA Helmet"
@@ -229,24 +220,6 @@
starting_attachments = list(/obj/item/armor_module/armor/visor/marine/trooper, /obj/item/armor_module/storage/helmet)
greyscale_config = /datum/greyscale_config/armor_mk2/trooper
-/obj/item/clothing/head/modular/marine/kabuto
- name = "Style Pattern Kabuto Helmet"
- desc = "Usually paired with the Jaeger Combat Exoskeleton. Can mount utility functions on the helmet hard points. Has Kabuto markings"
- starting_attachments = list(/obj/item/armor_module/armor/visor/marine/kabuto, /obj/item/armor_module/storage/helmet)
- greyscale_config = /datum/greyscale_config/armor_mk1/kabuto
-
-/obj/item/clothing/head/modular/marine/hotaru
- name = "Style Pattern Hotaru Helmet"
- desc = "Usually paired with the Jaeger Combat Exoskeleton. Can mount utility functions on the helmet hard points. Has Hotaru markings"
- starting_attachments = list(/obj/item/armor_module/armor/visor/marine/hotaru, /obj/item/armor_module/storage/helmet)
- greyscale_config = /datum/greyscale_config/armor_mk1/hotaru
-
-/obj/item/clothing/head/modular/marine/dashe
- name = "Style Pattern Dashe Helmet"
- desc = "Usually paired with the Jaeger Combat Exoskeleton. Can mount utility functions on the helmet hard points. Has Dashe markings"
- starting_attachments = list(/obj/item/armor_module/armor/visor/marine/dashe, /obj/item/armor_module/storage/helmet)
- greyscale_config = /datum/greyscale_config/armor_mk1/dashe
-
// Hardsuit Helmets
/obj/item/clothing/head/modular/marine/hardsuit_helm
@@ -254,13 +227,6 @@
desc = "Usually paired with the FleckTex WY-01 modular exoskeleton. Can mount utility functions on the helmet hard points. Has Base markings"
greyscale_config = /datum/greyscale_config/hardsuit_variant
starting_attachments = list(/obj/item/armor_module/armor/visor/marine, /obj/item/armor_module/storage/helmet, /obj/item/armor_module/armor/secondary_color/helm)
- attachments_by_slot = list(
- ATTACHMENT_SLOT_VISOR,
- ATTACHMENT_SLOT_STORAGE,
- ATTACHMENT_SLOT_HEAD_MODULE,
- ATTACHMENT_SLOT_BADGE,
- ATTACHMENT_SLOT_HELM_SECONDARY_COLOR,
- )
/obj/item/clothing/head/modular/marine/hardsuit_helm/markfive
name = "FleckTex Mark V Breacher Helmet"
diff --git a/code/modules/clothing/modular_armor/mark_one.dm b/code/modules/clothing/modular_armor/mark_one.dm
index b3d1519922c8b..4b992a5f9455a 100644
--- a/code/modules/clothing/modular_armor/mark_one.dm
+++ b/code/modules/clothing/modular_armor/mark_one.dm
@@ -5,8 +5,8 @@
icon_state = "helmet"
item_state = "helmet"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
attachments_allowed = list(
diff --git a/code/modules/clothing/modular_armor/modular.dm b/code/modules/clothing/modular_armor/modular.dm
index 3249f84d45137..5547a63b6fa63 100644
--- a/code/modules/clothing/modular_armor/modular.dm
+++ b/code/modules/clothing/modular_armor/modular.dm
@@ -18,9 +18,9 @@
item_state_worn = TRUE
item_icons = list(slot_wear_suit_str = 'icons/mob/modular/modular_armor.dmi')
- flags_atom = CONDUCT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_item = SYNTH_RESTRICTED|IMPEDE_JETPACK
+ atom_flags = CONDUCT
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ item_flags = SYNTH_RESTRICTED|IMPEDE_JETPACK
/// What is allowed to be equipped in suit storage
allowed = list(
/obj/item/weapon/gun,
@@ -38,7 +38,7 @@
/obj/item/tool/shovel/etool,
/obj/item/weapon/energy/sword,
)
- flags_equip_slot = ITEM_SLOT_OCLOTHING
+ equip_slot_flags = ITEM_SLOT_OCLOTHING
w_class = WEIGHT_CLASS_BULKY
equip_delay_self = 2 SECONDS
unequip_delay_self = 1 SECONDS
@@ -96,17 +96,6 @@
/obj/item/armor_module/armor/legs/marine/ranger,
/obj/item/armor_module/armor/arms/marine/ranger,
- /obj/item/armor_module/armor/chest/marine/kabuto,
- /obj/item/armor_module/armor/legs/marine/kabuto,
- /obj/item/armor_module/armor/arms/marine/kabuto,
-
- /obj/item/armor_module/armor/chest/marine/hotaru,
- /obj/item/armor_module/armor/legs/marine/hotaru,
- /obj/item/armor_module/armor/arms/marine/hotaru,
-
- /obj/item/armor_module/armor/chest/marine/dashe,
- /obj/item/armor_module/armor/arms/marine/dashe,
- /obj/item/armor_module/armor/legs/marine/dashe,
/obj/item/armor_module/module/better_shoulder_lamp,
/obj/item/armor_module/module/valkyrie_autodoc,
@@ -159,7 +148,6 @@
return FALSE
return ..()
-
/obj/item/clothing/suit/modular/attack_self(mob/user)
. = ..()
if(.)
@@ -172,8 +160,8 @@
var/mob/living/carbon/human/H = user
if(H.wear_suit != src)
return
- turn_light(user, !light_on)
- return TRUE
+ if(turn_light(user, !light_on) == CHECKS_PASSED)
+ return TRUE
/obj/item/clothing/suit/modular/item_action_slot_check(mob/user, slot)
if(!light_range) // No light no ability
@@ -201,6 +189,24 @@
if(attachments_by_slot[ATTACHMENT_SLOT_STORAGE])
. += " It has a [attachments_by_slot[ATTACHMENT_SLOT_STORAGE]] installed."
+/obj/item/clothing/suit/modular/examine(mob/user)
+ . = ..()
+ var/armor_info
+ var/obj/item/clothing/suit/modular/wear_modular_suit = src
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CHESTPLATE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CHESTPLATE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_SHOULDER])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_SHOULDER]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_KNEE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_KNEE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_STORAGE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_STORAGE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_MODULE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_MODULE]].\n"
+ if(armor_info)
+ . += " It has the following attachments:"
+ . += armor_info
+
/obj/item/clothing/suit/modular/rownin
name = "\improper Rownin Skeleton"
desc = "A light armor, if you can even call it that, for marines that want to have agility in exchange for protection. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
@@ -293,12 +299,12 @@
greyscale_config = /datum/greyscale_config/armor_mk1
greyscale_colors = ARMOR_PALETTE_DESERT
- flags_armor_protection = HEAD
- flags_armor_features = ARMOR_NO_DECAP
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDE_EXCESS_HAIR
+ armor_protection_flags = HEAD
+ armor_features_flags = ARMOR_NO_DECAP
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDE_EXCESS_HAIR
allowed = null
- flags_equip_slot = ITEM_SLOT_HEAD
+ equip_slot_flags = ITEM_SLOT_HEAD
w_class = WEIGHT_CLASS_NORMAL
soft_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 15, FIRE = 15, ACID = 15)
@@ -369,12 +375,21 @@
. += "
This is a piece of modular armor, It can equip different attachments. "
. += " It currently has [attachments_by_slot[ATTACHMENT_SLOT_HEAD_MODULE] ? attachments_by_slot[ATTACHMENT_SLOT_HEAD_MODULE] : "nothing"] installed."
+/obj/item/clothing/head/modular/examine(mob/user)
+ . = ..()
+ var/armor_info
+ var/obj/item/clothing/head/modular/wear_modular_suit = src
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_HEAD_MODULE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_HEAD_MODULE]].\n"
+ if(armor_info)
+ . += " It has the following attachments:"
+ . += armor_info
+
/** Colorable masks */
/obj/item/clothing/mask/gas/modular
name = "style mask"
desc = "A cool sylish mask that through some arcane magic blocks gas attacks. How? Who knows. How did you even get this?"
breathy = FALSE
- voice_filter = null
icon_state = "gas_alt"
item_state = "gas_alt"
item_icons = list(slot_wear_mask_str)
diff --git a/code/modules/clothing/modular_armor/som.dm b/code/modules/clothing/modular_armor/som.dm
index 180ef33deb370..0f22e8547de02 100644
--- a/code/modules/clothing/modular_armor/som.dm
+++ b/code/modules/clothing/modular_armor/som.dm
@@ -3,7 +3,7 @@
/obj/item/clothing/suit/modular/som
name = "\improper SOM light battle armor"
desc = "The M-21 battle armor is typically used by SOM light infantry, or other specialists that require more mobility at the cost of some protection. Provides good protection without minor impairment to the users mobility. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
- soft_armor = list(MELEE = 45, BULLET = 70, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 55, ACID = 50)
+ soft_armor = list(MELEE = 45, BULLET = 65, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 55, ACID = 50)
icon = 'icons/mob/modular/som_armor.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/modular/som_armor.dmi',
@@ -22,6 +22,7 @@
/obj/item/armor_module/module/mimir_environment_protection/som,
/obj/item/armor_module/module/hlin_explosive_armor,
/obj/item/armor_module/module/eshield/som,
+ /obj/item/armor_module/module/eshield/som/overclocked,
/obj/item/armor_module/storage/general,
/obj/item/armor_module/storage/ammo_mag,
/obj/item/armor_module/storage/engineering,
@@ -60,10 +61,28 @@
/obj/item/armor_module/storage/medical/som,
)
+/obj/item/clothing/suit/modular/som/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/medical/som,
+ )
+
+/obj/item/clothing/suit/modular/som/shield_overclocked/medic
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/general/som,
+ )
+
+/obj/item/clothing/suit/modular/som/shield_overclocked/engineer
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/engineering,
+ )
+
/obj/item/clothing/suit/modular/som/light
name = "\improper SOM scout armor"
desc = "The M-11 scout armor is a lightweight suit that that allows for minimal encumberance while still providing reasonable protection. Often seen on scouts or other specialist units that aren't normally getting shot at. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
- soft_armor = list(MELEE = 35, BULLET = 60, LASER = 50, ENERGY = 50, BOMB = 45, BIO = 45, FIRE = 50, ACID = 40)
+ soft_armor = list(MELEE = 35, BULLET = 55, LASER = 50, ENERGY = 50, BOMB = 45, BIO = 45, FIRE = 50, ACID = 40)
icon_state = "som_light"
item_state = "som_light"
slowdown = SLOWDOWN_ARMOR_LIGHT
@@ -74,11 +93,41 @@
/obj/item/armor_module/storage/medical/som,
)
+/obj/item/clothing/suit/modular/som/light/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/medical/som,
+ )
+
+/obj/item/clothing/suit/modular/som/light/shield_overclocked/medic
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/general/som,
+ )
+
+/obj/item/clothing/suit/modular/som/light/shield_overclocked/engineer
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/engineering,
+ )
+
+/obj/item/clothing/suit/modular/som/light/engineer
+ starting_attachments = list(
+ /obj/item/armor_module/module/better_shoulder_lamp,
+ /obj/item/armor_module/storage/engineering,
+ )
+
+/obj/item/clothing/suit/modular/som/light/medic
+ starting_attachments = list(
+ /obj/item/armor_module/module/better_shoulder_lamp,
+ /obj/item/armor_module/storage/general/som,
+ )
+
/obj/item/clothing/suit/modular/som/heavy
name = "\improper SOM heavy battle armor"
desc = "A standard suit of M-31 heavy duty combat armor worn by SOM shock troops. Provides excellent protection however it does reduce mobility somewhat. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
- soft_armor = list(MELEE = 50, BULLET = 75, LASER = 65, ENERGY = 65, BOMB = 55, BIO = 55, FIRE = 60, ACID = 55)
+ soft_armor = list(MELEE = 50, BULLET = 70, LASER = 65, ENERGY = 65, BOMB = 55, BIO = 55, FIRE = 60, ACID = 55)
icon_state = "som_heavy"
item_state = "som_heavy"
slowdown = SLOWDOWN_ARMOR_HEAVY
@@ -107,10 +156,16 @@
/obj/item/armor_module/storage/medical/som,
)
+/obj/item/clothing/suit/modular/som/heavy/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/som/overclocked,
+ /obj/item/armor_module/storage/medical/som,
+ )
+
/obj/item/clothing/suit/modular/som/heavy/leader
name = "\improper SOM Gorgon pattern assault armor"
desc = "A bulky suit of heavy combat armor, the M-35 'Gorgon' armor provides the user with superior protection without severely impacting mobility. Typically seen on SOM leaders or their most elite combat units due to the significant construction and maintenance requirements. You'll need serious firepower to punch through this. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
- soft_armor = list(MELEE = 60, BULLET = 80, LASER = 70, ENERGY = 70, BOMB = 60, BIO = 55, FIRE = 65, ACID = 55)
+ soft_armor = list(MELEE = 60, BULLET = 75, LASER = 70, ENERGY = 70, BOMB = 60, BIO = 55, FIRE = 65, ACID = 55)
icon_state = "som_leader"
item_state = "som_leader"
@@ -124,6 +179,7 @@
/obj/item/armor_module/module/mimir_environment_protection/som,
/obj/item/armor_module/module/hlin_explosive_armor,
/obj/item/armor_module/module/eshield/som,
+ /obj/item/armor_module/module/eshield/som/overclocked,
/obj/item/armor_module/storage/general,
/obj/item/armor_module/storage/ammo_mag,
/obj/item/armor_module/storage/engineering,
@@ -165,9 +221,9 @@
)
icon_state = "som_helmet"
item_state = "som_helmet"
- soft_armor = list(MELEE = 45, BULLET = 70, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 55, ACID = 50)
- flags_inv_hide = HIDEEARS|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ soft_armor = list(MELEE = 45, BULLET = 65, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 55, ACID = 50)
+ inv_hide_flags = HIDEEARS|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
attachments_allowed = list(
/obj/item/armor_module/module/binoculars,
/obj/item/armor_module/module/binoculars/artemis_mark_two,
@@ -201,7 +257,7 @@
desc = "This specialised helmet is worn by SOM personel equipped to deal with dangerous chemical, radiological or otherwise hazard substances. Typical unleashed by the SOM themselves."
icon_state = "som_helmet_bio"
item_state = "som_helmet_bio"
- soft_armor = list(MELEE = 45, BULLET = 70, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 75, FIRE = 50, ACID = 70)
+ soft_armor = list(MELEE = 45, BULLET = 65, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 75, FIRE = 50, ACID = 70)
siemens_coefficient = 0.1
permeability_coefficient = 0
gas_transfer_coefficient = 0.1
@@ -215,7 +271,7 @@
desc = "A helmet paired with the 'Hades' armor module, designed for significantly improved protection from fire, without compromising normal durability."
icon_state = "som_helmet_light"
item_state = "som_helmet_light"
- soft_armor = list(MELEE = 45, BULLET = 70, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 90, ACID = 50)
+ soft_armor = list(MELEE = 45, BULLET = 65, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 90, ACID = 50)
attachments_allowed = list(
/obj/item/armor_module/storage/helmet,
/obj/item/armor_module/armor/badge,
@@ -224,14 +280,14 @@
/obj/item/clothing/head/modular/som/veteran
name = "\improper SOM veteran helmet"
desc = "The standard combat helmet worn by SOM combat specialists. State of the art materials provides more protection for more valuable brains."
- soft_armor = list(MELEE = 50, BULLET = 75, LASER = 65, ENERGY = 65, BOMB = 55, BIO = 55, FIRE = 60, ACID = 55)
+ soft_armor = list(MELEE = 50, BULLET = 70, LASER = 65, ENERGY = 65, BOMB = 55, BIO = 55, FIRE = 60, ACID = 55)
/obj/item/clothing/head/modular/som/lorica
name = "\improper Lorica Helmet System"
desc = "A bulky helmet paired with the 'Lorica' armor module, designed for outstanding protection at the cost of significant weight and reduced flexibility. Substantial additional armor improves protection against all damage."
icon_state = "som_helmet_lorica"
item_state = "som_helmet_lorica"
- soft_armor = list(MELEE = 60, BULLET = 85, LASER = 80, ENERGY = 80, BOMB = 65, BIO = 55, FIRE = 70, ACID = 60)
+ soft_armor = list(MELEE = 60, BULLET = 80, LASER = 80, ENERGY = 80, BOMB = 65, BIO = 55, FIRE = 70, ACID = 60)
attachments_allowed = list(
/obj/item/armor_module/storage/helmet,
/obj/item/armor_module/armor/badge,
@@ -242,7 +298,7 @@
desc = "Made for use with Gorgon pattern assault armor, providing superior protection. Typically seen on SOM leaders or their most elite combat units."
icon_state = "som_helmet_leader"
item_state = "som_helmet_leader"
- soft_armor = list(MELEE = 60, BULLET = 80, LASER = 70, ENERGY = 70, BOMB = 60, BIO = 55, FIRE = 65, ACID = 55)
+ soft_armor = list(MELEE = 60, BULLET = 75, LASER = 70, ENERGY = 70, BOMB = 60, BIO = 55, FIRE = 65, ACID = 55)
attachments_allowed = list(
/obj/item/armor_module/module/binoculars,
/obj/item/armor_module/module/binoculars/artemis_mark_two,
diff --git a/code/modules/clothing/modular_armor/style_line.dm b/code/modules/clothing/modular_armor/style_line.dm
index b420fad0a493e..d0e7ca96fa911 100644
--- a/code/modules/clothing/modular_armor/style_line.dm
+++ b/code/modules/clothing/modular_armor/style_line.dm
@@ -4,13 +4,13 @@
/obj/item/clothing/suit/modular/style
name = "\improper Drip"
desc = "They got that drip, doe."
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
allowed_uniform_type = /obj/item/clothing/under
icon = 'icons/obj/clothing/suits/marine_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/marine_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
attachments_allowed = list(
// Armor Modules
@@ -81,7 +81,7 @@
/obj/item/clothing/head/modular/style
name = "\improper Nice Hat"
desc = "Nice hat bro. How did you find this?"
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
attachments_allowed = list(
/obj/item/armor_module/armor/badge,
/obj/item/armor_module/storage/helmet,
@@ -102,7 +102,7 @@
visorless_offset_y = 0
- flags_inv_hide = NONE
+ inv_hide_flags = NONE
soft_armor = list(MELEE = 50, BULLET = 70, LASER = 70, ENERGY = 60, BOMB = 50, BIO = 50, FIRE = 50, ACID = 60)
starting_attachments = list(/obj/item/armor_module/storage/helmet)
@@ -116,6 +116,7 @@
icon_state = "beret_inhand"
item_state = "beret"
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/armor/stylehat_badge)
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/classic_beret
@@ -124,18 +125,21 @@
icon_state = "classic_beret_inhand"
item_state = "classic_beret"
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/armor/stylehat_badge/classic)
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/boonie
name = "TGMC boonie"
desc = "A boonie hat used by the TGMC, purpose made for operations in enviroments with a lot of sun, or dense vegetation."
icon_state = "boonie_inhand"
item_state = "boonie"
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/cap
name = "TGMC cap"
desc = "A common patrol cap used by the TGMC, stylish and comes in many colors. Mostly useful to keep the sun and officers away."
icon_state = "cap_inhand"
item_state = "cap"
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/slouchhat
@@ -143,6 +147,7 @@
desc = "A slouch hat, makes you feel down under, doesn't it? Has 'PROPERTY OF THE TGMC' markings under the hat."
icon_state = "slouch_inhand"
item_state = "slouch"
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/ushanka
name = "TGMC ushanka"
@@ -150,6 +155,7 @@
icon_state = "ushanka_inhand"
item_state = "ushanka"
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/armor/stylehat_badge/ushanka)
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/campaignhat
@@ -157,6 +163,7 @@
desc = "A campaign hat, you can feel the menacing aura that this hat erodes just by looking at it."
icon_state = "campaign_inhand"
item_state = "campaign"
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/beanie
@@ -164,6 +171,7 @@
desc = "A beanie, just looking at it makes you feel like an 'Oussama', or in better terms- A modern phenomenon of people suddenly needing to bench once they put on a beanie."
icon_state = "beanie_inhand"
item_state = "beanie"
+ inv_hide_flags = HIDE_EXCESS_HAIR
/obj/item/clothing/head/modular/style/headband
name = "TGMC headband"
@@ -177,6 +185,7 @@
desc = "A bandana that goes on your head. Has TGMC markings on the back tie, and it seems that the knot will never come undone somehow."
icon_state = "headbandana_inhand"
item_state = "headbandana"
+ inv_hide_flags = HIDE_EXCESS_HAIR
// style masks
/obj/item/clothing/mask/gas/modular/skimask
@@ -184,8 +193,8 @@
desc = "A stylish skimask, can be recolored. Makes you feel like an operator just looking at it."
icon_state = "ski_inhand"
item_state = "ski"
- flags_inv_hide = HIDEALLHAIR|HIDEEARS
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ inv_hide_flags = HIDEALLHAIR|HIDEEARS
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
greyscale_config = /datum/greyscale_config/style_hat
@@ -194,5 +203,5 @@
desc = "The CFCC is a prime and readied, yet stylish facemask ready to... cover your face."
icon_state = "coof_inhand"
item_state = "coof"
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
greyscale_config = /datum/greyscale_config/style_hat
diff --git a/code/modules/clothing/modular_armor/xenonauten.dm b/code/modules/clothing/modular_armor/xenonauten.dm
index 7b9d5caee7108..7b3531efcbdce 100644
--- a/code/modules/clothing/modular_armor/xenonauten.dm
+++ b/code/modules/clothing/modular_armor/xenonauten.dm
@@ -22,6 +22,7 @@
/obj/item/armor_module/module/ballistic_armor,
/obj/item/armor_module/module/chemsystem,
/obj/item/armor_module/module/eshield,
+ /obj/item/armor_module/module/eshield/overclocked,
/obj/item/armor_module/storage/general,
/obj/item/armor_module/storage/ammo_mag,
@@ -36,7 +37,7 @@
/obj/item/armor_module/armor/badge,
)
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
greyscale_config = /datum/greyscale_config/xenonaut
colorable_allowed = PRESET_COLORS_ALLOWED
colorable_colors = ARMOR_PALETTES_LIST
@@ -44,24 +45,66 @@
allowed_uniform_type = /obj/item/clothing/under
+/obj/item/clothing/suit/modular/xenonauten/hodgrenades
+ starting_attachments = list(
+ /obj/item/armor_module/module/ballistic_armor,
+ /obj/item/armor_module/storage/grenade,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/engineer
starting_attachments = list(
/obj/item/armor_module/module/better_shoulder_lamp,
/obj/item/armor_module/storage/engineering,
)
+/obj/item/clothing/suit/modular/xenonauten/lightmedical
+ starting_attachments = list(
+ /obj/item/armor_module/module/better_shoulder_lamp,
+ /obj/item/armor_module/storage/medical,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/lightgeneral
+ starting_attachments = list(
+ /obj/item/armor_module/module/better_shoulder_lamp,
+ /obj/item/armor_module/storage/general,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/mimir
starting_attachments = list(
/obj/item/armor_module/module/mimir_environment_protection/mark1,
/obj/item/armor_module/storage/general,
)
+/obj/item/clothing/suit/modular/xenonauten/mimirinjector
+ starting_attachments = list(
+ /obj/item/armor_module/module/mimir_environment_protection/mark1,
+ /obj/item/armor_module/storage/injector,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/shield
starting_attachments = list(
/obj/item/armor_module/module/eshield,
/obj/item/armor_module/storage/medical,
)
+/obj/item/clothing/suit/modular/xenonauten/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/medical,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/shield_overclocked/medic
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/general,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/shield_overclocked/engineer
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/engineering,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/valk
starting_attachments = list(
/obj/item/armor_module/module/valkyrie_autodoc,
@@ -81,6 +124,30 @@
/obj/item/armor_module/storage/medical,
)
+/obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/medical,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked/medic
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/general,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/light/shield_overclocked/engineer
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/engineering,
+ )
+
+/obj/item/clothing/suit/modular/xenonauten/light/lightmedical
+ starting_attachments = list(
+ /obj/item/armor_module/module/better_shoulder_lamp,
+ /obj/item/armor_module/storage/medical,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/heavy
name = "\improper Xenonauten-H pattern armored vest"
desc = "A XN-H vest, also known as Xenonauten, a set vest with modular attachments made to work in many enviroments. This one seems to be a heavy variant. Alt-Click to remove attached items. Use it to toggle the built-in flashlight."
@@ -88,12 +155,24 @@
slowdown = SLOWDOWN_ARMOR_HEAVY
greyscale_config = /datum/greyscale_config/xenonaut/heavy
+/obj/item/clothing/suit/modular/xenonauten/heavy/mimirengi
+ starting_attachments = list(
+ /obj/item/armor_module/module/mimir_environment_protection/mark1,
+ /obj/item/armor_module/storage/engineering,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/heavy/leader
starting_attachments = list(
/obj/item/armor_module/module/valkyrie_autodoc,
/obj/item/armor_module/storage/medical,
)
+/obj/item/clothing/suit/modular/xenonauten/heavy/tyr_onegeneral
+ starting_attachments = list(
+ /obj/item/armor_module/module/tyr_extra_armor/mark1,
+ /obj/item/armor_module/storage/general,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/heavy/tyr_one
starting_attachments = list(
/obj/item/armor_module/module/tyr_extra_armor/mark1,
@@ -106,6 +185,12 @@
/obj/item/armor_module/storage/medical,
)
+/obj/item/clothing/suit/modular/xenonauten/heavy/grenadier //Literally grenades
+ starting_attachments = list(
+ /obj/item/armor_module/module/ballistic_armor,
+ /obj/item/armor_module/storage/grenade,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/heavy/surt
starting_attachments = list(
/obj/item/armor_module/module/fire_proof,
@@ -118,10 +203,16 @@
/obj/item/armor_module/storage/medical,
)
+/obj/item/clothing/suit/modular/xenonauten/heavy/shield_overclocked
+ starting_attachments = list(
+ /obj/item/armor_module/module/eshield/overclocked,
+ /obj/item/armor_module/storage/medical,
+ )
+
/obj/item/clothing/suit/modular/xenonauten/pilot
name = "\improper TerraGov standard flak jacket"
desc = "A flak jacket used by dropship pilots to protect themselves while flying in the cockpit. Excels in protecting the wearer against high-velocity solid projectiles."
- flags_item = NONE
+ item_flags = NONE
soft_armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 25, BOMB = 30, BIO = 5, FIRE = 25, ACID = 30)
slowdown = 0.25
@@ -130,6 +221,49 @@
attachments_allowed = list()
+ allowed = list(
+ /obj/item/weapon/gun,
+ /obj/item/tank/emergency_oxygen,
+ /obj/item/flashlight,
+ /obj/item/ammo_magazine,
+ /obj/item/storage/fancy/cigarettes,
+ /obj/item/tool/lighter,
+ /obj/item/weapon/baton,
+ /obj/item/restraints/handcuffs,
+ /obj/item/explosive/grenade,
+ /obj/item/binoculars,
+ /obj/item/weapon/combat_knife,
+ /obj/item/attachable/bayonetknife,
+ /obj/item/storage/belt/sparepouch,
+ /obj/item/storage/holster/blade,
+ /obj/item/storage/holster/belt,
+ /obj/item/weapon/energy/sword,
+ )
+
+/obj/item/clothing/suit/storage/marine/ballistic
+ name = "\improper Crasher multi-threat ballistic armor"
+ desc = "A reused design of a old body armor system from the 21st century."
+ soft_armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 25, BOMB = 30, BIO = 5, FIRE = 25, ACID = 30)
+ slowdown = 0.25
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ icon = 'icons/mob/clothing/suits/marine_armor.dmi'
+ icon_state = "ballistic_vest"
+ item_icons = list(
+ slot_wear_suit_str = 'icons/mob/clothing/suits/marine_armor.dmi'
+ )
+ equip_delay_self = 2 SECONDS
+ unequip_delay_self = 0 SECONDS
+ armor_features_flags = NONE
+
+ icon_state_variants = list(
+ "urban",
+ "jungle",
+ "desert",
+ "snow",
+ )
+ colorable_allowed = ICON_STATE_VARIANTS_ALLOWED
+ current_variant = "urban"
+
allowed = list(
/obj/item/weapon/gun,
/obj/item/tank/emergency_oxygen,
@@ -176,16 +310,28 @@
//RUTGMC EDIT ADDITION END
)
starting_attachments = list(/obj/item/armor_module/storage/helmet)
- flags_item_map_variant = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
+ item_map_variant_flags = ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_DESERT_VARIANT
greyscale_config = /datum/greyscale_config/xenonaut/helm
greyscale_colors = ARMOR_PALETTE_DRAB
visorless_offset_y = 0
+/obj/item/clothing/head/modular/m10x/hod
+ starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/hod_head)
+
+/obj/item/clothing/head/modular/m10x/freyr
+ starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/artemis)
+
+/obj/item/clothing/head/modular/m10x/antenna
+ starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/antenna)
+
/obj/item/clothing/head/modular/m10x/welding
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/welding)
+/obj/item/clothing/head/modular/m10x/superiorwelding
+ starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/welding/superior)
+
/obj/item/clothing/head/modular/m10x/mimir
starting_attachments = list(/obj/item/armor_module/storage/helmet, /obj/item/armor_module/module/mimir_environment_protection/mimir_helmet/mark1)
diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm
index 584a50987f776..f93b6c8002e76 100644
--- a/code/modules/clothing/shoes/colour.dm
+++ b/code/modules/clothing/shoes/colour.dm
@@ -3,9 +3,9 @@
icon_state = "black"
desc = "A pair of black shoes."
- flags_cold_protection = FEET
+ cold_protection_flags = FEET
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = FEET
+ heat_protection_flags = FEET
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/shoes/brown
@@ -81,7 +81,7 @@
remove_cuffs(user)
/obj/item/clothing/shoes/orange/attackby(obj/item/I, mob/user, params)
- . = ..()
-
if(istype(I, /obj/item/restraints/handcuffs))
attach_cuffs(I, user)
+ return
+ return ..()
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index de8bac8ae89e8..f59661fb62c49 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -7,13 +7,13 @@
/obj/item/clothing/shoes/magboots/attack_self(mob/user)
if(magpulse)
- flags_inventory &= ~NOSLIPPING
+ inventory_flags &= ~NOSLIPPING
slowdown = SHOES_SLOWDOWN
magpulse = 0
icon_state = "magboots0"
to_chat(user, "You disable the mag-pulse traction system.")
else
- flags_inventory |= NOSLIPPING
+ inventory_flags |= NOSLIPPING
slowdown = 2
magpulse = 1
icon_state = "magboots1"
@@ -26,6 +26,6 @@
/obj/item/clothing/shoes/magboots/examine(mob/user)
. = ..()
var/state = "disabled"
- if(flags_inventory&NOSLIPPING)
+ if(inventory_flags&NOSLIPPING)
state = "enabled"
. += "Its mag-pulse traction system appears to be [state]."
diff --git a/code/modules/clothing/shoes/marine_shoes.dm b/code/modules/clothing/shoes/marine_shoes.dm
index d9a18311802ed..aa3a304f868c6 100644
--- a/code/modules/clothing/shoes/marine_shoes.dm
+++ b/code/modules/clothing/shoes/marine_shoes.dm
@@ -3,10 +3,10 @@
desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time."
icon_state = "marine"
item_state = "marine"
- flags_armor_protection = FEET
- flags_cold_protection = FEET
- flags_heat_protection = FEET
- flags_inventory = NOQUICKEQUIP|NOSLIPPING
+ armor_protection_flags = FEET
+ cold_protection_flags = FEET
+ heat_protection_flags = FEET
+ inventory_flags = NOQUICKEQUIP|NOSLIPPING
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
siemens_coefficient = 0.7
@@ -26,6 +26,7 @@
update_icon()
/obj/item/clothing/shoes/marine/update_icon_state()
+ . = ..()
icon_state = initial(icon_state)
if(!attachments_by_slot[ATTACHMENT_SLOT_STORAGE])
return
@@ -58,7 +59,7 @@
desc = "Only a small amount of monkeys, kittens, and orphans were killed in making this."
icon_state = "laceups"
soft_armor = list(MELEE = 35, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 25)
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
siemens_coefficient = 0.6
/obj/item/clothing/shoes/marinechief/captain
@@ -81,13 +82,13 @@
desc = "The height of fashion, but these look to be woven with protective fiber."
icon_state = "jackboots"
item_state = "jackboots"
- flags_armor_protection = FEET
+ armor_protection_flags = FEET
soft_armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 15)
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
- flags_cold_protection = FEET
- flags_heat_protection = FEET
- flags_inventory = NOSLIPPING
+ cold_protection_flags = FEET
+ heat_protection_flags = FEET
+ inventory_flags = NOSLIPPING
siemens_coefficient = 0.6
/obj/item/clothing/shoes/marine/deathsquad
@@ -96,12 +97,12 @@
icon_state = "commando_boots"
item_state = "commando_boots"
permeability_coefficient = 0.01
- flags_armor_protection = FEET
+ armor_protection_flags = FEET
soft_armor = list(MELEE = 40, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 25)
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
- flags_cold_protection = FEET
- flags_heat_protection = FEET
+ cold_protection_flags = FEET
+ heat_protection_flags = FEET
siemens_coefficient = 0.2
resistance_flags = UNACIDABLE
starting_attachments = list(/obj/item/armor_module/storage/boot/full)
@@ -129,9 +130,9 @@
desc = "A field of invisible energy, it protects the wearer but prevents any clothing from being worn."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-blue"
- flags_item = DELONDROP
+ item_flags = DELONDROP
soft_armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 30, BIO = 20, FIRE = 20, ACID = 25)
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
/obj/item/clothing/shoes/sectoid/Initialize(mapload)
. = ..()
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 50cfa8a563d46..b30b842ba7863 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -8,7 +8,7 @@
icon_state = "brown"
item_state = "brown"
permeability_coefficient = 0.05
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
var/list/clothing_choices = list()
siemens_coefficient = 0.8
@@ -21,8 +21,8 @@
desc = "When you want to turn up the heat."
icon_state = "swat"
soft_armor = list(MELEE = 80, BULLET = 60, LASER = 50, ENERGY = 25, BOMB = 50, BIO = 10, FIRE = 25, ACID = 25)
- flags_inventory = NOSLIPPING
- flags_item = SYNTH_RESTRICTED
+ inventory_flags = NOSLIPPING
+ item_flags = SYNTH_RESTRICTED
siemens_coefficient = 0.6
/obj/item/clothing/shoes/ruggedboot
@@ -30,22 +30,22 @@
desc = "A pair of boots used by workers in dangerous environments."
icon_state = "swat"
soft_armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 25, BOMB = 20, BIO = 20, FIRE = 20, ACID = 20)
- flags_inventory = NOSLIPPING
- flags_item = SYNTH_RESTRICTED
+ inventory_flags = NOSLIPPING
+ item_flags = SYNTH_RESTRICTED
siemens_coefficient = 0.6
/obj/item/clothing/shoes/combat //Basically SWAT shoes combined with galoshes.
name = "combat boots"
desc = "When you REALLY want to turn up the heat"
icon_state = "swat"
- flags_item = SYNTH_RESTRICTED
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 80, BULLET = 60, LASER = 50, ENERGY = 25, BOMB = 50, BIO = 10, FIRE = 25, ACID = 25)
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
siemens_coefficient = 0.6
- flags_cold_protection = FEET
+ cold_protection_flags = FEET
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = FEET
+ heat_protection_flags = FEET
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/shoes/space_ninja
@@ -53,33 +53,33 @@
desc = "A pair of running shoes. Excellent for running and even better for smashing skulls."
icon_state = "s-ninja"
permeability_coefficient = 0.01
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
soft_armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, FIRE = 15, ACID = 15)
siemens_coefficient = 0.2
- flags_cold_protection = FEET
+ cold_protection_flags = FEET
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = FEET
+ heat_protection_flags = FEET
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/shoes/sandal
desc = "A pair of rather plain, wooden sandals."
name = "sandals"
icon_state = "wizard"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/shoes/sandal/marisa
desc = "A pair of magic, black shoes."
name = "magic shoes"
icon_state = "black"
- flags_armor_protection = FEET
+ armor_protection_flags = FEET
/obj/item/clothing/shoes/galoshes
desc = "Rubber boots"
name = "galoshes"
icon_state = "galoshes"
permeability_coefficient = 0.05
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
slowdown = SHOES_SLOWDOWN+1
/obj/item/clothing/shoes/clown_shoes
@@ -109,9 +109,9 @@
item_state = "cult"
siemens_coefficient = 0.7
- flags_cold_protection = FEET
+ cold_protection_flags = FEET
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- flags_heat_protection = FEET
+ heat_protection_flags = FEET
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/shoes/cyborg
@@ -142,7 +142,7 @@
desc = "Help you swim good."
name = "swimming fins"
icon_state = "flippers"
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
slowdown = SHOES_SLOWDOWN+1
@@ -151,8 +151,8 @@
desc = "When you feet are as cold as your heart"
icon_state = "swat"
siemens_coefficient = 0.6
- flags_cold_protection = FEET
- flags_heat_protection = FEET
+ cold_protection_flags = FEET
+ heat_protection_flags = FEET
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
@@ -161,6 +161,6 @@
desc = "Praise the machine spirit!"
icon_state = "tp_boots"
item_state = "tp_boots"
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm
index 5152ebdfde39b..9181e55479d2c 100644
--- a/code/modules/clothing/spacesuits/rig.dm
+++ b/code/modules/clothing/spacesuits/rig.dm
@@ -8,7 +8,7 @@
var/brightness_on = 4 //luminosity when on
var/on = FALSE
actions_types = list(/datum/action/item_action/toggle)
- flags_heat_protection = HEAD
+ heat_protection_flags = HEAD
max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/head/helmet/space/rig/attack_self(mob/user)
@@ -37,7 +37,7 @@
slowdown = 1
soft_armor = list(MELEE = 40, BULLET = 5, LASER = 20, ENERGY = 5, BOMB = 35, BIO = 100, FIRE = 5, ACID = 5)
allowed = list(/obj/item/flashlight,/obj/item/tank,/obj/item/suit_cooling_unit)
- flags_heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ heat_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE
//Engineering rig
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index 491b26213d4d3..504d8a60d5a4b 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -9,10 +9,10 @@
desc = "A special helmet designed for work in a hazardous, low-pressure environment."
permeability_coefficient = 0.01
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 0, ACID = 0)
- flags_inventory = COVEREYES|COVERMOUTH|NOPRESSUREDMAGE|BLOCKSHARPOBJ
- flags_inv_hide = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
- flags_cold_protection = HEAD
+ inventory_flags = COVEREYES|COVERMOUTH|NOPRESSUREDMAGE|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
+ cold_protection_flags = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
eye_protection = 2
@@ -26,12 +26,12 @@
w_class = WEIGHT_CLASS_BULKY
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen,/obj/item/suit_cooling_unit)
slowdown = 3
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 0, ACID = 0)
- flags_inventory = BLOCKSHARPOBJ|NOPRESSUREDMAGE
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inventory_flags = BLOCKSHARPOBJ|NOPRESSUREDMAGE
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
diff --git a/code/modules/clothing/spacesuits/standard_space_suits.dm b/code/modules/clothing/spacesuits/standard_space_suits.dm
index 0680ae66ec9a2..4723d9b559be8 100644
--- a/code/modules/clothing/spacesuits/standard_space_suits.dm
+++ b/code/modules/clothing/spacesuits/standard_space_suits.dm
@@ -26,13 +26,13 @@
w_class = WEIGHT_CLASS_BULKY
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS
allowed = list(/obj/item/tank/emergency_oxygen, /obj/item/flashlight,/obj/item/weapon/gun, /obj/item/ammo_magazine, /obj/item/weapon/baton,/obj/item/restraints/handcuffs)
slowdown = 1.5
soft_armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 25, BOMB = 50, BIO = 100, FIRE = 25, ACID = 25)
- flags_inventory = NOPRESSUREDMAGE
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inventory_flags = NOPRESSUREDMAGE
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.7
@@ -41,9 +41,9 @@
name = "Santa's hat"
desc = "Ho ho ho. Merrry X-mas!"
icon_state = "santahat"
- flags_inventory = NOPRESSUREDMAGE|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEYES
- flags_armor_protection = HEAD
+ inventory_flags = NOPRESSUREDMAGE|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEYES
+ armor_protection_flags = HEAD
/obj/item/clothing/suit/space/santa
name = "Santa's suit"
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index d90038f4cae4a..27631ca64b2b9 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -1,9 +1,9 @@
/obj/item/clothing/suit/armor
- flags_inventory = BLOCKSHARPOBJ
- flags_armor_protection = CHEST|GROIN
- flags_cold_protection = CHEST|GROIN
- flags_heat_protection = CHEST|GROIN
+ inventory_flags = BLOCKSHARPOBJ
+ armor_protection_flags = CHEST|GROIN
+ cold_protection_flags = CHEST|GROIN
+ heat_protection_flags = CHEST|GROIN
min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
siemens_coefficient = 0.6
@@ -35,7 +35,7 @@
item_state = "armor"
blood_overlay_type = "armor"
permeability_coefficient = 0.8
- flags_armor_protection = CHEST
+ armor_protection_flags = CHEST
soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 10, BOMB = 15, BIO = 0, FIRE = 10, ACID = 10)
allowed = list (
/obj/item/flashlight,
@@ -50,7 +50,7 @@
desc = "An armoured jacket with gold regalia"
icon_state = "admiral_jacket"
item_state = "admiral_jacket"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clothing/suit/armor/vest/security
@@ -65,7 +65,7 @@
desc = "An armoured jacket with silver rank pips and livery."
icon_state = "warden_jacket"
item_state = "warden_jacket"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/suit/armor/bulletproof
name = "bulletproof vest"
@@ -73,8 +73,8 @@
icon_state = "bulletproof"
item_state = "bulletproof"
blood_overlay_type = "armor"
- flags_armor_protection = CHEST
- soft_armor = list(MELEE = 30, BULLET = 55, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, FIRE = 0, ACID = 15)
+ armor_protection_flags = CHEST
+ soft_armor = list(MELEE = 30, BULLET = 75, LASER = 15, ENERGY = 15, BOMB = 30, BIO = 0, FIRE = 0, ACID = 15)
hard_armor = list(MELEE = 0, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 5)
siemens_coefficient = 0.7
permeability_coefficient = 0.9
@@ -93,12 +93,12 @@
desc = "A suit of armor with heavy padding to protect against melee attacks. Looks like it might impair movement."
icon_state = "riot"
item_state = "swat"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
slowdown = 1.2
soft_armor = list(MELEE = 65, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, FIRE = 10, ACID = 10)
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDEJUMPSUIT
- flags_item = SYNTH_RESTRICTED
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDEJUMPSUIT
+ item_flags = SYNTH_RESTRICTED
siemens_coefficient = 0.5
permeability_coefficient = 0.7
equip_delay_self = 20
@@ -111,14 +111,14 @@
item_state = "swat"
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS
allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/baton,/obj/item/restraints/handcuffs,/obj/item/tank/emergency_oxygen)
slowdown = 1
soft_armor = list(MELEE = 50, BULLET = 60, LASER = 50, ENERGY = 25, BOMB = 50, BIO = 100, FIRE = 25, ACID = 25)
- flags_inventory = BLOCKSHARPOBJ|NOPRESSUREDMAGE
- flags_item = SYNTH_RESTRICTED
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inventory_flags = BLOCKSHARPOBJ|NOPRESSUREDMAGE
+ item_flags = SYNTH_RESTRICTED
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.6
@@ -129,9 +129,9 @@
icon_state = "detective"
item_state = "det_suit"
blood_overlay_type = "coat"
- flags_inventory = NONE
- flags_inv_hide = NONE
- flags_armor_protection = CHEST|ARMS
+ inventory_flags = NONE
+ inv_hide_flags = NONE
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/armor/det_suit
@@ -140,8 +140,8 @@
icon_state = "detective-armor"
item_state = "detective-armor"
blood_overlay_type = "armor"
- flags_armor_protection = CHEST|GROIN
- flags_item = SYNTH_RESTRICTED
+ armor_protection_flags = CHEST|GROIN
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 50, BULLET = 15, LASER = 50, ENERGY = 10, BOMB = 25, BIO = 0, FIRE = 10, ACID = 10)
/obj/item/clothing/suit/armor/rugged
@@ -150,8 +150,8 @@
icon_state = "swatarmor"
item_state = "swatarmor"
var/obj/item/weapon/gun/holstered = null
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- flags_item = SYNTH_RESTRICTED
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ item_flags = SYNTH_RESTRICTED
slowdown = 0
soft_armor = list(MELEE = 50, BULLET = 40, LASER = 40, ENERGY = 40, BOMB = 50, BIO = 40, FIRE = 50, ACID = 50)
siemens_coefficient = 0.7
@@ -162,8 +162,8 @@
desc = "A field of invisible energy, it protects the wearer but prevents any clothing from being worn."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-blue"
- flags_item = DELONDROP
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ item_flags = DELONDROP
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
soft_armor = list(MELEE = 55, BULLET = 55, LASER = 35, ENERGY = 20, BOMB = 40, BIO = 40, FIRE = 40, ACID = 40)
allowed = list()//how would you put a gun onto a field of energy?
@@ -173,7 +173,7 @@
/obj/item/clothing/suit/armor/sectoid/shield
name = "powerful psionic field"
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
soft_armor = list(MELEE = 55, BULLET = 55, LASER = 35, ENERGY = 20, BOMB = 40, BIO = 40, FIRE = 40, ACID = 40)
/obj/item/clothing/suit/armor/sectoid/shield/Initialize(mapload)
@@ -190,11 +190,11 @@
icon_state = "centcom"
item_state = "centcom"
w_class = WEIGHT_CLASS_BULKY//bulky item
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/weapon/gun,/obj/item/weapon/baton,/obj/item/restraints/handcuffs,/obj/item/tank/emergency_oxygen)
- flags_inventory = NONE
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inventory_flags = NONE
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0
@@ -205,14 +205,14 @@
item_state = "swat_suit"
w_class = WEIGHT_CLASS_BULKY//bulky item
gas_transfer_coefficient = 0.90
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 3
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
siemens_coefficient = 0
/obj/item/clothing/suit/armor/tdome
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
/obj/item/clothing/suit/armor/tdome/red
name = "Thunderdome suit (red)"
@@ -233,11 +233,11 @@
desc = "A greatcoat enhanced with a special alloy for some protection and style."
icon_state = "hos"
item_state = "hos"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
- flags_item = SYNTH_RESTRICTED
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 65, BULLET = 30, LASER = 50, ENERGY = 10, BOMB = 25, BIO = 0, FIRE = 10, ACID = 10)
- flags_inventory = NONE
- flags_inv_hide = HIDEJUMPSUIT
+ inventory_flags = NONE
+ inv_hide_flags = HIDEJUMPSUIT
siemens_coefficient = 0.6
/obj/item/clothing/suit/armor/hos/jensen
@@ -245,7 +245,7 @@
desc = "A trenchcoat augmented with a special alloy for some protection and style."
icon_state = "jensencoat"
item_state = "jensencoat"
- flags_inv_hide = NONE
+ inv_hide_flags = NONE
siemens_coefficient = 0.6
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index 8f1e72456e806..e631d9be42085 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -5,9 +5,9 @@
desc = "A hood that protects the head and face from biological comtaminants."
permeability_coefficient = 0.01
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 0, ACID = 0)
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
siemens_coefficient = 0.9
/obj/item/clothing/suit/bio_suit
@@ -18,11 +18,11 @@
w_class = WEIGHT_CLASS_BULKY//bulky item
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 1
allowed = list(/obj/item/tank/emergency_oxygen,/obj/item/tool/pen,/obj/item/flashlight/pen)
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 0, ACID = 0)
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
siemens_coefficient = 0.9
//Virology biosuit, green stripe
@@ -31,8 +31,8 @@
/obj/item/clothing/suit/bio_suit/virology
icon_state = "bio_virology"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
//Security biosuit, grey with red stripe across the chest
/obj/item/clothing/head/bio_hood/security
@@ -40,8 +40,8 @@
/obj/item/clothing/suit/bio_suit/security
icon_state = "bio_security"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
//Janitor's biosuit, grey with purple arms
/obj/item/clothing/head/bio_hood/janitor
@@ -49,8 +49,8 @@
/obj/item/clothing/suit/bio_suit/janitor
icon_state = "bio_janitor"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
//Scientist's biosuit, white with a pink-ish hue
@@ -59,14 +59,14 @@
/obj/item/clothing/suit/bio_suit/scientist
icon_state = "bio_scientist"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
//CMO's biosuit, blue stripe
/obj/item/clothing/suit/bio_suit/cmo
icon_state = "bio_cmo"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
/obj/item/clothing/head/bio_hood/cmo
icon_state = "bio_cmo"
@@ -78,4 +78,4 @@
desc = "It protected doctors from the Black Death, back then. You bet your arse it's gonna help you against viruses."
icon_state = "plaguedoctor"
item_state = "bio_suit"
- flags_inv_hide = HIDEGLOVES|HIDEJUMPSUIT
+ inv_hide_flags = HIDEGLOVES|HIDEJUMPSUIT
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index d82c86293bb8a..5f320b47c166d 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -3,13 +3,13 @@
*/
//Botonist
-/obj/item/clothing/suit/apron
+/obj/item/clothing/suit/storage/apron
name = "apron"
desc = "A basic blue apron."
icon_state = "apron"
item_state = "apron"
blood_overlay_type = "armor"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
allowed = list (
/obj/item/reagent_containers/spray/plantbgone,
/obj/item/tool/analyzer/plant_analyzer,
@@ -29,7 +29,7 @@
desc = "A plastic covering to prevent the passage of bodily fluids during surgery."
icon_state = "surgical"
item_state = "surgical"
- flags_armor_protection = CHEST
+ armor_protection_flags = CHEST
allowed = list(
/obj/item/tank/emergency_oxygen,
/obj/item/healthanalyzer,
@@ -57,16 +57,16 @@
desc = "Worn by a Captain to show their class."
icon_state = "captunic"
item_state = "bio_suit"
- flags_armor_protection = CHEST|ARMS
- flags_inv_hide = HIDEJUMPSUIT
+ armor_protection_flags = CHEST|ARMS
+ inv_hide_flags = HIDEJUMPSUIT
/obj/item/clothing/suit/captunic/capjacket
name = "captain's uniform jacket"
desc = "A less formal jacket for everyday captain use."
icon_state = "capjacket"
item_state = "bio_suit"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEJUMPSUIT
//Chaplain
/obj/item/clothing/suit/chaplain_hoodie
@@ -74,40 +74,40 @@
desc = "This suit says to you 'hush'!"
icon_state = "chaplain_hoodie"
item_state = "chaplain_hoodie"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/nun
name = "nun robe"
desc = "Maximum piety in this star system."
icon_state = "nun"
item_state = "nun"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDESHOES|HIDEJUMPSUIT
//Chef
-/obj/item/clothing/suit/chef
+/obj/item/clothing/suit/storage/chef
name = "Chef's apron"
desc = "An apron used by a high class chef."
icon_state = "chef"
item_state = "chef"
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
allowed = list (/obj/item/tool/kitchen/knife,
/obj/item/tool/kitchen/knife/butcher)
-/obj/item/clothing/suit/chef/classic
+/obj/item/clothing/suit/storage/chef/classic
name = "A classic chef's apron."
desc = "A basic, dull, white chef's apron."
icon_state = "apronchef"
item_state = "apronchef"
blood_overlay_type = "armor"
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
//Security
/obj/item/clothing/suit/security
desc = "You shouldn't see this"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/suit/security/formal
name = "formal jacket"
@@ -125,12 +125,12 @@
/obj/item/clothing/suit/security/formal/officer/tan
icon_state = "wardentanjacket"
-/obj/item/clothing/suit/security/formal/senior_officer
+/obj/item/clothing/suit/storage/security/formal/senior_officer
name = "senior officer's jacket"
desc = "This piece of clothing was specifically designed for asserting superior authority."
icon_state = "hosbluejacket"
-/obj/item/clothing/suit/security/formal/senior_officer/tan
+/obj/item/clothing/suit/storage/security/formal/senior_officer/tan
icon_state = "hostanjacket"
//Detective
@@ -140,7 +140,7 @@
icon_state = "detective"
item_state = "det_suit"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
allowed = list(
/obj/item/tank/emergency_oxygen,
/obj/item/flashlight,
@@ -167,7 +167,7 @@
name = "jacket"
desc = "A forensics technician jacket."
item_state = "det_suit"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
allowed = list(
/obj/item/tank/emergency_oxygen,
/obj/item/flashlight,
@@ -214,7 +214,7 @@
/obj/item/clothing/mask/gas,
/obj/item/tool/taperoll/engineering,
)
- flags_armor_protection = CHEST
+ armor_protection_flags = CHEST
/obj/item/clothing/suit/storage/hazardvest/lime
name = "lime reflective safety vest"
@@ -233,7 +233,7 @@
icon_state = "suitjacket_blue_open"
item_state = "suitjacket_blue_open"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/storage/lawyer/purpjacket
name = "Purple Suit Jacket"
@@ -241,7 +241,7 @@
icon_state = "suitjacket_purp"
item_state = "suitjacket_purp"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
//Internal Affairs
/obj/item/clothing/suit/storage/internalaffairs
@@ -250,7 +250,7 @@
icon_state = "ia_jacket_open"
item_state = "ia_jacket"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/storage/internalaffairs/verb/toggle()
set name = "Toggle Coat Buttons"
@@ -289,7 +289,7 @@
/obj/item/radio,
/obj/item/tank/emergency_oxygen,
)
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/storage/fr_jacket/verb/toggle()
set name = "Toggle Jacket Buttons"
@@ -315,14 +315,14 @@
icon = 'icons/obj/clothing/belts.dmi'
icon_state = "suspenders"
blood_overlay_type = "armor" //it's the less thing that I can put here
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/suit/storage/snow_suit
name = "snow suit"
desc = "A standard snow suit. It can protect the wearer from extreme cold."
icon_state = "snowsuit_alpha"
- flags_armor_protection = CHEST|GROIN|ARMS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS
+ armor_protection_flags = CHEST|GROIN|ARMS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS
soft_armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
blood_overlay_type = "armor"
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index c90d2fee6a8c9..4497024be51ed 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -3,7 +3,7 @@
desc = "A suit that protects against minor chemical spills."
icon_state = "labcoat"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
permeability_coefficient = 0.6
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 50, FIRE = 0, ACID = 0)
allowed = list(
@@ -63,33 +63,37 @@
name = "chief medical officer's labcoat"
desc = "Bluer than the standard model."
icon_state = "labcoat_cmo"
-
/obj/item/clothing/suit/storage/labcoat/mad
name = "The Mad's labcoat"
desc = "It makes you look capable of konking someone on the noggin and shooting them into space."
icon_state = "labgreen"
-/obj/item/clothing/suit/storage/labcoat/genetics
- name = "Geneticist labcoat"
- desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
- icon_state = "labcoat_gen"
+/obj/item/clothing/suit/storage/labcoat/paramedic
+ name = "paramedic's labcoat"
+ desc = "A suit that holds small medical items for responding and tending to emergencies."
+ icon_state = "labcoat_paramedic"
/obj/item/clothing/suit/storage/labcoat/chemist
- name = "Chemist labcoat"
+ name = "chemist labcoat"
desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder."
icon_state = "labcoat_chem"
/obj/item/clothing/suit/storage/labcoat/virologist
- name = "Virologist labcoat"
+ name = "virologist labcoat"
desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
icon_state = "labcoat_viro"
+/obj/item/clothing/suit/storage/labcoat/genetics
+ name = "geneticist labcoat"
+ desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder."
+ icon_state = "labcoat_gen"
+
/obj/item/clothing/suit/storage/labcoat/science
- name = "Scientist labcoat"
+ name = "scientist labcoat"
desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
icon_state = "labcoat_sci"
/obj/item/clothing/suit/storage/labcoat/researcher
- name = "Researcher's labcoat"
+ name = "researcher's labcoat"
desc = "A high quality labcoat, seemingly worn by scholars and researchers alike. It has a distinct rough feel to it, and goads you towards adventure."
icon_state = "labcoat_researcher"
diff --git a/code/modules/clothing/suits/marine_armor.dm b/code/modules/clothing/suits/marine_armor.dm
index 1e672f8b7cd95..51febd51386ba 100644
--- a/code/modules/clothing/suits/marine_armor.dm
+++ b/code/modules/clothing/suits/marine_armor.dm
@@ -9,13 +9,13 @@
item_state = "armor"
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/marine_armor.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
- flags_atom = CONDUCT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
- flags_heat_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ atom_flags = CONDUCT
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ heat_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
blood_overlay_type = "armor"
@@ -38,32 +38,31 @@
/obj/item/tool/pickaxe/plasmacutter,
)
var/locate_cooldown = 0 //Cooldown for SL locator
- var/list/armor_overlays
+ var/list/armor_overlays = list()
actions_types = list(/datum/action/item_action/toggle/suit_toggle)
- flags_armor_features = ARMOR_LAMP_OVERLAY
- flags_item = SYNTH_RESTRICTED|IMPEDE_JETPACK
+ armor_features_flags = ARMOR_LAMP_OVERLAY
+ item_flags = SYNTH_RESTRICTED|IMPEDE_JETPACK
w_class = WEIGHT_CLASS_HUGE
equip_delay_self = 2 SECONDS
unequip_delay_self = 2 SECONDS
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
/obj/item/clothing/suit/storage/marine/Initialize(mapload)
. = ..()
- armor_overlays = list("lamp") //Just one for now, can add more later.
update_icon()
-/obj/item/clothing/suit/storage/marine/update_icon(mob/user)
- var/image/I
- I = armor_overlays["lamp"]
- overlays -= I
- qdel(I)
- if(flags_armor_features & ARMOR_LAMP_OVERLAY)
- I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off")
+/obj/item/clothing/suit/storage/marine/turn_light(mob/user, toggle_on)
+ . = ..()
+ user?.update_inv_wear_suit()
+
+/obj/item/clothing/suit/storage/marine/update_overlays()
+ . = ..()
+ if(armor_features_flags & ARMOR_LAMP_OVERLAY)
+ var/image/I = image(icon, src, armor_features_flags & ARMOR_LAMP_ON? "lamp-on" : "lamp-off")
armor_overlays["lamp"] = I
- overlays += I
+ . += I
else
armor_overlays["lamp"] = null
- user?.update_inv_wear_suit()
/obj/item/clothing/suit/storage/marine/apply_custom(mutable_appearance/standing, inhands, icon_used, state_used)
if(inhands)
@@ -87,8 +86,8 @@
var/mob/living/carbon/human/H = user
if(H.wear_suit != src)
return
- turn_light(user, !light_on)
- return TRUE
+ if(turn_light(user, !light_on) == CHECKS_PASSED)
+ return TRUE
/obj/item/clothing/suit/storage/marine/item_action_slot_check(mob/user, slot)
if(!ishuman(user))
@@ -104,7 +103,25 @@
item_state = "mech_pilot_suit"
slowdown = SLOWDOWN_ARMOR_LIGHT
soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
+
+/obj/item/clothing/suit/storage/marine/assault_crewman
+ name = "\improper PAS-73 pattern tanker armor"
+ desc = "A somewhat sparsely armored but robust armored vest. Used by tankers, mostly to absorb bumps in the road as they drive over enemies."
+ icon_state = "assault_crewman_suit"
+ item_state = "assault_crewman_suit"
+ slowdown = SLOWDOWN_ARMOR_LIGHT
+ soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35)
+ item_map_variant_flags = NONE
+
+/obj/item/clothing/suit/storage/marine/transport_crewman
+ name = "\improper PAS-74 pattern transport armor"
+ desc = "A somewhat sparsely armored but robust armored vest. Used by transport crewmen so that they can pretend that they may survice when their vehicle is overrun."
+ icon_state = "transport_crewman_suit"
+ item_state = "transport_crewman_suit"
+ slowdown = SLOWDOWN_ARMOR_LIGHT
+ soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35)
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/riot
name = "\improper M5 riot control armor"
@@ -124,7 +141,7 @@
/obj/item/storage/belt/knifepouch,
/obj/item/weapon/twohanded,
)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
//===========================SPECIALIST================================
@@ -137,23 +154,23 @@
slowdown = SLOWDOWN_ARMOR_MEDIUM
supporting_limbs = CHEST | GROIN | ARM_LEFT | ARM_RIGHT | HAND_LEFT | HAND_RIGHT | LEG_LEFT | LEG_RIGHT | FOOT_LEFT | FOOT_RIGHT | HEAD //B18 effectively stabilizes these.
resistance_flags = UNACIDABLE
- obj_flags = AUTOBALANCE_CHECK
+ item_flags = AUTOBALANCE_CHECK
/obj/item/clothing/suit/storage/marine/specialist/Initialize(mapload, ...)
. = ..()
AddComponent(/datum/component/suit_autodoc)
AddComponent(/datum/component/stun_mitigation, slot_override = SLOT_WEAR_SUIT, shield_cover = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, FIRE = 50, ACID = 50))
AddElement(/datum/element/limb_support, supporting_limbs)
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.b18_in_use += src
/obj/item/clothing/suit/storage/marine/specialist/Destroy()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.b18_in_use -= src
return ..()
/obj/item/clothing/suit/storage/marine/specialist/valhalla
- obj_flags = NONE
+ item_flags = NONE
/obj/item/clothing/suit/storage/marine/B17
name = "\improper B17 defensive armor"
@@ -162,20 +179,20 @@
soft_armor = list(MELEE = 75, BULLET = 75, LASER = 50, ENERGY = 55, BOMB = 100, BIO = 55, FIRE = 75, ACID = 65)
max_heat_protection_temperature = HEAVYARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
slowdown = SLOWDOWN_ARMOR_MEDIUM
- obj_flags = AUTOBALANCE_CHECK
+ item_flags = AUTOBALANCE_CHECK
/obj/item/clothing/suit/storage/marine/B17/Initialize(mapload, ...)
. = ..()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.b17_in_use += src
/obj/item/clothing/suit/storage/marine/B17/Destroy()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.b17_in_use -= src
return ..()
/obj/item/clothing/suit/storage/marine/B17/valhalla
- obj_flags = NONE
+ item_flags = NONE
////////////////////////////////
@@ -184,7 +201,7 @@
desc = "A somewhat outdated but robust armored vest, still in use despite the rise of exoskeleton armor due to ease of use and manufacturing. It offers more protection against the exotic dangers that technicians face."
icon_state = "tanker"
soft_armor = list(MELEE = 40, BULLET = 55, LASER = 60, ENERGY = 45, BOMB = 60, BIO = 45, FIRE = 45, ACID = 65)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/officer
name = "\improper PAS-N3 pattern officer armor"
@@ -192,7 +209,7 @@
icon_state = "officer"
soft_armor = list(MELEE = 40, BULLET = 60, LASER = 60, ENERGY = 45, BOMB = 45, BIO = 45, FIRE = 45, ACID = 50)
slowdown = 0.5
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
allowed = list(
/obj/item/weapon/gun,
/obj/item/tank/emergency_oxygen,
@@ -223,16 +240,16 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
- flags_armor_features = ARMOR_LAMP_OVERLAY
+ armor_features_flags = ARMOR_LAMP_OVERLAY
/obj/item/clothing/suit/storage/marine/veteran/pmc
name = "\improper M4 pattern PMC armor"
desc = "A common armor vest that is designed for high-profile security operators and corporate mercenaries in mind."
icon_state = "pmc_armor"
- soft_armor = list(MELEE = 55, BULLET = 70, LASER = 60, ENERGY = 38, BOMB = 50, BIO = 15, FIRE = 38, ACID = 45)
+ soft_armor = list(MELEE = 55, BULLET = 70, LASER = 60, ENERGY = 55, BOMB = 50, BIO = 15, FIRE = 38, ACID = 45)
slowdown = SLOWDOWN_ARMOR_LIGHT
allowed = list(
/obj/item/weapon/gun,
@@ -248,7 +265,7 @@
/obj/item/weapon/claymore/mercsword/machete,
/obj/item/weapon/combat_knife,
)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/veteran/pmc/leader
name = "\improper M4 pattern PMC leader armor"
@@ -261,8 +278,8 @@
name = "\improper M4 pattern PMC sniper armor"
icon_state = "pmc_sniper"
soft_armor = list(MELEE = 55, BULLET = 65, LASER = 55, ENERGY = 60, BOMB = 75, BIO = 10, FIRE = 60, ACID = 60)
- flags_inventory = BLOCKSHARPOBJ
- flags_inv_hide = HIDELOWHAIR
+ inventory_flags = BLOCKSHARPOBJ
+ inv_hide_flags = HIDELOWHAIR
/obj/item/clothing/suit/storage/marine/veteran/pmc/gunner
name = "\improper PMC gunner armor"
@@ -270,7 +287,7 @@
icon_state = "pmc_heavyarmor"
slowdown = SLOWDOWN_ARMOR_HEAVY
soft_armor = list(MELEE = 65, BULLET = 80, LASER = 70, ENERGY = 70, BOMB = 80, BIO = 30, FIRE = 65, ACID = 65)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/*===========================Death Commando============================*/
/obj/item/clothing/suit/storage/marine/veteran/pmc/commando
@@ -297,12 +314,12 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "guardarmor"
soft_armor = list(MELEE = 75, BULLET = 65, LASER = 60, ENERGY = 60, BOMB = 50, BIO = 0, FIRE = 60, ACID = 60)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/imperial/sergeant
// SL armour, better than flak, covers more
@@ -338,6 +355,17 @@
icon_state = "commissar_coat"
item_state = "commissar_coat"
soft_armor = list(MELEE = 75, BULLET = 60, LASER = 55, ENERGY = 40, BOMB = 45, BIO = 15, FIRE = 40, ACID = 40)
+ allowed = list(
+ /obj/item/weapon/gun,
+ /obj/item/instrument,
+ /obj/item/storage/belt/sparepouch,
+ /obj/item/storage/holster/blade,
+ /obj/item/weapon/claymore,
+ /obj/item/storage/holster/belt,
+ /obj/item/storage/belt/knifepouch,
+ /obj/item/weapon/twohanded,
+ /obj/item/tool/pickaxe/plasmacutter,
+ )
/*===========================U.S.L================================*/
@@ -345,13 +373,13 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
- flags_atom = CONDUCT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_heat_protection =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ atom_flags = CONDUCT
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ heat_protection_flags =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE
max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
blood_overlay_type = "armor"
@@ -371,8 +399,8 @@
/obj/item/storage/holster/blade,
/obj/item/weapon/twohanded,
)
- flags_armor_features = ARMOR_LAMP_OVERLAY
- flags_item = SYNTH_RESTRICTED
+ armor_features_flags = ARMOR_LAMP_OVERLAY
+ item_flags = SYNTH_RESTRICTED
var/locate_cooldown = 0 //Cooldown for SL locator
var/armor_overlays["lamp"]
actions_types = list(/datum/action/item_action/toggle)
@@ -382,18 +410,14 @@
armor_overlays = list("lamp")
update_icon()
-/obj/item/clothing/suit/storage/faction/update_icon(mob/user)
- var/image/I
- I = armor_overlays["lamp"]
- overlays -= I
- qdel(I)
- if(flags_armor_features & ARMOR_LAMP_OVERLAY)
- I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off")
+/obj/item/clothing/suit/storage/faction/update_overlays()
+ . = ..()
+ if(armor_features_flags & ARMOR_LAMP_OVERLAY)
+ var/image/I = image(icon, src, armor_features_flags & ARMOR_LAMP_ON? "lamp-on" : "lamp-off")
armor_overlays["lamp"] = I
- overlays += I
- else armor_overlays["lamp"] = null
- if(user) user.update_inv_wear_suit()
-
+ . += I
+ else
+ armor_overlays["lamp"] = null
/obj/item/clothing/suit/storage/faction/attack_self(mob/user)
if(!isturf(user.loc))
@@ -407,8 +431,8 @@
var/mob/living/carbon/human/H = user
if(H.wear_suit != src) return
- turn_light(user, !light_on)
- return 1
+ if(turn_light(user, !light_on) == CHECKS_PASSED)
+ return TRUE
/obj/item/clothing/suit/storage/faction/item_action_slot_check(mob/user, slot)
if(!ishuman(user)) return FALSE
@@ -420,7 +444,7 @@
desc = "Standard body armor of the USL pirates, the UM5 (United Medium MK5) is a medium body armor, roughly on par with the venerable M3 pattern body armor in service with the TGMC."
icon_state = "upp_armor"
slowdown = SLOWDOWN_ARMOR_MEDIUM
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
soft_armor = list(MELEE = 55, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 55, BIO = 10, FIRE = 60, ACID = 60)
/// Modified version of the armor for HvH combat. Stats are based on medium armor, with tyr mark 2.
@@ -467,9 +491,9 @@
desc = "A armored protective chestplate scrapped together from various plates. It keeps up remarkably well, as the craftsmanship is solid, and the design mirrors such armors in the UPP and the TGMC."
icon_state = "freelancer_armor"
slowdown = SLOWDOWN_ARMOR_LIGHT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_heat_protection =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ heat_protection_flags =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
soft_armor = list(MELEE = 50, BULLET = 60, LASER = 50, ENERGY = 60, BOMB = 40, BIO = 10, FIRE = 60, ACID = 50)
attachments_by_slot = list(
ATTACHMENT_SLOT_STORAGE,
@@ -540,10 +564,10 @@
desc = "The hauberk of a colonist militia member, created from boiled leather and some modern armored plates. While primitive compared to most modern suits of armor, it gives the wearer almost perfect mobility, which suits the needs of the local colonists. "
icon_state = "rebel_armor"
slowdown = SLOWDOWN_ARMOR_VERY_LIGHT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_heat_protection =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_item = SYNTH_RESTRICTED
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ heat_protection_flags =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 30, BOMB = 60, BIO = 30, FIRE = 30, ACID = 30)
allowed = list(
/obj/item/weapon/twohanded,
@@ -580,9 +604,9 @@
desc = "A green jacket worn by TGMC personnel. The back has the flag of the TerraGov on it."
icon_state = "RO_jacket"
blood_overlay_type = "coat"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_heat_protection =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ heat_protection_flags =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
/*===========================HELGHAST - MERCENARY================================*/
@@ -655,15 +679,15 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "som_armor"
item_state = "som_armor"
slowdown = SLOWDOWN_ARMOR_LIGHT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
soft_armor = list(MELEE = 50, BULLET = 55, LASER = 55, ENERGY = 55, BOMB = 55, BIO = 55, FIRE = 55, ACID = 55)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/som/veteran
name = "\improper S12 combat Hauberk"
@@ -671,7 +695,7 @@
icon_state = "som_armor_veteran"
item_state = "som_armor_veteran"
slowdown = SLOWDOWN_ARMOR_HEAVY
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
soft_armor = list(MELEE = 65, BULLET = 70, LASER = 70, ENERGY = 55, BOMB = 55, BIO = 55, FIRE = 55, ACID = 60)
/obj/item/clothing/suit/storage/marine/som/leader
@@ -680,7 +704,7 @@
icon_state = "som_armor_leader"
item_state = "som_armor_leader"
slowdown = SLOWDOWN_ARMOR_MEDIUM
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|HANDS|FEET
soft_armor = list(MELEE = 55, BULLET = 50, LASER = 40, ENERGY = 55, BOMB = 55, BIO = 55, FIRE = 55, ACID = 60)
/obj/item/clothing/suit/storage/marine/icc
@@ -689,19 +713,57 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "icc"
slowdown = SLOWDOWN_ARMOR_MEDIUM
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
- flags_heat_protection =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS|FEET|HANDS
+ heat_protection_flags =CHEST|GROIN|ARMS|LEGS|FEET|HANDS
soft_armor = list(MELEE = 50, BULLET = 60, LASER = 50, ENERGY = 60, BOMB = 70, BIO = 10, FIRE = 60, ACID = 50)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
/obj/item/clothing/suit/storage/marine/icc/guard
name = "\improper Modelle/19 combat armor"
desc = "A piece of ICCGF body armor, worn by specialized infantry. Most Infantry actions in the ICC forces are done by adhoc personnel due to constant shortages of manpower, however most real Infantry divisions are of high quality, and are better known as 'Guardsmen'. Protects well from most sources, and will entirely protect from explosions."
icon_state = "icc_guard"
soft_armor = list(MELEE = 60, BULLET = 65, LASER = 40, ENERGY = 60, BOMB = 85, BIO = 10, FIRE = 55, ACID = 40)
+
+/obj/item/clothing/suit/storage/marine/icc/guard/heavy
+ name = "\improper Modelle/22 'Cuirassier' combat armor"
+ desc = "A piece of ICCGF body armor, worn by specialized infantry. Most Infantry actions in the ICC forces are done by adhoc personnel due to constant shortages of manpower, however most real Infantry divisions are of high quality, and are better known as 'Guardsmen'. Protects well from most sources, and will entirely protect from explosions."
+ icon_state = "icc_guard_heavy"
+ soft_armor = list(MELEE = 70, BULLET = 75, LASER = 40, ENERGY = 60, BOMB = 90, BIO = 10, FIRE = 55, ACID = 40)
+
+//===========================SPEC OPS================================
+
+/obj/item/clothing/suit/storage/marine/specops
+ name = "Ballistic vest"
+ desc = "Civilian type armor, made to combat both melee and projectiles."
+ icon = 'icons/mob/clothing/suits/ert_suits.dmi'
+ item_icons = list(
+ slot_wear_suit_str = 'icons/mob/clothing/suits/ert_suits.dmi',
+ )
+ icon_state = "specops_vest"
+ soft_armor = list(MELEE = 30, BULLET = 50, LASER = 20, ENERGY = 25, BOMB = 30, BIO = 5, FIRE = 25, ACID = 30)
+ slowdown = SLOWDOWN_ARMOR_LIGHT
+ armor_protection_flags = CHEST|GROIN
+ armor_features_flags = NONE
+
+/obj/item/clothing/suit/storage/marine/specops/support
+ name = "Ballistic vest"
+ desc = "Civilian type armor, made to combat both melee and projectiles."
+ icon_state = "specops_vest_support"
+
+/obj/item/clothing/suit/storage/marine/specops/medic
+ name = "Ballistic vest"
+ desc = "Civilian type armor, made to combat both melee and projectiles."
+ icon_state = "specops_vest_medic"
+
+/obj/item/clothing/suit/storage/marine/specops/leader
+ name = "Ballistic vest"
+ desc = "Civilian type armor, made to combat both melee and projectiles. Comes with tactical elbow pads."
+ icon_state = "specops_vest_leader"
+ soft_armor = list(MELEE = 50, BULLET = 50, LASER = 40, ENERGY = 35, BOMB = 30, BIO = 5, FIRE = 25, ACID = 30)
+ slowdown = SLOWDOWN_ARMOR_MEDIUM
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 6605025912769..f181cb246c69d 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -14,7 +14,7 @@
icon_state = "bluetag"
item_state = "bluetag"
blood_overlay_type = "armor"
- flags_armor_protection = CHEST
+ armor_protection_flags = CHEST
allowed = list (/obj/item/weapon/gun)
siemens_coefficient = 3
@@ -24,7 +24,7 @@
icon_state = "redtag"
item_state = "redtag"
blood_overlay_type = "armor"
- flags_armor_protection = CHEST
+ armor_protection_flags = CHEST
allowed = list (/obj/item/weapon/gun)
siemens_coefficient = 3
@@ -36,7 +36,7 @@
desc = "Yarr."
icon_state = "pirate"
item_state = "pirate"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
/obj/item/clothing/suit/hgpirate
@@ -44,9 +44,9 @@
desc = "Yarr."
icon_state = "hgpirate"
item_state = "hgpirate"
- flags_inv_hide = HIDEJUMPSUIT
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
- flags_item = SYNTH_RESTRICTED
+ inv_hide_flags = HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
+ item_flags = SYNTH_RESTRICTED
soft_armor = list(MELEE = 60, BULLET = 90, LASER = 60, ENERGY = 20, BOMB = 25, BIO = 10, FIRE = 20, ACID = 20)
@@ -55,8 +55,8 @@
desc = "Suit for a cyborg costume."
icon_state = "death"
item_state = "death"
- flags_atom = CONDUCT
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ atom_flags = CONDUCT
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
/obj/item/clothing/suit/johnny_coat
name = "johnny~~ coat"
@@ -69,17 +69,17 @@
desc = "This pretty much looks ridiculous."
icon_state = "justice"
item_state = "justice"
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_armor_protection = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
/obj/item/clothing/suit/judgerobe
name = "judge's robe"
desc = "This robe commands authority."
icon_state = "judge"
item_state = "judge"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
allowed = list(/obj/item/storage/fancy/cigarettes,/obj/item/spacecash)
- flags_inv_hide = HIDEJUMPSUIT
+ inv_hide_flags = HIDEJUMPSUIT
/obj/item/clothing/suit/wcoat
name = "waistcoat"
@@ -87,15 +87,15 @@
icon_state = "vest"
item_state = "wcoat"
blood_overlay_type = "armor"
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
-/obj/item/clothing/suit/apron/overalls
+/obj/item/clothing/suit/storage/apron/overalls
name = "coveralls"
desc = "A set of denim overalls."
icon_state = "overalls"
item_state = "overalls"
- flags_armor_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
/obj/item/clothing/suit/syndicatefake
@@ -105,16 +105,16 @@
desc = "A plastic replica of the syndicate space suit, you'll look just like a real murderous syndicate agent in this! This is a toy, it is not made for use in space!"
w_class = WEIGHT_CLASS_NORMAL
allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen,/obj/item/toy)
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_armor_protection = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
/obj/item/clothing/suit/hastur
name = "Hastur's Robes"
desc = "Robes not meant to be worn by man"
icon_state = "hastur"
item_state = "hastur"
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
/obj/item/clothing/suit/imperium_monk
@@ -122,8 +122,8 @@
desc = "Have YOU killed a xenos today?"
icon_state = "imperium_monk"
item_state = "imperium_monk"
- flags_armor_protection = HEAD|CHEST|GROIN|LEGS|FEET|ARMS
- flags_inv_hide = HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = HEAD|CHEST|GROIN|LEGS|FEET|ARMS
+ inv_hide_flags = HIDESHOES|HIDEJUMPSUIT
/obj/item/clothing/suit/chickensuit
@@ -131,8 +131,8 @@
desc = "A suit made long ago by the ancient empire KFC."
icon_state = "chickensuit"
item_state = "chickensuit"
- flags_armor_protection = CHEST|ARMS|GROIN|LEGS|FEET
- flags_inv_hide = HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|ARMS|GROIN|LEGS|FEET
+ inv_hide_flags = HIDESHOES|HIDEJUMPSUIT
siemens_coefficient = 2
@@ -141,8 +141,8 @@
desc = "A suit that looks like a primate"
icon_state = "monkeysuit"
item_state = "monkeysuit"
- flags_armor_protection = CHEST|ARMS|GROIN|LEGS|FEET|HANDS
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|ARMS|GROIN|LEGS|FEET|HANDS
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
siemens_coefficient = 2
@@ -151,8 +151,8 @@
desc = "This is a nice holiday my son."
icon_state = "holidaypriest"
item_state = "holidaypriest"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_inv_hide = HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ inv_hide_flags = HIDEJUMPSUIT
/obj/item/clothing/suit/cardborg
@@ -160,8 +160,8 @@
desc = "An ordinary cardboard box with holes cut in the sides."
icon_state = "cardborg"
item_state = "cardborg"
- flags_armor_protection = CHEST|GROIN
- flags_inv_hide = HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN
+ inv_hide_flags = HIDEJUMPSUIT
/obj/item/clothing/suit/white_dress_jacket
@@ -183,8 +183,8 @@
desc = "A suit that completely restrains the wearer."
icon_state = "straight_jacket"
item_state = "straight_jacket"
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
/obj/item/clothing/suit/straight_jacket/equipped(mob/living/carbon/user, slot)
@@ -209,7 +209,7 @@
desc = "A worn out, curiously comfortable t-shirt with a picture of Ian. You wouldn't go so far as to say it feels like being hugged when you wear it but it's pretty close. Good for sleeping in."
icon_state = "ianshirt"
item_state = "ianshirt"
- flags_armor_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
//Blue suit jacket toggle
/obj/item/clothing/suit/suit/verb/toggle()
@@ -241,14 +241,14 @@
desc = "Slightly old-fashioned sleepwear."
icon_state = "blue_pyjamas"
item_state = "blue_pyjamas"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
/obj/item/clothing/under/redpyjamas
name = "red pyjamas"
desc = "Slightly old-fashioned sleepwear."
icon_state = "red_pyjamas"
item_state = "red_pyjamas"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
//coats
@@ -275,13 +275,13 @@
desc = "A suit made out of chitinous alien hide."
icon_state = "xenos"
item_state = "xenos_helm"
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
siemens_coefficient = 2
//swimsuit
/obj/item/clothing/under/swimsuit/
siemens_coefficient = 1
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/under/swimsuit/black
name = "black swimsuit"
@@ -328,12 +328,12 @@
desc = "Your classic, non-racist poncho. This one is red."
icon_state = "redponcho"
-/obj/item/clothing/suit/bomber
+/obj/item/clothing/suit/storage/bomber
name = "bomber jacket"
desc = "A well-worn WW2 leather bomber jacket."
icon_state = "bomber"
- flags_armor_protection = CHEST|ARMS
- flags_cold_protection = CHEST|ARMS
+ armor_protection_flags = CHEST|ARMS
+ cold_protection_flags = CHEST|ARMS
min_cold_protection_temperature = T0C
siemens_coefficient = 0.7
allowed = list (
@@ -350,17 +350,17 @@
icon = 'icons/obj/clothing/suits/ert_suits.dmi'
item_icons = list(
slot_wear_suit_str = 'icons/mob/clothing/suits/marine_armor.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
icon_state = "rebel_armor"
item_state = "rebel_armor"
- flags_armor_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
/obj/item/clothing/suit/techpriest
name = "Techpriest Robes"
desc = "Praise the omnissiah!"
icon_state = "tp_bodyrobes"
item_state = "tp_bodyrobes"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index bd218054515a3..bdbdb87ceb7e6 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -18,15 +18,15 @@
w_class = WEIGHT_CLASS_BULKY//bulky item
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- flags_item = IMPEDE_JETPACK
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ item_flags = IMPEDE_JETPACK
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen,/obj/item/tool/extinguisher)
slowdown = 1
- flags_inventory = NOPRESSUREDMAGE
- flags_inv_hide = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags_heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ inventory_flags = NOPRESSUREDMAGE
+ inv_hide_flags = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
+ heat_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
/obj/item/clothing/suit/fire/heavy
name = "firesuit"
@@ -45,9 +45,9 @@
desc = "Use in case of bomb."
icon_state = "bombsuit"
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 100, BIO = 0, FIRE = 0, ACID = 0)
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
siemens_coefficient = 0
@@ -61,21 +61,21 @@
permeability_coefficient = 0.01
slowdown = 2
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 100, BIO = 0, FIRE = 0, ACID = 0)
- flags_inv_hide = HIDEJUMPSUIT
- flags_heat_protection = CHEST|GROIN
+ inv_hide_flags = HIDEJUMPSUIT
+ heat_protection_flags = CHEST|GROIN
max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
siemens_coefficient = 0
/obj/item/clothing/head/bomb_hood/security
icon_state = "bombsuitsec"
item_state = "bombsuitsec"
- flags_armor_protection = HEAD
+ armor_protection_flags = HEAD
/obj/item/clothing/suit/bomb_suit/security
icon_state = "bombsuitsec"
item_state = "bombsuitsec"
allowed = list(/obj/item/weapon/gun,/obj/item/weapon/baton,/obj/item/restraints/handcuffs)
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
/*
* Radiation protection
@@ -84,9 +84,9 @@
name = "Radiation Hood"
icon_state = "rad"
desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation"
- flags_inventory = COVEREYES|COVERMOUTH
- flags_inv_hide = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
- flags_armor_protection = HEAD|FACE|EYES
+ inventory_flags = COVEREYES|COVERMOUTH
+ inv_hide_flags = HIDEFACE|HIDEMASK|HIDEEARS|HIDEALLHAIR
+ armor_protection_flags = HEAD|FACE|EYES
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, FIRE = 0, ACID = 0)
@@ -98,8 +98,8 @@
w_class = WEIGHT_CLASS_BULKY//bulky item
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS|HANDS|FEET
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS|HANDS|FEET
allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen,/obj/item/clothing/head/radiation,/obj/item/clothing/mask/gas)
slowdown = 1.5
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, FIRE = 0, ACID = 0)
- flags_inv_hide = HIDEJUMPSUIT
+ inv_hide_flags = HIDEJUMPSUIT
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index b5c3122d3b9da..272d2a8d72d23 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -4,7 +4,7 @@
icon_state = "wizard"
//Not given any special protective value since the magic robes are full-body protection --NEO
siemens_coefficient = 0.8
- flags_armor_protection = NONE
+ armor_protection_flags = NONE
/obj/item/clothing/head/wizard/red
name = "red wizard hat"
@@ -16,7 +16,7 @@
name = "wizard hat"
desc = "It has WIZZARD written across it in sequins. Comes with a cool beard."
icon_state = "wizard-fake"
- flags_armor_protection = HEAD|FACE
+ armor_protection_flags = HEAD|FACE
/obj/item/clothing/head/wizard/marisa
name = "Witch Hat"
@@ -30,7 +30,7 @@
icon_state = "magus"
item_state = "magus"
siemens_coefficient = 0.8
- flags_armor_protection = HEAD|FACE|EYES
+ armor_protection_flags = HEAD|FACE|EYES
/obj/item/clothing/head/wizard/amp
name = "psychic amplifier"
@@ -53,7 +53,7 @@
permeability_coefficient = 0.01
soft_armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, FIRE = 20, ACID = 20)
allowed = list()
- flags_inv_hide = HIDEJUMPSUIT
+ inv_hide_flags = HIDEJUMPSUIT
siemens_coefficient = 0.8
/obj/item/clothing/suit/wizrobe/red
@@ -74,14 +74,14 @@
desc = "A set of armoured robes that seem to radiate a dark power"
icon_state = "magusblue"
item_state = "magusblue"
- flags_armor_protection = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
+ armor_protection_flags = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
/obj/item/clothing/suit/wizrobe/magusred
name = "Magus Robe"
desc = "A set of armoured robes that seem to radiate a dark power"
icon_state = "magusred"
item_state = "magusred"
- flags_armor_protection = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
+ armor_protection_flags = CHEST|GROIN|ARMS|HANDS|LEGS|FEET
/obj/item/clothing/suit/wizrobe/psypurple
name = "purple robes"
@@ -89,13 +89,13 @@
icon_state = "psyamp"
item_state = "psyamp"
-/obj/item/clothing/suit/wizrobe/gentlecoat
+/obj/item/clothing/suit/storage/wizrobe/gentlecoat
name = "Gentlemans Coat"
desc = "A heavy threaded twead gray jacket. For a different sort of Gentleman."
icon_state = "gentlecoat"
item_state = "gentlecoat"
- flags_armor_protection = CHEST|GROIN|ARMS
- flags_inv_hide = NONE
+ armor_protection_flags = CHEST|GROIN|ARMS
+ inv_hide_flags = NONE
/obj/item/clothing/suit/wizrobe/fake
name = "wizard robe"
@@ -117,7 +117,7 @@
desc = "Magic is all about the spell power, ZE!"
icon_state = "marisa"
item_state = "marisarobe"
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
siemens_coefficient = 1
diff --git a/code/modules/clothing/under/gimmick.dm b/code/modules/clothing/under/gimmick.dm
index 5260f7e1b712b..8bb9ed5bb9620 100644
--- a/code/modules/clothing/under/gimmick.dm
+++ b/code/modules/clothing/under/gimmick.dm
@@ -28,16 +28,16 @@
name = "combat pants"
desc = "The only thing a man needs when he's up agains the world."
icon_state = "rambo_suit"
- flags_armor_protection = LEGS|GROIN
- flags_cold_protection = LEGS|GROIN
- flags_heat_protection = LEGS|GROIN
+ armor_protection_flags = LEGS|GROIN
+ cold_protection_flags = LEGS|GROIN
+ heat_protection_flags = LEGS|GROIN
/obj/item/clothing/suit/gimmick/rambo
name = "pendant"
desc = "It's a precious stone and something of a talisman of protection."
- flags_armor_protection = CHEST
- flags_cold_protection = CHEST
- flags_heat_protection = CHEST
+ armor_protection_flags = CHEST
+ cold_protection_flags = CHEST
+ heat_protection_flags = CHEST
icon_state = "rambo_pendant"
//MCCLANE
@@ -45,26 +45,26 @@
name = "holiday attire"
desc = "The perfect outfit for a Christmas holiday with family. Shoes not included."
icon_state = "mcclane_suit"
- flags_armor_protection = CHEST|GROIN|LEGS
- flags_cold_protection = CHEST|GROIN|LEGS
- flags_heat_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
+ cold_protection_flags = CHEST|GROIN|LEGS
+ heat_protection_flags = CHEST|GROIN|LEGS
//DUTCH
/obj/item/clothing/under/gimmick/dutch
name = "combat fatigues"
desc = "Just another pair of military fatigues for a grueling tour in a jungle."
icon_state = "dutch_suit"
- flags_armor_protection = LEGS|GROIN
- flags_cold_protection = LEGS|GROIN
- flags_heat_protection = LEGS|GROIN
+ armor_protection_flags = LEGS|GROIN
+ cold_protection_flags = LEGS|GROIN
+ heat_protection_flags = LEGS|GROIN
/obj/item/clothing/suit/armor/gimmick/dutch
name = "armored jacket"
desc = "It's hot in the jungle. Sometimes it's hot and heavy, and sometimes it's hell on earth."
icon_state = "dutch_armor"
- flags_armor_protection = CHEST
- flags_cold_protection = CHEST
- flags_heat_protection = CHEST
+ armor_protection_flags = CHEST
+ cold_protection_flags = CHEST
+ heat_protection_flags = CHEST
soft_armor = list(MELEE = 45, BULLET = 45, LASER = 35, ENERGY = 25, BOMB = 25, BIO = 0, FIRE = 25, ACID = 25)
allowed = list(
/obj/item/weapon/gun,
@@ -85,20 +85,20 @@
name = "metal body"
desc = "It may be metallic, but it contains the heart and soul of Alex J. Murphy."
icon_state = "robocop_suit"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
/obj/item/clothing/shoes/gimmick/robocop
name = "polished metal boots"
desc = "The perfect size to stomp on the scum of Detroit."
icon_state = "robocop_shoes"
soft_armor = list(MELEE = 87, BULLET = 87, LASER = 87, ENERGY = 87, BOMB = 87, BIO = 50, FIRE = 87, ACID = 87)
- flags_inventory = CONDUCT|NOSLIPPING
+ inventory_flags = CONDUCT|NOSLIPPING
/obj/item/clothing/gloves/gimmick/robocop
name = "metal hands"
desc = "The cold, unfeeling hands of the law."
icon_state = "black"
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
soft_armor = list(MELEE = 87, BULLET = 87, LASER = 87, ENERGY = 87, BOMB = 87, BIO = 50, FIRE = 87, ACID = 87)
/obj/item/clothing/head/helmet/gimmick/robocop
@@ -107,8 +107,8 @@
icon_state = "robocop_helmet"
item_state = "robocop_helmet"
soft_armor = list(MELEE = 87, BULLET = 87, LASER = 87, ENERGY = 87, BOMB = 87, BIO = 50, FIRE = 87, ACID = 87)
- flags_inventory = COVEREYES|BLOCKSHARPOBJ
- flags_inv_hide = HIDEEARS|HIDEEYES|HIDETOPHAIR
+ inventory_flags = COVEREYES|BLOCKSHARPOBJ
+ inv_hide_flags = HIDEEARS|HIDEEYES|HIDETOPHAIR
anti_hug = 100
/obj/item/clothing/suit/armor/gimmick/robocop
@@ -117,11 +117,11 @@
icon_state = "robocop_armor"
item_state = "robocop_armor"
slowdown = 1
- flags_atom = CONDUCT
- flags_inventory = BLOCKSHARPOBJ
- flags_armor_protection = CHEST|GROIN|ARMS|LEGS
- flags_cold_protection = CHEST|GROIN|ARMS|LEGS
- flags_heat_protection = CHEST|GROIN|ARMS|LEGS
+ atom_flags = CONDUCT
+ inventory_flags = BLOCKSHARPOBJ
+ armor_protection_flags = CHEST|GROIN|ARMS|LEGS
+ cold_protection_flags = CHEST|GROIN|ARMS|LEGS
+ heat_protection_flags = CHEST|GROIN|ARMS|LEGS
allowed = list(/obj/item/weapon/gun/pistol/auto9)
soft_armor = list(MELEE = 87, BULLET = 87, LASER = 87, ENERGY = 87, BOMB = 87, BIO = 50, FIRE = 87, ACID = 87)
@@ -135,7 +135,7 @@
name = "black boots"
desc = "Perfectly functional, this pair of boots has stomped on many planets and starships."
icon_state = "skywalker_shoes"
- flags_inventory = NOSLIPPING
+ inventory_flags = NOSLIPPING
/obj/item/clothing/gloves/gimmick/skywalker
name = "black glove"
diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm
index cbe1456fd64b4..b7c832e4bb8a8 100644
--- a/code/modules/clothing/under/jobs/civilian.dm
+++ b/code/modules/clothing/under/jobs/civilian.dm
@@ -24,7 +24,7 @@
desc = "Shooooorts! They're comfy and easy to wear!"
icon_state = "cargotech"
item_state = "lb_suit"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/under/rank/chaplain
desc = "It's a black jumpsuit, often worn by religious folk."
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index 77f515a31dc99..0ab72e9d89afb 100644
--- a/code/modules/clothing/under/jobs/medsci.dm
+++ b/code/modules/clothing/under/jobs/medsci.dm
@@ -16,7 +16,7 @@
name = "research director dress uniform"
desc = "Feminine fashion for the style concious RD. Its fabric provides minor protection from biological contaminants."
icon_state = "dress_rd"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/under/rank/scientist
desc = "It's made of a special fiber that provides minor protection against small explosions. It has markings that denote the wearer as a scientist."
@@ -61,14 +61,14 @@
name = "nurse's suit"
icon_state = "nursesuit"
permeability_coefficient = 0.50
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/rank/nurse
desc = "A dress commonly worn by the nursing staff in the medical department."
name = "nurse's dress"
icon_state = "nurse"
permeability_coefficient = 0.50
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
adjustment_variants = list()
/obj/item/clothing/under/rank/orderly
diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm
index 31afc17a16e5d..9d527dd68dd3d 100644
--- a/code/modules/clothing/under/jobs/security.dm
+++ b/code/modules/clothing/under/jobs/security.dm
@@ -38,7 +38,7 @@
name = "dispatcher's uniform"
desc = "A dress shirt and khakis with a security patch sewn on."
icon_state = "dispatch"
- flags_armor_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
siemens_coefficient = 0.9
adjustment_variants = list()
diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm
index 5d12a98926b8a..d78f579e658b7 100644
--- a/code/modules/clothing/under/marine_uniform.dm
+++ b/code/modules/clothing/under/marine_uniform.dm
@@ -9,8 +9,8 @@
icon_state = "marine_jumpsuit"
item_icons = list(
slot_w_uniform_str = 'icons/mob/clothing/uniforms/marine_uniforms.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
has_sensor = 2
adjustment_variants = list(
@@ -19,6 +19,12 @@
"No Top" = "_r",
)
+/obj/item/clothing/under/marine/holster
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/holster)
+
+/obj/item/clothing/under/marine/corpman_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/white_vest)
+
/obj/item/clothing/under/marine/hyperscale
name = "\improper 8E Chameleon TGMC uniform"
desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented marine uniform BUT colorable with a facepaint! You suspect it's not as robust-proof as advertised."
@@ -32,6 +38,9 @@
/obj/item/clothing/under/marine/black_vest
starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+/obj/item/clothing/under/marine/brown_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/brown_vest)
+
//Squad colored turtlenecks
/obj/item/clothing/under/marine/squad/neck
name = "\improper TGMC Delta turtleneck"
@@ -98,7 +107,7 @@
icon_state = "marine_undersuit"
adjustment_variants = list()
has_sensor = 2
- flags_item_map_variant = null
+ item_map_variant_flags = null
/obj/item/clothing/under/marine/mp
name = "military police uniform"
@@ -115,6 +124,9 @@
"Down" = "_d",
)
+/obj/item/clothing/under/marine/orion_fatigue/black_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+
/obj/item/clothing/under/marine/red_fatigue
name = "\improper Big Red fatigues"
desc = "Originated from Big Red. Designed for dry, low humid, and Mars-eqse environments, they're meant for recon, stealth, and evac operations. They come with a built in cassette player hearable only to the user to help pass time, during any possible long waits. They make you feel like one with the desert, forged by the beating Sun. Rumors had it that it can recycle your sweat and urine for drinkable water!"
@@ -124,6 +136,9 @@
"Down" = "_d",
)
+/obj/item/clothing/under/marine/red_fatigue/black_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+
/obj/item/clothing/under/marine/lv_fatigue
name = "\improper LV-624 fatigues"
desc = "Originated from LV-624. Designed for wet, high humid, and jungle environments, they're meant for recon, stealth, and evac operations. They come with a built in cassette player hearable only to the user to help pass time, during any possible long waits. Somewhere, someone is playing 'Fortunate Sons' in the background, and you can smell napalm and Agent Orange in the air..."
@@ -133,12 +148,19 @@
"Down" = "_d",
)
+/obj/item/clothing/under/marine/lv_fatigue/black_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+
/obj/item/clothing/under/marine/striped
name = "\improper Striped fatigues"
desc = "A simple set of camo pants and a striped shirt."
icon_state = "marine_striped"
item_state = "marine_striped"
adjustment_variants = list()
+
+/obj/item/clothing/under/marine/striped/black_vest
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+
/obj/item/clothing/under/marine/black_suit
name = "\improper marine black suit"
desc = "A easy fitting black suit, somehow exactly your size."
@@ -174,7 +196,7 @@
name = "marine officer uniform"
desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented uniform worn by logistics officers of the TGMC. Do the corps proud."
icon_state = "BO_jumpsuit"
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
/obj/item/clothing/under/marine/officer/ro_suit
name = "requisition officer suit"
@@ -186,8 +208,8 @@
name = "pilot officer flightsuit"
desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented, survival-friendly pilot flightsuit. Fly the marines onwards to glory."
icon_state = "pilot_flightsuit"
- flags_cold_protection = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
- flags_item_map_variant = null
+ cold_protection_flags = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
+ item_map_variant_flags = null
adjustment_variants = list(
"Half" = "_h",
)
@@ -197,17 +219,27 @@
desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented uniform worn by mech pilots. Not as impressive as a titanium robot but good enough."
icon_state = "marine_mech_pilot"
+/obj/item/clothing/under/marine/officer/assault_crewman
+ name = "assault crewman uniform"
+ desc = "A standard-issue, carbon fibre uniform optimised for operating heavy equipment. Feels like a hand-me-down from last decade."
+ icon_state = "marine_assault_crewman"
+
+/obj/item/clothing/under/marine/officer/transport_crewman
+ name = "transport crewman uniform"
+ desc = "A standard issue comfortable uniform designed for sitting all day."
+ icon_state = "marine_transport_crewman"
+
/obj/item/clothing/under/marine/officer/bridge
name = "staff officer uniform"
desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented staff officer uniform. Do the navy proud."
icon_state = "BO_jumpsuit"
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
/obj/item/clothing/under/marine/officer/exec
name = "field commander uniform"
desc = "A special-issue, kevlar-weaved, hazmat-tested, EMF-augmented worn by a field-grade officer of the TGMC. You suspect it's not as robust-proof as advertised."
icon_state = "XO_jumpsuit"
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
/obj/item/clothing/under/marine/officer/exec/webbing
starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
@@ -216,7 +248,7 @@
name = "captain uniform"
desc = "A special-issue, well-ironed, kevlar-weaved, hazmat-tested, EMF-augmented uniform worth of a TerraGov Naval Captain. Even looking at it the wrong way could result in being court-martialed."
icon_state = "CO_jumpsuit"
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT)
/obj/item/clothing/under/marine/officer/admiral
name = "admiral uniform"
@@ -272,8 +304,8 @@
icon_state = "guardjumpsuit"
item_icons = list(
slot_w_uniform_str = 'icons/mob/clothing/uniforms/ert_uniforms.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
item_state = "guardjumpsuit"
soft_armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 10, BIO = 10, FIRE = 10, ACID = 10)
@@ -290,8 +322,8 @@
icon = 'icons/obj/clothing/uniforms/ert_uniforms.dmi'
item_icons = list(
slot_w_uniform_str = 'icons/mob/clothing/uniforms/ert_uniforms.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
adjustment_variants = list()
@@ -433,7 +465,7 @@
adjustment_variants = list()
/obj/item/clothing/under/som
- name = "\improper SOM officer uniform"
+ name = "\improper SOM uniform"
desc = "The standard uniform of SOM military personnel. Its design shows a clear lineage from mining uniforms used in the old mining colonies."
icon = 'icons/obj/clothing/uniforms/ert_uniforms.dmi'
icon_state = "som_uniform"
@@ -478,7 +510,7 @@
/obj/item/clothing/under/som/officer
name = "\improper SOM officer uniform"
- desc = "The distinct black uniform of a SOM officer. Usually worn by junior officers"
+ desc = "The distinct black uniform of a SOM officer. Usually worn by junior officers."
icon_state = "som_officer_uniform"
item_state = "som_officer_uniform"
adjustment_variants = list()
@@ -488,7 +520,7 @@
/obj/item/clothing/under/som/officer/senior
name = "\improper SOM officer uniform"
- desc = "The distinct jacketed black uniform of a SOM officer. Usually worn by senior officers"
+ desc = "The distinct jacketed black uniform of a SOM officer. Usually worn by senior officers."
icon_state = "som_senior_officer_uniform"
item_state = "som_senior_officer_uniform"
@@ -499,8 +531,8 @@
icon_state = "icc"
item_icons = list(
slot_w_uniform_str = 'icons/mob/clothing/uniforms/ert_uniforms.dmi',
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/items/items_left.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/items/items_right.dmi',
)
item_state = "icc"
has_sensor = FALSE
@@ -513,7 +545,7 @@
desc = "A field of invisible energy, it protects the wearer but prevents any clothing from being worn."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-blue"
- flags_item = DELONDROP
+ item_flags = DELONDROP
/obj/item/clothing/under/sectoid/Initialize(mapload)
. = ..()
@@ -535,3 +567,16 @@
/obj/item/clothing/under/marine/robotic/webbing
starting_attachments = list(/obj/item/armor_module/storage/uniform/black_vest)
+
+/obj/item/clothing/under/marine/specops
+ name = "Tactical turtleneck"
+ desc = "A TGMC turtleneck issued to special operation units"
+ icon = 'icons/mob/clothing/uniforms/ert_uniforms.dmi'
+ icon_state = "specops_uniform"
+ item_icons = list(
+ slot_w_uniform_str = 'icons/mob/clothing/uniforms/ert_uniforms.dmi',
+ )
+ starting_attachments = list(/obj/item/armor_module/storage/uniform/holster)
+ item_state = "specops_uniform"
+ min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE
+ has_sensor = 0
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 88a815e14a1ed..4d3b4564a0f1a 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -43,7 +43,7 @@
desc = "It makes you look HONKable!"
icon_state = "sexyclown"
item_state = "sexyclown"
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/rank/vice
name = "vice officer's jumpsuit"
@@ -87,8 +87,8 @@
w_class = WEIGHT_CLASS_BULKY//bulky item
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- flags_cold_protection = CHEST|GROIN|LEGS|ARMS //Needs gloves and shoes with cold protection to be fully protected.
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ cold_protection_flags = CHEST|GROIN|LEGS|ARMS //Needs gloves and shoes with cold protection to be fully protected.
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
/obj/item/clothing/under/acj
@@ -98,9 +98,9 @@
desc = "it's a cybernetically enhanced jumpsuit used for administrative duties."
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
soft_armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100)
- flags_cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ cold_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0
@@ -128,7 +128,7 @@
name = "dark undersuit"
desc = "A thick, layered grey undersuit lined with power cables. Feels a little like wearing an electrical storm."
icon_state = "psysuit"
- flags_armor_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ armor_protection_flags = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
/obj/item/clothing/under/gentlesuit
name = "Gentlemans Suit"
@@ -174,7 +174,7 @@
name = "pirate outfit"
desc = "Yarr."
icon_state = "pirate"
- flags_armor_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
/obj/item/clothing/under/soviet
name = "soviet uniform"
@@ -190,23 +190,23 @@
name = "kilt"
desc = "Includes shoes and plaid"
icon_state = "kilt"
- flags_armor_protection = CHEST|GROIN|FEET
+ armor_protection_flags = CHEST|GROIN|FEET
/obj/item/clothing/under/sexymime
name = "sexy mime outfit"
desc = "The only time when you DON'T enjoy looking at someone's rack."
icon_state = "sexymime"
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/gladiator
name = "gladiator uniform"
desc = "Are you not entertained? Is that not why you are here?"
icon_state = "gladiator"
- flags_armor_protection = GROIN
+ armor_protection_flags = GROIN
//dress
/obj/item/clothing/under/dress/
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/dress/dress_fire
name = "flame dress"
@@ -243,19 +243,19 @@
name = "captain's dress uniform"
desc = "Feminine fashion for the style concious captain."
icon_state = "dress_cap"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/under/dress/dress_hop
name = "head of personnel dress uniform"
desc = "Feminine fashion for the style concious HoP."
icon_state = "dress_hop"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/under/dress/dress_hr
name = "human resources director uniform"
desc = "Superior class for the nosy H.R. Director."
icon_state = "huresource"
- flags_armor_protection = CHEST|GROIN|ARMS
+ armor_protection_flags = CHEST|GROIN|ARMS
/obj/item/clothing/under/dress/plaid_blue
name = "blue plaid skirt"
@@ -274,44 +274,44 @@
//wedding stuff
/obj/item/clothing/under/wedding/
- flags_armor_protection = CHEST|GROIN|LEGS
+ armor_protection_flags = CHEST|GROIN|LEGS
/obj/item/clothing/under/wedding/bride_orange
name = "orange wedding dress"
desc = "A big and puffy orange dress."
icon_state = "bride_orange"
- flags_inv_hide = HIDESHOES
+ inv_hide_flags = HIDESHOES
/obj/item/clothing/under/wedding/bride_purple
name = "purple wedding dress"
desc = "A big and puffy purple dress."
icon_state = "bride_purple"
- flags_inv_hide = HIDESHOES
+ inv_hide_flags = HIDESHOES
/obj/item/clothing/under/wedding/bride_blue
name = "blue wedding dress"
desc = "A big and puffy blue dress."
icon_state = "bride_blue"
- flags_inv_hide = HIDESHOES
+ inv_hide_flags = HIDESHOES
/obj/item/clothing/under/wedding/bride_red
name = "red wedding dress"
desc = "A big and puffy red dress."
icon_state = "bride_red"
- flags_inv_hide = HIDESHOES
+ inv_hide_flags = HIDESHOES
/obj/item/clothing/under/wedding/bride_white
name = "silky wedding dress"
desc = "A white wedding gown made from the finest silk."
icon_state = "bride_white"
- flags_inv_hide = HIDESHOES
- flags_armor_protection = CHEST|GROIN
+ inv_hide_flags = HIDESHOES
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/sundress
name = "sundress"
desc = "Makes you want to frolic in a field of daisies."
icon_state = "sundress"
- flags_armor_protection = CHEST|GROIN
+ armor_protection_flags = CHEST|GROIN
/obj/item/clothing/under/captainformal
name = "captain's formal uniform"
@@ -373,9 +373,9 @@
icon_state = "pilot_spec"
item_state = "pilot_spec"
resistance_flags = UNACIDABLE
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
soft_armor = list(MELEE = 70, BULLET = 70, LASER = 70, ENERGY = 70, BOMB = 70, BIO = 70, FIRE = 70, ACID = 70)
- flags_cold_protection = CHEST|GROIN|LEGS|ARMS
+ cold_protection_flags = CHEST|GROIN|LEGS|ARMS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0
slowdown= -1
@@ -387,5 +387,5 @@
desc = "Praise the omnissiah!"
icon_state = "tp_bodyrobes"
item_state = "tp_bodyrobes"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm
index 0617b56f7c416..3161764d35e7c 100644
--- a/code/modules/clothing/under/shorts.dm
+++ b/code/modules/clothing/under/shorts.dm
@@ -2,7 +2,7 @@
name = "athletic shorts"
desc = "95% Polyester, 5% Spandex!"
gender = PLURAL
- flags_armor_protection = GROIN
+ armor_protection_flags = GROIN
/obj/item/clothing/under/shorts/red
name = "red athletic shorts"
diff --git a/code/modules/clothing/under/ties.dm b/code/modules/clothing/under/ties.dm
index b3a2d9118c007..5ed053b460ccd 100644
--- a/code/modules/clothing/under/ties.dm
+++ b/code/modules/clothing/under/ties.dm
@@ -3,12 +3,12 @@
desc = "A neosilk clip-on tie."
icon = 'icons/obj/clothing/ties.dmi'
icon_state = "bluetie"
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
w_class = WEIGHT_CLASS_SMALL
/obj/item/clothing/tie/Initialize(mapload)
. = ..()
- AddElement(/datum/element/attachment, ATTACHMENT_SLOT_UNIFORM_TIE, 'icons/obj/clothing/ties_overlay.dmi', flags_attach_features = (ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB), mob_overlay_icon = 'icons/mob/ties.dmi')
+ AddElement(/datum/element/attachment, ATTACHMENT_SLOT_UNIFORM_TIE, 'icons/obj/clothing/ties_overlay.dmi', attach_features_flags = (ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB), mob_overlay_icon = 'icons/mob/ties.dmi')
/obj/item/clothing/tie/blue
name = "blue tie"
@@ -161,13 +161,13 @@
name = "holobadge"
desc = "This glowing blue badge marks the holder as THE LAW."
icon_state = "holobadge"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
var/stored_name = null
/obj/item/clothing/tie/holobadge/cord
icon_state = "holobadge-cord"
- flags_equip_slot = ITEM_SLOT_MASK
+ equip_slot_flags = ITEM_SLOT_MASK
/obj/item/clothing/tie/holobadge/attack_self(mob/user as mob)
if(!stored_name)
@@ -178,6 +178,8 @@
/obj/item/clothing/tie/holobadge/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card/id))
var/obj/item/card/id/id_card = I
diff --git a/code/modules/clothing/under/under.dm b/code/modules/clothing/under/under.dm
index 36c8c3fc47d31..e81a0f541e092 100644
--- a/code/modules/clothing/under/under.dm
+++ b/code/modules/clothing/under/under.dm
@@ -6,11 +6,11 @@
slot_r_hand_str = 'icons/mob/inhands/clothing/uniforms_right.dmi',
)
name = "under"
- flags_armor_protection = CHEST|GROIN|LEGS|ARMS
- flags_cold_protection = CHEST|GROIN|LEGS|ARMS
- flags_heat_protection = CHEST|GROIN|LEGS|ARMS
+ armor_protection_flags = CHEST|GROIN|LEGS|ARMS
+ cold_protection_flags = CHEST|GROIN|LEGS|ARMS
+ heat_protection_flags = CHEST|GROIN|LEGS|ARMS
permeability_coefficient = 0.90
- flags_equip_slot = ITEM_SLOT_ICLOTHING
+ equip_slot_flags = ITEM_SLOT_ICLOTHING
soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
w_class = WEIGHT_CLASS_BULKY
blood_sprite_state = "uniformblood"
@@ -144,6 +144,23 @@
. += "Its vital tracker appears to be enabled."
if(3)
. += "Its vital tracker and tracking beacon appear to be enabled."
+ var/armor_info
+ var/obj/item/clothing/under/wear_modular_suit = src
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_UNIFORM])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_UNIFORM]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_BADGE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_BADGE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_UNIFORM_TIE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_UNIFORM_TIE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CAPE])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CAPE]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CAPE_HIGHLIGHT])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_CAPE_HIGHLIGHT]].\n"
+ if(wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_KAMA])
+ armor_info += " - [wear_modular_suit.attachments_by_slot[ATTACHMENT_SLOT_KAMA]].\n"
+ if(armor_info)
+ . += " It has the following attachments:"
+ . += armor_info
//we only want to quick equip from actual 'holster' type webbings
/obj/item/clothing/under/do_quick_equip(mob/user)
diff --git a/code/modules/codex/entries/ammunition_codex.dm b/code/modules/codex/entries/ammunition_codex.dm
index 5fcea85747341..bb5af652336fa 100644
--- a/code/modules/codex/entries/ammunition_codex.dm
+++ b/code/modules/codex/entries/ammunition_codex.dm
@@ -20,16 +20,16 @@
if(ammo.damage_type)
entry.mechanics_text += "Damage type: [ammo.damage_type] "
- if(ammo.flags_ammo_behavior & AMMO_INCENDIARY)
+ if(ammo.ammo_behavior_flags & AMMO_INCENDIARY)
entry.mechanics_text += "Secondary effect: set target on fire. "
- if(ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
- entry.mechanics_text += "Secondary effect: explosion. "
+ if(ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
+ entry.mechanics_text += "Secondary effect: Hits the turf clicked on. "
- if(ammo.flags_ammo_behavior & AMMO_SPECIAL_PROCESS)
+ if(ammo.ammo_behavior_flags & AMMO_SPECIAL_PROCESS)
entry.mechanics_text += "Secondary effect: hits nearby targets in-flight. "
- if(ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
+ if(ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
entry.mechanics_text += "Secondary effect: affects tiles travelled through. "
if(ammo.penetration)
diff --git a/code/modules/codex/entries/clothing_codex.dm b/code/modules/codex/entries/clothing_codex.dm
index 1ac214c36f997..aff9924b86990 100644
--- a/code/modules/codex/entries/clothing_codex.dm
+++ b/code/modules/codex/entries/clothing_codex.dm
@@ -74,10 +74,10 @@ GLOBAL_LIST_INIT(string_equip_flags, list("suit slot" = ITEM_SLOT_OCLOTHING,
if(accuracy_mod)
armor_strings += " This will alter your shooting accuracy by up to [accuracy_mod]% when worn."
- if(flags_inventory & NOPRESSUREDMAGE)
+ if(inventory_flags & NOPRESSUREDMAGE)
armor_strings += "Wearing this will protect you from the vacuum of space."
- if(flags_inventory & BLOCKSHARPOBJ)
+ if(inventory_flags & BLOCKSHARPOBJ)
armor_strings += "The material is exceptionally thick."
if(max_heat_protection_temperature >= FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE)
@@ -91,10 +91,10 @@ GLOBAL_LIST_INIT(string_equip_flags, list("suit slot" = ITEM_SLOT_OCLOTHING,
var/list/covers = list()
var/list/slots = list()
for(var/name in GLOB.string_part_flags)
- if(flags_armor_protection & GLOB.string_part_flags[name])
+ if(armor_protection_flags & GLOB.string_part_flags[name])
covers += name
for(var/name in GLOB.string_equip_flags)
- if(flags_equip_slot & GLOB.string_equip_flags[name])
+ if(equip_slot_flags & GLOB.string_equip_flags[name])
slots += name
if(length(covers))
diff --git a/code/modules/codex/entries/guns_codex.dm b/code/modules/codex/entries/guns_codex.dm
index 48e352e6f530d..f66367a631154 100644
--- a/code/modules/codex/entries/guns_codex.dm
+++ b/code/modules/codex/entries/guns_codex.dm
@@ -14,7 +14,25 @@
. = ..()
var/list/traits = list()
- if(flags_gun_features & GUN_WIELDED_FIRING_ONLY)
+ var/skill_name
+ switch(gun_skill_category)
+ if(SKILL_RIFLES)
+ skill_name = "rifle skill"
+ if(SKILL_SMGS)
+ skill_name = "SMG skill"
+ if(SKILL_HEAVY_WEAPONS)
+ skill_name = "heavy weapon skill"
+ if(SKILL_SMARTGUN)
+ skill_name = "smartgun skill"
+ if(SKILL_SHOTGUNS)
+ skill_name = "shotgun skill"
+ if(SKILL_PISTOLS)
+ skill_name = "pistol skill"
+
+ if(skill_name)
+ traits += "This weapons is effected by the user's [skill_name] rating. "
+
+ if(gun_features_flags & GUN_WIELDED_FIRING_ONLY)
traits += "This can only be fired with a two-handed grip."
else
traits += "It's best fired with a two-handed grip."
@@ -146,6 +164,16 @@
traditional chargers and their capability to switch their lens, allowing more flexibility, something that a ballistic weapon \
aren't capable of."
+/datum/codex_entry/plasma_weapons
+ display_name = "plasma weapons"
+ mechanics_text = "This weapon is a plasma weapon; it fires bursts of superheated gas that have been ionized and electrically charged. You can \
+ unload it by holding it and clicking it with an empty hand, and reload it by clicking it with a power cell or a plasma cartridge, depending on the model of \
+ the weapon. \
+ "
+ lore_text = "Plasma weapons are rare and powerful due to the high cost and difficulty of producing and controlling plasma \
+ pulses. They have a devastating effect on most targets, as the plasma can melt, burn, or vaporize them. Using a plasma weapon in a confined space is very risky, \
+ as the plasma can damage the surroundings or harm friendly units with its intense heat and radiation."
+
/datum/codex_entry/ballistic_weapons
display_name = "ballistic weapons"
mechanics_text = "This weapon is a ballistic weapon; it fires solid shots using a magazine or loaded rounds of ammunition. You can \
@@ -185,16 +213,16 @@
/datum/codex_entry/sniper_rifle
associated_paths = list(/obj/item/weapon/gun/rifle/sniper/antimaterial)
lore_text = "A rather strange gun in the TGMC's arsenal. The M42A \"Express\" originally was born out of it's younger brother the M42. Made by the same \
- company who eventually went on to design the M56 smartgun system. Which the M42As specialized scope eventually adopted a modified IFF system similar to it's cousin the smartgun.
\
+ company who eventually went on to design the HSG-102 smartgun system. Which the M42As specialized scope eventually adopted a modified IFF system similar to it's cousin the smartgun.
\
It was at first marketed to PMCs and civilians as an expensive accurate long range rifle but it failed due to the lack of need for such a thing for PMCs and the wide variety of options \
- already available for civilians in a more affordable package. The company after the failure went onto design the M56 smartgun and succeeded there however. Which kept them afloat after the failure of the M42.
\
+ already available for civilians in a more affordable package. The company after the failure went onto design the HS-102 smartgun and succeeded there however. Which kept them afloat after the failure of the M42.
\
Later however an announcement by the Marine Corps who decided to replace the aging supply of the current adopted Sniper Rifle after complaints that the frames were starting to wear out due to long-term use and thus trials would be announced to replace them.
\
Eventually, the board of directors decided to give that reviving the M42 design was a worthwhile possibility. And thus the design was decided to be modernized and equipped with an IFF-capable scope, after that it was named as the M42A and submitted to go the trials.
\
Though high unit cost didn't allow it to be more widely adopted it was eventually decided that it would meet limited adoption for Marksmen and be designated the SR-26."
/datum/codex_entry/battle_rifle
associated_paths = list(/obj/item/weapon/gun/rifle/tx8)
- lore_text = "The M45A was born from a commission order from the TGMC to the company which made the M42A and M56 smartgun systems.
\
+ lore_text = "The M45A was born from a commission order from the TGMC to the company which made the M42A and HS-102 smartgun systems.
\
The reason for this commission order resulted from complaints from light infantry and scout units about the poor accuracy of the new SR-26 \
carbine at longer ranges and the large size of the SG-29 making close combat uncomfortable eventually reached the higher ups, who kept getting \
the same complaints over and over. So they eventually reached out to a trusted company to do it.
\
diff --git a/code/modules/codex/entries/magazine_codex.dm b/code/modules/codex/entries/magazine_codex.dm
index 0d44f7803f7a6..bd7aac50a3f20 100644
--- a/code/modules/codex/entries/magazine_codex.dm
+++ b/code/modules/codex/entries/magazine_codex.dm
@@ -26,7 +26,7 @@
if(wield_delay_mod)
traits += "Wield delay modifier: [wield_delay_mod] seconds "
- if(flags_magazine & MAGAZINE_WORN)
+ if(magazine_flags & MAGAZINE_WORN)
traits += "This magazine is worn instead of inserted into a gun. "
traits += "Basic statistics for ammunition in this magazine are as follows: "
@@ -56,16 +56,16 @@
if(default_ammo.max_range)
traits += "Maximum range: [default_ammo.max_range] "
- if(default_ammo.flags_ammo_behavior & AMMO_INCENDIARY)
+ if(default_ammo.ammo_behavior_flags & AMMO_INCENDIARY)
traits += "Secondary effect: Set target on fire "
- if(default_ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
- traits += "Secondary effect: Explosive "
+ if(default_ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
+ traits += "Secondary effect: Targets turfs "
- if(default_ammo.flags_ammo_behavior & AMMO_SPECIAL_PROCESS)
+ if(default_ammo.ammo_behavior_flags & AMMO_SPECIAL_PROCESS)
traits += "Secondary effect: Hits nearby targets in-flight "
- if(default_ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
+ if(default_ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
traits += "Secondary effect: Affects tiles travelled through "
if(default_ammo.accuracy)
diff --git a/code/modules/codex/entries/misc_codex.dm b/code/modules/codex/entries/misc_codex.dm
index baf907f71f102..36a6c41bb01ed 100644
--- a/code/modules/codex/entries/misc_codex.dm
+++ b/code/modules/codex/entries/misc_codex.dm
@@ -20,7 +20,7 @@
var/list/slots = list()
for(var/name in GLOB.string_equip_flags)
- if(flags_equip_slot & GLOB.string_equip_flags[name])
+ if(equip_slot_flags & GLOB.string_equip_flags[name])
slots += name
if(length(slots))
diff --git a/code/modules/codex/entries/mobs_codex.dm b/code/modules/codex/entries/mobs_codex.dm
index f2ad6de3157f2..32e35ba65ee7a 100644
--- a/code/modules/codex/entries/mobs_codex.dm
+++ b/code/modules/codex/entries/mobs_codex.dm
@@ -40,7 +40,7 @@
if(xeno_caste.caste_flags & CASTE_EVOLUTION_ALLOWED)
xeno_strings += " This can evolve to:"
- for(var/type in xeno_caste.evolves_to)
+ for(var/type in get_evolution_options())
xeno_strings += "[GLOB.xeno_caste_datums[type][XENO_UPGRADE_BASETYPE].caste_name]"
if(length(actions))
diff --git a/code/modules/codex/entries/stacks_codex.dm b/code/modules/codex/entries/stacks_codex.dm
index 55d271c6437fc..d9532c90b3551 100644
--- a/code/modules/codex/entries/stacks_codex.dm
+++ b/code/modules/codex/entries/stacks_codex.dm
@@ -5,7 +5,7 @@
Clicking on a floor without any tiles will reinforce the floor. You can make reinforced glass by combining rods and normal glass sheets."
/datum/codex_entry/glass
- associated_paths = list(/obj/item/stack/sheet/glass)
+ associated_paths = list(/obj/item/stack/sheet/glass/glass)
mechanics_text = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets."
/datum/codex_entry/glass_reinf
diff --git a/code/modules/codex/entries/weapons_codex.dm b/code/modules/codex/entries/weapons_codex.dm
index 6f84521cc4c5d..55d51ee3e131b 100644
--- a/code/modules/codex/entries/weapons_codex.dm
+++ b/code/modules/codex/entries/weapons_codex.dm
@@ -28,10 +28,10 @@
if(slot == ATTACHMENT_SLOT_UNDER)
attach_strings += "This attaches to the underbarrel slot on most weapons. "
- if(flags_attach_features & ATTACH_REMOVABLE)
+ if(attach_features_flags & ATTACH_REMOVABLE)
attach_strings += "This can be field stripped off the weapon if needed."
- if(flags_attach_features & ATTACH_ACTIVATION)
+ if(attach_features_flags & ATTACH_ACTIVATION)
attach_strings += "This needs to be activated to be used."
attach_strings += " Always on modifications: "
diff --git a/code/modules/condor/cas_chair.dm b/code/modules/condor/cas_chair.dm
index c33aadcc24e11..0e56de61fe3e7 100644
--- a/code/modules/condor/cas_chair.dm
+++ b/code/modules/condor/cas_chair.dm
@@ -144,15 +144,15 @@
occupant.forceMove(get_step(loc, WEST))
occupant = null
-/obj/structure/caspart/caschair/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/structure/caspart/caschair/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!occupant)
- to_chat(X, span_xenowarning("There is nothing of interest in there."))
+ to_chat(xeno_attacker, span_xenowarning("There is nothing of interest in there."))
return
- if(X.status_flags & INCORPOREAL || X.do_actions)
+ if(xeno_attacker.status_flags & INCORPOREAL || xeno_attacker.do_actions)
return
- visible_message(span_warning("[X] begins to pry the [src]'s cover!"), 3)
+ visible_message(span_warning("[xeno_attacker] begins to pry the [src]'s cover!"), 3)
playsound(src,'sound/effects/metal_creaking.ogg', 25, 1)
- if(!do_after(X, 2 SECONDS))
+ if(!do_after(xeno_attacker, 2 SECONDS))
return
playsound(loc, 'sound/effects/metal_creaking.ogg', 25, 1)
eject_user(TRUE)
@@ -204,12 +204,12 @@
switch(action)
if("launch")
if(!cas_usable)
- to_chat(usr, "Combat has not yet initiated, CAS unavailable.")
+ to_chat(usr, span_warning("Combat has not yet initiated, CAS unavailable."))
return
if(owner.state == PLANE_STATE_FLYING || owner.mode != SHUTTLE_IDLE)
return
- if(owner.fuel_left <= LOW_FUEL_THRESHOLD)
- to_chat(usr, "Unable to launch, low fuel.")
+ if(owner.fuel_left <= LOW_FUEL_TAKEOFF_THRESHOLD)
+ to_chat(usr, span_warning("Unable to launch, low fuel."))
return
SSshuttle.moveShuttleToDock(owner.id, SSshuttle.generate_transit_dock(owner), TRUE)
owner.currently_returning = FALSE
diff --git a/code/modules/condor/cas_shuttle.dm b/code/modules/condor/cas_shuttle.dm
index a8a799d61b2d9..a0e49ed127bd6 100644
--- a/code/modules/condor/cas_shuttle.dm
+++ b/code/modules/condor/cas_shuttle.dm
@@ -57,8 +57,11 @@
/obj/docking_port/mobile/marine_dropship/casplane/process()
#ifndef TESTING
fuel_left--
+ if((fuel_max*LOW_FUEL_WARNING_THRESHOLD) == fuel_left)
+ chair.occupant?.playsound_local(loc, 'sound/voice/plane_vws/low_fuel.ogg', 70, FALSE)
if((fuel_left <= LOW_FUEL_LANDING_THRESHOLD) && (state == PLANE_STATE_FLYING))
to_chat(chair.occupant, span_warning("Out of fuel, landing."))
+ chair.occupant?.playsound_local(loc, 'sound/voice/plane_vws/no_fuel.ogg', 70, FALSE)
SSshuttle.moveShuttle(id, SHUTTLE_CAS_DOCK, TRUE)
currently_returning = TRUE
end_cas_mission(chair.occupant)
@@ -194,6 +197,7 @@
#endif
to_chat(user, span_warning("Targets detected, routing to area of operations."))
+ user.playsound_local(chair, 'sound/voice/plane_vws/flightcomputer_hot.ogg', 70, FALSE)
give_eye_control(user)
eyeobj.setLoc(get_turf(starting_point))
@@ -261,7 +265,7 @@
if(A.ceiling >= CEILING_UNDERGROUND)
to_chat(source, span_warning("That target is too deep underground!"))
return
- if(A.flags_area & OB_CAS_IMMUNE)
+ if(A.area_flags & OB_CAS_IMMUNE)
to_chat(source, span_warning("Our payload won't reach this target!"))
return
if(active_weapon.ammo_equipped?.ammo_count <= 0)
diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm
index 172c26ebfc24a..0eedb5d5ebafc 100644
--- a/code/modules/detectivework/footprints_and_rag.dm
+++ b/code/modules/detectivework/footprints_and_rag.dm
@@ -17,7 +17,7 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 5
- flags_item = NOBLUDGEON
+ item_flags = NOBLUDGEON
/obj/item/reagent_containers/glass/rag/attack_self(mob/user as mob)
return
diff --git a/code/modules/detectivework/forensics.dm b/code/modules/detectivework/forensics.dm
index a2a05eeeb6915..82ae7324e20b9 100644
--- a/code/modules/detectivework/forensics.dm
+++ b/code/modules/detectivework/forensics.dm
@@ -24,14 +24,14 @@
fibertext = "Material from \a [M.wear_suit]."
if(prob(10*item_multiplier) && !(fibertext in suit_fibers))
suit_fibers += fibertext
- suit_coverage = M.wear_suit.flags_armor_protection
+ suit_coverage = M.wear_suit.armor_protection_flags
- if(M.w_uniform && (M.w_uniform.flags_armor_protection & ~suit_coverage))
+ if(M.w_uniform && (M.w_uniform.armor_protection_flags & ~suit_coverage))
fibertext = "Fibers from \a [M.w_uniform]."
if(prob(15*item_multiplier) && !(fibertext in suit_fibers))
suit_fibers += fibertext
- if(M.gloves && (M.gloves.flags_armor_protection & ~suit_coverage))
+ if(M.gloves && (M.gloves.armor_protection_flags & ~suit_coverage))
fibertext = "Material from a pair of [M.gloves.name]."
if(prob(20*item_multiplier) && !(fibertext in suit_fibers))
suit_fibers += "Material from a pair of [M.gloves.name]."
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index f8ded08499344..09b3a47fcdb48 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -10,9 +10,9 @@
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
)
item_state = "electronic"
- flags_atom = CONDUCT
- flags_item = NOBLUDGEON
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ item_flags = NOBLUDGEON
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
to_chat(user, span_warning("This device is non-functional."))
diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm
index 5ebc598dc5a7f..06d7c058e2eb7 100644
--- a/code/modules/economy/ATM.dm
+++ b/code/modules/economy/ATM.dm
@@ -65,6 +65,8 @@ log transactions
/obj/machinery/atm/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card))
var/obj/item/card/id/idcard = I
diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm
index 1da5cd8857d4f..0706983d80db9 100644
--- a/code/modules/economy/EFTPOS.dm
+++ b/code/modules/economy/EFTPOS.dm
@@ -117,6 +117,8 @@
/obj/item/eftpos/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/card))
var/obj/item/card/C = I
diff --git a/code/modules/economy/cash.dm b/code/modules/economy/cash.dm
index 186f6404acbc8..50af2fd224207 100644
--- a/code/modules/economy/cash.dm
+++ b/code/modules/economy/cash.dm
@@ -18,6 +18,8 @@
/obj/item/spacecash/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/spacecash) && !istype(I, /obj/item/spacecash/ewallet))
var/obj/item/spacecash/bundle/bundle
@@ -45,8 +47,12 @@
desc = "They are worth 0 dollars."
worth = 0
-/obj/item/spacecash/bundle/update_icon()
- overlays.Cut()
+/obj/item/spacecash/bundle/update_desc(updates)
+ . = ..()
+ desc = "They are worth [worth] dollars."
+
+/obj/item/spacecash/bundle/update_overlays()
+ . = ..()
var/sum = worth
var/num = 0
for(var/i in list(1000,500,200,100,50,20,10,1))
@@ -58,15 +64,14 @@
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
- overlays += banknote
+ . += banknote
if(num == 0) // Less than one thaler, let's just make it look like 1 for ease
var/image/banknote = image('icons/obj/stack_objects.dmi', "spacecash1")
var/matrix/M = matrix()
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
- overlays += banknote
- desc = "They are worth [worth] dollars."
+ . += banknote
/obj/item/spacecash/bundle/attack_self(mob/user)
var/oldloc = loc
@@ -76,7 +81,7 @@
if(gc_destroyed || loc != oldloc) return
src.worth -= amount
- src.update_icon()
+ src.update_appearance()
if(!worth)
usr.temporarilyRemoveItemFromInventory(src)
if(amount in list(1000,500,200,100,50,20,1))
@@ -86,7 +91,7 @@
else
var/obj/item/spacecash/bundle/bundle = new (usr.loc)
bundle.worth = amount
- bundle.update_icon()
+ bundle.update_appearance()
user.put_in_hands(bundle)
if(!worth)
qdel(src)
@@ -143,7 +148,7 @@
return
var/obj/item/spacecash/bundle/bundle = new (spawnloc)
bundle.worth = sum
- bundle.update_icon()
+ bundle.update_appearance()
if (ishuman(human_user) && !human_user.get_active_held_item())
human_user.put_in_hands(bundle)
diff --git a/code/modules/events/intel_computer.dm b/code/modules/events/intel_computer.dm
index a8a58cd29135d..8a2a0a34f0c60 100644
--- a/code/modules/events/intel_computer.dm
+++ b/code/modules/events/intel_computer.dm
@@ -20,6 +20,6 @@
/datum/round_event/intel_computer/proc/activate(obj/machinery/computer/intel_computer/I)
I.active = TRUE
- SSminimaps.add_marker(I, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "intel", ABOVE_FLOAT_LAYER))
- priority_announce("Our data sifting algorithm has detected valuable classified information on a access point in [get_area(I)]. Should this data be recovered by ground forces, a reward will be given in the form of increased assets.", title = "TGMC Intel Division")
+ SSminimaps.add_marker(I, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "intel", ABOVE_FLOAT_LAYER)) //RUTGMC EDIT
+ minor_announce("Our data sifting algorithm has detected valuable classified information on a access point in [get_area(I)]. Should this data be recovered by ground forces, a reward will be given in the form of increased assets.", title = "TGMC Intel Division")
xeno_message("We sense a looming threat from [get_area(I)]. We must keep the hosts away from there.")
diff --git a/code/modules/factory/howtopaper.dm b/code/modules/factory/howtopaper.dm
index 36e56666bb0a8..fcd1ff0f0128a 100644
--- a/code/modules/factory/howtopaper.dm
+++ b/code/modules/factory/howtopaper.dm
@@ -10,15 +10,15 @@
Machines will always output in the direction they are facing and input from the opposite direction.
RECIPES:
- WP GRENADE:
- UNBOXER -> CUTTER -> HEATER -> FORMER
-
- M15 GRENADE:
- UNBOXER -> CUTTER -> FORMER
+ ALL GRENADES:
+ UNBOXER -> CUTTER -> HEATER -> FORMER -> COMPRESSOR
PIZZA:
UNBOXER -> CUTTER -> HEATER
+ ALL C4 PLASTIQUES AND DETPACKS:
+ UNBOXER -> CUTTER -> FLATTER
+
ALL SADAR AMMO TYPES:
UNBOXER -> CUTTER -> HEATER -> FLATTER -> ATOMIC RECONSTRUCTOR
The words of the shrike reverberate in your head...
[span_alert(input)]
"))
//Display the ruler's hive message at the top of the game screen.
X.play_screen_text(queens_word, /atom/movable/screen/text/screen_text/queen_order)
@@ -76,38 +76,42 @@
return ..()
/datum/action/ability/activable/xeno/screech/use_ability(atom/A)
- var/mob/living/carbon/xenomorph/queen/X = owner
+ var/mob/living/carbon/xenomorph/queen/xeno_owner = owner
//screech is so powerful it kills huggers in our hands
- if(istype(X.r_hand, /obj/item/clothing/mask/facehugger))
- var/obj/item/clothing/mask/facehugger/FH = X.r_hand
+ if(istype(xeno_owner.r_hand, /obj/item/clothing/mask/facehugger))
+ var/obj/item/clothing/mask/facehugger/FH = xeno_owner.r_hand
if(FH.stat != DEAD)
FH.kill_hugger()
- if(istype(X.l_hand, /obj/item/clothing/mask/facehugger))
- var/obj/item/clothing/mask/facehugger/FH = X.l_hand
+ if(istype(xeno_owner.l_hand, /obj/item/clothing/mask/facehugger))
+ var/obj/item/clothing/mask/facehugger/FH = xeno_owner.l_hand
if(FH.stat != DEAD)
FH.kill_hugger()
succeed_activate()
add_cooldown()
- playsound(X.loc, 'sound/voice/alien_queen_screech.ogg', 75, 0)
- X.visible_message(span_xenohighdanger("\The [X] emits an ear-splitting guttural roar!"))
+ playsound(xeno_owner.loc, 'sound/voice/alien_queen_screech.ogg', 75, 0)
+ xeno_owner.visible_message(span_xenohighdanger("\The [xeno_owner] emits an ear-splitting guttural roar!"))
GLOB.round_statistics.queen_screech++
SSblackbox.record_feedback("tally", "round_statistics", 1, "queen_screech")
- X.create_shriekwave() //Adds the visual effect. Wom wom wom
- //stop_momentum(charge_dir) //Screech kills a charge
-
- var/list/nearby_living = list()
- for(var/mob/living/L in hearers(WORLD_VIEW, X))
- nearby_living.Add(L)
+ xeno_owner.create_shriekwave() //Adds the visual effect. Wom wom wom
- for(var/i in GLOB.mob_living_list)
- var/mob/living/L = i
- if(get_dist(L, X) > WORLD_VIEW_NUM)
+ for(var/obj/vehicle/sealed/armored/tank AS in GLOB.tank_list)
+ if(get_dist(tank, xeno_owner) > WORLD_VIEW_NUM)
+ continue
+ if(tank.z != owner.z)
continue
- L.screech_act(X, WORLD_VIEW_NUM, L in nearby_living)
+ for(var/mob/living/living_victim AS in tank.occupants)
+ living_victim.screech_act(xeno_owner, WORLD_VIEW_NUM) //todo: The effects of screech are weird due to relying on get_dist for a mob on a diff z-level
+
+ var/list/nearby_living = list() //if you're a hearer you get effected more severely
+ for(var/mob/living/living_victim in hearers(WORLD_VIEW, xeno_owner))
+ nearby_living.Add(living_victim)
+
+ for(var/mob/living/living_victim AS in cheap_get_living_near(xeno_owner, WORLD_VIEW_NUM))
+ living_victim.screech_act(xeno_owner, WORLD_VIEW_NUM, living_victim in nearby_living)
/datum/action/ability/activable/xeno/screech/ai_should_start_consider()
return TRUE
@@ -230,10 +234,10 @@
var/mob/living/carbon/xenomorph/queen/xeno = owner
if(xeno.do_actions)
return
- if(xeno.is_zoomed)
+ if(xeno.xeno_flags & XENO_ZOOMED)
zoom_xeno_out(xeno.observed_xeno ? FALSE : TRUE)
return
- if(!do_after(xeno, 1 SECONDS, IGNORE_HELD_ITEM, null, BUSY_ICON_GENERIC) || xeno.is_zoomed)
+ if(!do_after(xeno, 1 SECONDS, IGNORE_HELD_ITEM, null, BUSY_ICON_GENERIC) || (xeno.xeno_flags & XENO_ZOOMED))
return
zoom_xeno_in(xeno.observed_xeno ? FALSE : TRUE) //No need for feedback message if our eye is elsewhere.
@@ -292,7 +296,7 @@
/datum/action/ability/xeno_action/set_xeno_lead/proc/select_xeno_leader(mob/living/carbon/xenomorph/selected_xeno)
var/mob/living/carbon/xenomorph/queen/xeno_ruler = owner
- if(selected_xeno.queen_chosen_lead)
+ if(selected_xeno.xeno_flags & XENO_LEADER)
unset_xeno_leader(selected_xeno)
return
@@ -448,7 +452,7 @@
/datum/action/ability/xeno_action/bulwark
name = "Royal Bulwark"
action_icon_state = "bulwark"
- desc = "Creates a field of defensive energy, filling chinks in the armor of nearby sisters, making them more resilient."
+ desc = "Creates a field of defensive energy, filling gaps in the armor of nearby sisters, making them more resilient."
ability_cost = 100
cooldown_duration = 20 SECONDS
keybinding_signals = list(
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/queen/castedatum_queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/queen/castedatum_queen.dm
index e1fcb83e09373..2143f888ae9ed 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/queen/castedatum_queen.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/queen/castedatum_queen.dm
@@ -23,6 +23,9 @@
// *** Health *** //
max_health = 500
+ // *** Sunder *** //
+ sunder_multiplier = 0.8
+
// *** Evolution *** //
//upgrade_threshold = TIER_THREE_THRESHOLD // RUTGMC DELETION
evolve_min_xenos = 8
@@ -56,6 +59,7 @@
/datum/action/ability/activable/xeno/cocoon,
/datum/action/ability/activable/xeno/plant_weeds,
/datum/action/ability/activable/xeno/secrete_resin,
+ /datum/action/ability/activable/xeno/secrete_special_resin,
/datum/action/ability/xeno_action/blessing_menu,
/datum/action/ability/xeno_action/place_acidwell,
/datum/action/ability/xeno_action/lay_egg,
@@ -95,6 +99,7 @@
/datum/action/ability/activable/xeno/cocoon,
/datum/action/ability/activable/xeno/plant_weeds,
/datum/action/ability/activable/xeno/secrete_resin,
+ /datum/action/ability/activable/xeno/secrete_special_resin,
/datum/action/ability/xeno_action/blessing_menu,
/datum/action/ability/xeno_action/place_acidwell,
/datum/action/ability/xeno_action/lay_egg,
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/queen/queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/queen/queen.dm
index 340acfb0a0d2b..c3a1ea78f0b2e 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/queen/queen.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/queen/queen.dm
@@ -76,17 +76,17 @@
var/prefix = (hive.prefix || xeno_caste.upgrade_name) ? "[hive.prefix][xeno_caste.upgrade_name] " : ""
switch(playtime_mins)
if(0 to 600)
- name = prefix + "Hatchling Queen ([nicknumber])"
- if(601 to 1500)
name = prefix + "Young Queen ([nicknumber])"
+ if(601 to 1500)
+ name = prefix + "Mature Queen ([nicknumber])"
if(1501 to 4200)
- name = prefix + "Mature Empress ([nicknumber])"
- if(4201 to 10500)
name = prefix + "Elder Empress ([nicknumber])"
- if(10501 to INFINITY)
+ if(4201 to 10500)
name = prefix + "Ancient Empress ([nicknumber])"
+ if(10501 to INFINITY)
+ name = prefix + "Prime Empress ([nicknumber])"
else
- name = prefix + "Hatchling Queen ([nicknumber])"
+ name = prefix + "Young Queen ([nicknumber])"
real_name = name
if(mind)
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/ravager/abilities_ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/ravager/abilities_ravager.dm
index aac732b46d432..440f0e78aa2a6 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/ravager/abilities_ravager.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/ravager/abilities_ravager.dm
@@ -122,7 +122,7 @@
atoms_to_ravage += get_step(owner, turn(owner.dir, -45)).contents
atoms_to_ravage += get_step(owner, turn(owner.dir, 45)).contents
for(var/atom/movable/ravaged AS in atoms_to_ravage)
- if(!(ravaged.resistance_flags & XENO_DAMAGEABLE))
+ if(!(ravaged.resistance_flags & XENO_DAMAGEABLE) || !X.Adjacent(ravaged))
continue
if(!ishuman(ravaged))
ravaged.attack_alien(X, X.xeno_caste.melee_damage)
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/ravager/castedatum_ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/ravager/castedatum_ravager.dm
index 0bd20765a77b5..17043f7597a05 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/ravager/castedatum_ravager.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/ravager/castedatum_ravager.dm
@@ -9,7 +9,8 @@
wound_type = "ravager" //used to match appropriate wound overlays
// *** Melee Attacks *** //
- melee_damage = 30
+ melee_damage = 25
+ melee_ap = 15
attack_delay = 7
// *** Speed *** //
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm
index 82154957c04a4..c2b5ab3a9c33b 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm
@@ -77,7 +77,8 @@
/datum/action/ability/xeno_action/evasion
name = "Evasion"
action_icon_state = "evasion_on"
- desc = "Take evasive action, forcing non-friendly projectiles that would hit you to miss for a short duration so long as you keep moving. Alternate use toggles Auto Evasion off or on."
+ desc = "Take evasive action, forcing non-friendly projectiles that would hit you to miss for a short duration so long as you keep moving. \
+ Alternate use toggles Auto Evasion off or on. Click again while active to deactivate early."
ability_cost = 75
cooldown_duration = 10 SECONDS
keybinding_signals = list(
@@ -113,6 +114,15 @@
update_button_icon()
/datum/action/ability/xeno_action/evasion/action_activate()
+ //Since both the button and the evasion extension call this proc directly, check if the cooldown timer exists
+ //The evasion extension removes the cooldown before calling this proc again, so use that to differentiate if it was the player trying to cancel
+ if(evade_active && cooldown_timer)
+ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_EVASION_ACTIVATION))
+ return
+ evasion_deactivate()
+ return
+
+ use_state_flags = ABILITY_IGNORE_COOLDOWN|ABILITY_IGNORE_PLASMA //To allow the ability button to be clicked while on cooldown for deactivation purposes
succeed_activate()
add_cooldown()
if(evade_active)
@@ -137,6 +147,7 @@
RegisterSignal(owner, COMSIG_LIVING_PRE_THROW_IMPACT, PROC_REF(evasion_throw_dodge))
GLOB.round_statistics.runner_evasions++
SSblackbox.record_feedback("tally", "round_statistics", 1, "runner_evasions")
+ TIMER_COOLDOWN_START(src, COOLDOWN_EVASION_ACTIVATION, 1 SECONDS)
/datum/action/ability/xeno_action/evasion/process()
var/mob/living/carbon/xenomorph/runner/runner_owner = owner
@@ -152,7 +163,7 @@
*/
/datum/action/ability/xeno_action/evasion/proc/evasion_flamer_hit(datum/source, obj/projectile/proj)
SIGNAL_HANDLER
- if(!(proj.ammo.flags_ammo_behavior & AMMO_FLAME))
+ if(!(proj.ammo.ammo_behavior_flags & AMMO_FLAME))
return
evasion_stacks = max(0, evasion_stacks - proj.damage) // We lose evasion stacks equal to the burn damage.
if(evasion_stacks)
@@ -173,6 +184,7 @@
/// Deactivates Evasion, clearing signals, vars, etc.
/datum/action/ability/xeno_action/evasion/proc/evasion_deactivate()
+ use_state_flags = NONE //To prevent the ability from being used while on cooldown now that it can no longer be deactivated
STOP_PROCESSING(SSprocessing, src)
UnregisterSignal(owner, list(
COMSIG_LIVING_STATUS_STUN,
@@ -218,12 +230,12 @@
return FALSE
if(xeno_owner.issamexenohive(proj.firer)) //We automatically dodge allied projectiles at no cost, and no benefit to our evasion stacks
return COMPONENT_PROJECTILE_DODGE
- if(proj.ammo.flags_ammo_behavior & AMMO_FLAME) //We can't dodge literal fire
+ if(proj.ammo.ammo_behavior_flags & AMMO_FLAME) //We can't dodge literal fire
return FALSE
if(proj.original_target == xeno_owner && proj.distance_travelled < 2) //Pointblank shot.
return FALSE
- if(!(proj.ammo.flags_ammo_behavior & AMMO_SENTRY) && !xeno_owner.fire_stacks) //We ignore projectiles from automated sources/sentries for the purpose of contributions towards our cooldown refresh; also fire prevents accumulation of evasion stacks
- evasion_stacks += proj.damage //Add to evasion stacks for the purposes of determining whether or not our cooldown refreshes
+ if(!xeno_owner.fire_stacks)
+ evasion_stacks += proj.damage //Add to evasion stacks for the purposes of determining whether or not our cooldown refreshes, fire negates this
evasion_dodge_fx(proj)
return COMPONENT_PROJECTILE_DODGE
@@ -299,7 +311,6 @@
return FALSE
/datum/action/ability/activable/xeno/snatch/use_ability(atom/A)
- succeed_activate()
var/mob/living/carbon/xenomorph/X = owner
if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM, A, BUSY_ICON_DANGER, extra_checks = CALLBACK(owner, TYPE_PROC_REF(/mob, break_do_after_checks), list("health" = X.health))))
return FALSE
@@ -333,6 +344,7 @@
RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, PROC_REF(owner_turned))
owner.add_movespeed_modifier(MOVESPEED_ID_SNATCH, TRUE, 0, NONE, TRUE, 2)
owner_turned(null, null, owner.dir)
+ succeed_activate()
add_cooldown()
///Signal handler to update the item overlay when the owner is changing dir
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/runner/castedatum_runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/runner/castedatum_runner.dm
index 3dcab32f8d909..3329c5835fa70 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/runner/castedatum_runner.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/runner/castedatum_runner.dm
@@ -27,14 +27,8 @@
// *** Evolution *** //
evolution_threshold = 100
- //upgrade_threshold = TIER_ONE_THRESHOLD // RUTGMC DELETION
-/* RU TGMC EDIT
- evolves_to = list(
- /mob/living/carbon/xenomorph/hunter,
- /mob/living/carbon/xenomorph/bull,
- /mob/living/carbon/xenomorph/wraith,
- )
-RU TGMC EDIT */
+ //upgrade_threshold = TIER_ONE_THRESHOLD
+
// *** Flags *** //
caste_flags = CASTE_EVOLUTION_ALLOWED
can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA|CASTE_CAN_BE_LEADER|CASTE_CAN_RIDE_CRUSHER
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/runner/runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/runner/runner.dm
index ce11e90bc7d15..6284e284f1490 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/runner/runner.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/runner/runner.dm
@@ -28,6 +28,14 @@
if(. == CONSCIOUS && layer != initial(layer))
layer = MOB_LAYER
+/mob/living/carbon/xenomorph/runner/UnarmedAttack(atom/A, has_proximity, modifiers)
+ /// Runner should not be able to slash while evading.
+ var/datum/action/ability/xeno_action/evasion/evasion_action = actions_by_path[/datum/action/ability/xeno_action/evasion]
+ if(evasion_action.evade_active)
+ balloon_alert(src, "Cannot slash while evading")
+ return
+ return ..()
+
/mob/living/carbon/xenomorph/runner/med_hud_set_status()
. = ..()
hud_set_evasion()
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm b/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm
index 0bf0da0ec3ca6..aa5442ecd1b0c 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm
@@ -25,7 +25,7 @@
// *** Flags *** //
caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION
- can_flags = CASTE_CAN_BE_QUEEN_HEALED
+ can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA
caste_traits = null
// *** Defense *** //
@@ -41,4 +41,5 @@
actions = list(
/datum/action/ability/xeno_action/xeno_resting,
/datum/action/ability/activable/xeno/xeno_spit,
+ /datum/action/ability/activable/xeno/corrosive_acid/drone,
)
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/sentinel/abilities_sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/sentinel/abilities_sentinel.dm
index 929fe567b5ed4..e3ac16b40bc91 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/sentinel/abilities_sentinel.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/sentinel/abilities_sentinel.dm
@@ -14,7 +14,7 @@
bullet_color = COLOR_PALE_GREEN_GRAY
damage = 16
spit_cost = 30
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS
/// The amount of stacks applied on hit.
var/intoxication_stacks = 5
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/sentinel/castedatum_sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/sentinel/castedatum_sentinel.dm
index a9ff1952802cc..882a6d88ab981 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/sentinel/castedatum_sentinel.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/sentinel/castedatum_sentinel.dm
@@ -27,8 +27,6 @@
evolution_threshold = 100
//upgrade_threshold = TIER_ONE_THRESHOLD // RUTGMC DELETION
- evolves_to = list(/mob/living/carbon/xenomorph/spitter)
-
// *** Flags *** //
caste_flags = CASTE_EVOLUTION_ALLOWED
can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA|CASTE_CAN_BE_LEADER|CASTE_CAN_RIDE_CRUSHER
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/shrike/abilities_shrike.dm b/code/modules/mob/living/carbon/xenomorph/castes/shrike/abilities_shrike.dm
index 8002d5e8bfc25..d7405439d14d8 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/shrike/abilities_shrike.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/shrike/abilities_shrike.dm
@@ -160,7 +160,7 @@ RU TGMC EDIT */
add_cooldown()
addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_icons)), 1 SECONDS)
var/mob/living/carbon/xenomorph/xeno = owner
- owner.icon_state = "[xeno.xeno_caste.caste_name][xeno.is_a_rouny ? " rouny" : ""] Screeching"
+ owner.icon_state = "[xeno.xeno_caste.caste_name][(xeno.xeno_flags & XENO_ROUNY) ? " rouny" : ""] Screeching"
if(target) // Keybind use doesn't have a target
owner.face_atom(target)
@@ -180,23 +180,26 @@ RU TGMC EDIT */
lower_left = locate(owner.x + 1, owner.y - 1, owner.z)
upper_right = locate(owner.x + 3, owner.y + 1, owner.z)
- for(var/turf/affected_tile in block(lower_left, upper_right)) //everything in the 2x3 block is found.
+ var/list/things_to_throw = list()
+ for(var/turf/affected_tile in block(lower_left, upper_right)) //everything in the 3x3 block is found.
affected_tile.Shake(duration = 0.5 SECONDS)
- for(var/i in affected_tile)
- var/atom/movable/affected = i
+ for(var/atom/movable/affected AS in affected_tile)
if(!ishuman(affected) && !istype(affected, /obj/item) && !isdroid(affected))
affected.Shake(duration = 0.5 SECONDS)
continue
- if(ishuman(affected)) //if they're human, they also should get knocked off their feet from the blast.
+ if(ishuman(affected))
var/mob/living/carbon/human/H = affected
- if(H.stat == DEAD) //unless they are dead, then the blast mysteriously ignores them.
+ if(H.stat == DEAD)
continue
- H.apply_effects(2 SECONDS, 2 SECONDS) // Stun
+ H.apply_effects(2 SECONDS, 2 SECONDS)
shake_camera(H, 2, 1)
- var/throwlocation = affected.loc //first we get the target's location
- for(var/x in 1 to 6)
- throwlocation = get_step(throwlocation, owner.dir) //then we find where they're being thrown to, checking tile by tile.
- affected.throw_at(throwlocation, 6, 1, owner, TRUE)
+ things_to_throw += affected
+
+ for(var/atom/movable/affected AS in things_to_throw)
+ var/throwlocation = affected.loc
+ for(var/x in 1 to 6)
+ throwlocation = get_step(throwlocation, owner.dir)
+ affected.throw_at(throwlocation, 6, 1, owner, TRUE)
owner.visible_message(span_xenowarning("[owner] sends out a huge blast of psychic energy!"), \
span_xenowarning("We send out a huge blast of psychic energy!"))
@@ -315,6 +318,7 @@ RU TGMC EDIT */ //moved to modular
keybinding_signals = list(
KEYBINDING_NORMAL = COMSIG_XENOABILITY_PLACE_ACID_WELL,
)
+ use_state_flags = ABILITY_USE_LYING
/datum/action/ability/xeno_action/place_acidwell/can_use_action(silent = FALSE, override_flags)
. = ..()
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/shrike/castedatum_shrike.dm b/code/modules/mob/living/carbon/xenomorph/castes/shrike/castedatum_shrike.dm
index 39850eb059920..ad936f4269c96 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/shrike/castedatum_shrike.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/shrike/castedatum_shrike.dm
@@ -29,7 +29,6 @@
maximum_active_caste = 1
//upgrade_threshold = TIER_TWO_THRESHOLD // RUTGMC DELETION
- evolves_to = list(/mob/living/carbon/xenomorph/queen)
deevolves_to = /mob/living/carbon/xenomorph/drone
// *** Flags *** //
@@ -58,6 +57,7 @@
/datum/action/ability/activable/xeno/neurotox_sting/ozelomelyn,
/datum/action/ability/xeno_action/call_of_the_burrowed,
/datum/action/ability/activable/xeno/secrete_resin,
+ /datum/action/ability/activable/xeno/secrete_special_resin,
/datum/action/ability/xeno_action/place_acidwell,
/datum/action/ability/activable/xeno/corrosive_acid,
/datum/action/ability/activable/xeno/psychic_cure,
@@ -94,6 +94,7 @@
/datum/action/ability/activable/xeno/neurotox_sting/ozelomelyn,
/datum/action/ability/xeno_action/call_of_the_burrowed,
/datum/action/ability/activable/xeno/secrete_resin,
+ /datum/action/ability/activable/xeno/secrete_special_resin,
/datum/action/ability/xeno_action/place_acidwell,
/datum/action/ability/activable/xeno/corrosive_acid,
/datum/action/ability/activable/xeno/psychic_cure,
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm
index e220cbc53c5b4..0bf801722154d 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm
@@ -13,6 +13,7 @@
// *** Melee Attacks *** //
melee_damage = 8
+ accuracy_malus = 65
// *** Speed *** //
speed = -0.6
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/spiderling.dm b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/spiderling.dm
index f2ecf279d0e6e..a78fe68f88c2e 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/spiderling.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/spiderling.dm
@@ -50,9 +50,9 @@
return ..()
///If we're covering our widow, any clicks should be transferred to them
-/mob/living/carbon/xenomorph/spiderling/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/mob/living/carbon/xenomorph/spiderling/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!get_dist(src, spidermother) && isxeno(x))
- spidermother.attack_alien(X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+ spidermother.attack_alien(xeno_attacker, damage_amount, damage_type, armor_type, effects, armor_penetration, isrightclick)
return
return ..()
@@ -145,7 +145,7 @@
/// Check if escorted_atom moves away from the spiderling while it's attacking something, this is to always keep them close to escorted_atom
/datum/ai_behavior/spiderling/look_for_new_state()
if(current_action == MOVING_TO_ATOM)
- if(escorted_atom)
+ if(escorted_atom && !(mob_parent.Adjacent(escorted_atom)))
change_action(ESCORTING_ATOM, escorted_atom)
/// Check so that we dont keep attacking our target beyond it's death
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/spitter/abilities_spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/spitter/abilities_spitter.dm
index 22cdd0196ade5..58ac31d937d25 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/spitter/abilities_spitter.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/spitter/abilities_spitter.dm
@@ -61,7 +61,7 @@
for(var/obj/O in T)
if(is_type_in_typecache(O, GLOB.acid_spray_hit) && O.acid_spray_act(owner))
return // returned true if normal density applies
- if(O.density && !(O.allow_pass_flags & PASS_PROJECTILE) && !(O.flags_atom & ON_BORDER))
+ if(O.density && !(O.allow_pass_flags & PASS_PROJECTILE) && !(O.atom_flags & ON_BORDER))
blocked = TRUE
break
@@ -125,7 +125,7 @@
newspit.generate_bullet(scatter_spit, scatter_spit.damage * SPIT_UPGRADE_BONUS(X))
newspit.def_zone = X.get_limbzone_target()
- newspit.fire_at(target, X, null, newspit.ammo.max_range)
+ newspit.fire_at(target, X, X, newspit.ammo.max_range)
succeed_activate()
add_cooldown()
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/spitter/castedatum_spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/spitter/castedatum_spitter.dm
index b1d9c86c904b0..9921f1031becf 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/spitter/castedatum_spitter.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/spitter/castedatum_spitter.dm
@@ -25,10 +25,6 @@
evolution_threshold = 225
//upgrade_threshold = TIER_TWO_THRESHOLD // RUTGMC DELETION
- evolves_to = list(
- /mob/living/carbon/xenomorph/boiler,
- /mob/living/carbon/xenomorph/praetorian,
- )
deevolves_to = list(
/mob/living/carbon/xenomorph/sentinel,
)
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm b/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm
index 45753dc7d1c25..505abb98ab776 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm
@@ -212,7 +212,7 @@
return !uncrossing
/obj/effect/xeno/shield/do_projectile_hit(obj/projectile/proj)
- proj.flags_projectile_behavior |= PROJECTILE_FROZEN
+ proj.projectile_behavior_flags |= PROJECTILE_FROZEN
proj.iff_signal = null
frozen_projectiles += proj
take_damage(proj.damage, proj.ammo.damage_type, proj.ammo.armor_type, 0, REVERSE_DIR(proj.dir), proj.ammo.penetration)
@@ -221,7 +221,7 @@
release_projectiles()
owner.apply_effect(1 SECONDS, WEAKEN)
-/obj/effect/xeno/shield/obj_destruction()
+/obj/effect/xeno/shield/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
release_projectiles()
owner.apply_effect(1 SECONDS, WEAKEN)
return ..()
@@ -229,7 +229,7 @@
///Unfeezes the projectiles on their original path
/obj/effect/xeno/shield/proc/release_projectiles()
for(var/obj/projectile/proj AS in frozen_projectiles)
- proj.flags_projectile_behavior &= ~PROJECTILE_FROZEN
+ proj.projectile_behavior_flags &= ~PROJECTILE_FROZEN
proj.resume_move()
record_projectiles_frozen(owner, LAZYLEN(frozen_projectiles))
@@ -238,15 +238,14 @@
playsound(loc, 'sound/effects/portal.ogg', 20)
var/perpendicular_angle = Get_Angle(get_turf(src), get_step(src, dir)) //the angle src is facing, get_turf because pixel_x or y messes with the angle
for(var/obj/projectile/proj AS in frozen_projectiles)
- proj.flags_projectile_behavior &= ~PROJECTILE_FROZEN
+ proj.projectile_behavior_flags &= ~PROJECTILE_FROZEN
proj.distance_travelled = 0 //we're effectively firing it fresh
var/new_angle = (perpendicular_angle + (perpendicular_angle - proj.dir_angle - 180))
if(new_angle < 0)
new_angle += 360
else if(new_angle > 360)
new_angle -= 360
- proj.firer = src
- proj.fire_at(shooter = src, source = src, angle = new_angle, recursivity = TRUE)
+ proj.fire_at(source = src, angle = new_angle, recursivity = TRUE)
//Record those sick rocket shots
//Is not part of record_projectiles_frozen() because it is probably bad to be running that for every bullet!
@@ -268,6 +267,7 @@
ability_cost = 40
cooldown_duration = 12 SECONDS
keybind_flags = ABILITY_KEYBIND_USE_ABILITY
+ target_flags = ABILITY_TURF_TARGET
keybinding_signals = list(
KEYBINDING_NORMAL = COMSIG_XENOABILITY_PSYCHIC_CRUSH,
)
@@ -403,9 +403,9 @@
carbon_victim.apply_damage(xeno_owner.xeno_caste.crush_strength * 1.5, STAMINA, blocked = BOMB)
carbon_victim.adjust_stagger(5 SECONDS)
carbon_victim.add_slowdown(6)
- else if(ismecha(victim))
- var/obj/vehicle/sealed/mecha/mecha_victim = victim
- mecha_victim.take_damage(xeno_owner.xeno_caste.crush_strength * 5, BRUTE, BOMB)
+ else if(isvehicle(victim))
+ var/obj/vehicle/veh_victim = victim
+ veh_victim.take_damage(xeno_owner.xeno_caste.crush_strength * 5, BRUTE, BOMB)
stop_crush()
/// stops channeling and unregisters all listeners, resetting the ability
@@ -542,16 +542,13 @@
/datum/action/ability/activable/xeno/psy_blast/use_ability(atom/A)
var/mob/living/carbon/xenomorph/xeno_owner = owner
- var/turf/target_turf = get_turf(A)
-
owner.balloon_alert(owner, "We channel our psychic power")
-
generate_particles(A, 7)
//ADD_TRAIT(xeno_owner, TRAIT_IMMOBILE, PSYCHIC_BLAST_ABILITY_TRAIT) // RUTGMC DELETION, PSYBLAST IMMOBILIZING REMOVAL
var/datum/ammo/energy/xeno/ammo_type = xeno_owner.ammo
xeno_owner.update_glow(3, 3, ammo_type.glow_color)
- if(!do_after(xeno_owner, 1 SECONDS, NONE, target_turf, BUSY_ICON_DANGER) || !can_use_ability(A, FALSE))
+ if(!do_after(xeno_owner, 1 SECONDS, IGNORE_TARGET_LOC_CHANGE, A, BUSY_ICON_DANGER) || !can_use_ability(A, FALSE) || !(A in range(get_screen_size(TRUE), owner)))
owner.balloon_alert(owner, "Our focus is disrupted")
end_channel()
//REMOVE_TRAIT(xeno_owner, TRAIT_IMMOBILE, PSYCHIC_BLAST_ABILITY_TRAIT) // RUTGMC DELETION, PSYBLAST IMMOBILIZING REMOVAL
@@ -562,7 +559,7 @@
var/obj/projectile/hitscan/projectile = new /obj/projectile/hitscan(xeno_owner.loc)
projectile.effect_icon = initial(ammo_type.hitscan_effect_icon)
projectile.generate_bullet(ammo_type)
- projectile.fire_at(A, xeno_owner, null, projectile.ammo.max_range, projectile.ammo.shell_speed)
+ projectile.fire_at(A, xeno_owner, xeno_owner, projectile.ammo.max_range, projectile.ammo.shell_speed)
playsound(xeno_owner, 'sound/weapons/guns/fire/volkite_4.ogg', 40)
if(istype(xeno_owner.ammo, /datum/ammo/energy/xeno/psy_blast))
@@ -614,10 +611,10 @@
/datum/action/ability/xeno_action/toggle_warlock_zoom/action_activate()
var/mob/living/carbon/xenomorph/warlock/X = owner
- if(X.is_zoomed)
+ if(X.xeno_flags & XENO_ZOOMED)
X.zoom_out()
else
- if(!do_after(X, 0 SECONDS, IGNORE_HELD_ITEM, null, BUSY_ICON_GENERIC) || X.is_zoomed)
+ if(!do_after(X, 0 SECONDS, IGNORE_HELD_ITEM, null, BUSY_ICON_GENERIC) || (X.xeno_flags & XENO_ZOOMED))
return
X.zoom_in(0, 4.5)
..()
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/warlock/castedatum_warlock.dm b/code/modules/mob/living/carbon/xenomorph/castes/warlock/castedatum_warlock.dm
index e763a4a4e0769..29df8b9630e20 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/warlock/castedatum_warlock.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/warlock/castedatum_warlock.dm
@@ -12,7 +12,7 @@
speed = -0.5
plasma_max = 1700
plasma_gain = 60
- max_health = 375
+ max_health = 325
//upgrade_threshold = TIER_THREE_THRESHOLD // RUTGMC DELETION
spit_types = list(/datum/ammo/energy/xeno/psy_blast)
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/warrior/castedatum_warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/warrior/castedatum_warrior.dm
index bacec21114a7c..01c8ddb385a58 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/warrior/castedatum_warrior.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/warrior/castedatum_warrior.dm
@@ -25,7 +25,6 @@
evolution_threshold = 225
//upgrade_threshold = TIER_TWO_THRESHOLD // RUTGMC DELETION
- evolves_to = list(/mob/living/carbon/xenomorph/crusher, /mob/living/carbon/xenomorph/behemoth, /mob/living/carbon/xenomorph/gorger, /mob/living/carbon/xenomorph/warlock)
deevolves_to = /mob/living/carbon/xenomorph/defender
// *** Flags *** //
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/warrior/warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/warrior/warrior.dm
index f0b570655fe09..ed76584183512 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/warrior/warrior.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/warrior/warrior.dm
@@ -21,7 +21,7 @@
/mob/living/carbon/xenomorph/warrior/handle_special_state()
var/datum/action/ability/xeno_action/toggle_agility/agility_action = actions_by_path[/datum/action/ability/xeno_action/toggle_agility]
if(agility_action?.ability_active)
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Agility"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Agility"
return TRUE
return FALSE
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/widow/abilities_widow.dm b/code/modules/mob/living/carbon/xenomorph/castes/widow/abilities_widow.dm
index 73e8dade2c253..76604218de7ca 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/widow/abilities_widow.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/widow/abilities_widow.dm
@@ -17,7 +17,7 @@
newspit.generate_bullet(web_spit, web_spit.damage * SPIT_UPGRADE_BONUS(X))
newspit.def_zone = X.get_limbzone_target()
- newspit.fire_at(target, X, null, newspit.ammo.max_range)
+ newspit.fire_at(target, X, X, newspit.ammo.max_range)
succeed_activate()
add_cooldown()
@@ -46,7 +46,7 @@
var/obj/projectile/newspit = new (get_turf(X))
newspit.generate_bullet(leash_ball)
- newspit.fire_at(target, X, null, newspit.ammo.max_range)
+ newspit.fire_at(target, X, X, newspit.ammo.max_range)
succeed_activate()
add_cooldown()
@@ -108,15 +108,15 @@
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
/// This is so that xenos can remove leash balls
-/obj/structure/xeno/aoe_leash/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/structure/xeno/aoe_leash/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- X.visible_message(span_xenonotice("\The [X] starts tearing down \the [src]!"), \
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] starts tearing down \the [src]!"), \
span_xenonotice("We start to tear down \the [src]."))
- if(!do_after(X, 1 SECONDS, NONE, X, BUSY_ICON_GENERIC) || QDELETED(src))
+ if(!do_after(xeno_attacker, 1 SECONDS, NONE, xeno_attacker, BUSY_ICON_GENERIC) || QDELETED(src))
return
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- X.visible_message(span_xenonotice("\The [X] tears down \the [src]!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] tears down \the [src]!"), \
span_xenonotice("We tear down \the [src]."))
playsound(src, "alien_resin_break", 25)
take_damage(max_integrity)
@@ -135,6 +135,7 @@
KEYBINDING_NORMAL = COMSIG_XENOABILITY_CREATE_SPIDERLING,
KEYBINDING_ALTERNATE = COMSIG_XENOABILITY_CREATE_SPIDERLING_USING_CC,
)
+ use_state_flags = ABILITY_USE_LYING
/// List of all our spiderlings
var/list/mob/living/carbon/xenomorph/spiderling/spiderlings = list()
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/wraith/abilities_wraith.dm b/code/modules/mob/living/carbon/xenomorph/castes/wraith/abilities_wraith.dm
index b086e6e5fb67a..545d1423273cc 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/wraith/abilities_wraith.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/wraith/abilities_wraith.dm
@@ -297,6 +297,16 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
var/turf/return_turf = get_turf(portal)
if(!return_turf)
return_turf = locate(backup_coordinates[1], backup_coordinates[2], backup_coordinates[3])
+ if(banishment_target.density)
+ var/list/cards = GLOB.cardinals.Copy()
+ for(var/mob/living/displacing in return_turf)
+ if(displacing.stat == DEAD) //no.
+ continue
+ shuffle(cards) //direction should vary.
+ for(var/card AS in cards)
+ if(step(displacing, card))
+ to_chat(displacing, span_warning("A sudden force pushes you away from [return_turf]!"))
+ break
banishment_target.resistance_flags = initial(banishment_target.resistance_flags)
banishment_target.status_flags = initial(banishment_target.status_flags) //Remove stasis and temp invulerability
banishment_target.forceMove(return_turf)
@@ -382,7 +392,7 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
if(isclosedturf(T) && !ignore_closed_turf) //If we care about closed turfs
return TRUE
for(var/atom/blocker AS in T)
- if((blocker.flags_atom & ON_BORDER) || blocker == subject) //If they're a border entity or our subject, we don't care
+ if((blocker.atom_flags & ON_BORDER) || blocker == subject) //If they're a border entity or our subject, we don't care
continue
if(!blocker.CanPass(subject, T) && !ignore_can_pass) //If the subject atom can't pass and we care about that, we have a block
return TRUE
@@ -484,7 +494,7 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
to_chat(owner, span_xenowarning("There is already a portal here!"))
return FALSE
var/area/area = get_area(owner)
- if(area.flags_area & MARINE_BASE)
+ if(area.area_flags & MARINE_BASE)
if(!silent)
to_chat(owner, span_xenowarning("You cannot portal here!"))
return FALSE
@@ -552,6 +562,11 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
QDEL_NULL(portal_visuals)
return ..()
+/obj/effect/wraith_portal/ex_act()
+ if(linked_portal)
+ qdel(linked_portal)
+ qdel(src)
+
/obj/effect/wraith_portal/attack_ghost(mob/dead/observer/user)
. = ..()
if(!linked_portal)
@@ -637,8 +652,6 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
animate(get_filter("portal_ripple"), time = 1.3 SECONDS, loop = -1, easing = LINEAR_EASING, radius = 32)
vis_contents += our_destination
-/obj/effect/wraith_portal/ex_act()
- qdel(src)
/datum/action/ability/activable/xeno/rewind
name = "Time Shift"
@@ -662,6 +675,10 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
var/target_initial_brute_damage = 0
/// Initial sunder of the target
var/target_initial_sunder = 0
+ /// Initial fire stacks of the target
+ var/target_initial_fire_stacks = 0
+ /// Initial on_fire value
+ var/target_initial_on_fire = FALSE
/// How far can you rewind someone
var/range = 5
@@ -693,6 +710,8 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
last_target_locs_list = list(get_turf(A))
target_initial_brute_damage = targeted.getBruteLoss()
target_initial_burn_damage = targeted.getFireLoss()
+ target_initial_fire_stacks = targeted.fire_stacks
+ target_initial_on_fire = targeted.on_fire
if(isxeno(A))
var/mob/living/carbon/xenomorph/xeno_target = targeted
target_initial_sunder = xeno_target.sunder
@@ -735,7 +754,12 @@ GLOBAL_LIST_INIT(wraith_banish_very_short_duration_list, typecacheof(list(
targeted.status_flags &= ~(INCORPOREAL|GODMODE)
REMOVE_TRAIT(owner, TRAIT_IMMOBILE, TIMESHIFT_TRAIT)
targeted.heal_overall_damage(targeted.getBruteLoss() - target_initial_brute_damage, targeted.getFireLoss() - target_initial_burn_damage, updating_health = TRUE)
- if(isxeno(target))
+ if(target_initial_on_fire && target_initial_fire_stacks >= 0)
+ targeted.fire_stacks = target_initial_fire_stacks
+ targeted.IgniteMob()
+ else
+ targeted.ExtinguishMob()
+ if(isxeno(targeted))
var/mob/living/carbon/xenomorph/xeno_target = targeted
xeno_target.sunder = target_initial_sunder
targeted.remove_filter("rewind_blur")
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/wraith/castedatum_wraith.dm b/code/modules/mob/living/carbon/xenomorph/castes/wraith/castedatum_wraith.dm
index dddb8dd3caf8a..5f7998202ec22 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/wraith/castedatum_wraith.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/wraith/castedatum_wraith.dm
@@ -26,11 +26,6 @@
evolution_threshold = 225
//upgrade_threshold = TIER_TWO_THRESHOLD // RUTGMC DELETION
- evolves_to = list(
- /mob/living/carbon/xenomorph/defiler,
- /mob/living/carbon/xenomorph/ravager,
- /mob/living/carbon/xenomorph/warlock,
- )
deevolves_to = /mob/living/carbon/xenomorph/runner
// *** Flags *** //
diff --git a/code/modules/mob/living/carbon/xenomorph/charge_crush.dm b/code/modules/mob/living/carbon/xenomorph/charge_crush.dm
index 783252f54bd8b..52d41f5a48dd2 100644
--- a/code/modules/mob/living/carbon/xenomorph/charge_crush.dm
+++ b/code/modules/mob/living/carbon/xenomorph/charge_crush.dm
@@ -401,7 +401,7 @@
charge_datum.do_stop_momentum()
return PRECRUSH_STOPPED
if(anchored)
- if(flags_atom & ON_BORDER)
+ if(atom_flags & ON_BORDER)
if(dir == REVERSE_DIR(charger.dir))
. = (CHARGE_SPEED(charge_datum) * 80) //Damage to inflict.
charge_datum.speed_down(3)
@@ -425,6 +425,9 @@
/obj/vehicle/sealed/mecha/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum)
return (CHARGE_SPEED(charge_datum) * 375)
+/obj/hitbox/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum)
+ return (CHARGE_SPEED(charge_datum) * 20)
+
/obj/structure/razorwire/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum)
if(CHECK_BITFIELD(resistance_flags, INDESTRUCTIBLE) || charger.is_charging < CHARGE_ON)
charge_datum.do_stop_momentum()
diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm
index 8d1fbbab7477c..1351684d5d038 100644
--- a/code/modules/mob/living/carbon/xenomorph/death.dm
+++ b/code/modules/mob/living/carbon/xenomorph/death.dm
@@ -4,10 +4,7 @@
/mob/living/carbon/xenomorph/death(gibbing, deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw.", silent)
- if(stat == DEAD)
- return ..()
- return ..() //Just a different standard deathmessage
-
+ return ..() //we're just changing the death message
/mob/living/carbon/xenomorph/on_death()
GLOB.alive_xeno_list -= src
@@ -20,11 +17,13 @@
hive?.on_xeno_death(src)
hive?.update_tier_limits() //Update our tier limits.
- if(is_zoomed)
+ if(xeno_flags & XENO_ZOOMED)
zoom_out()
- if(tier != XENO_TIER_MINION)
- GLOB.key_to_time_of_xeno_death[key] = world.time
+ if(GLOB.xeno_stat_multiplicator_buff == 1) //if autobalance is on, it won't equal 1, so xeno respawn timer is not set
+ switch(tier)
+ if(XENO_TIER_ZERO, XENO_TIER_ONE, XENO_TIER_TWO, XENO_TIER_THREE) //minions and tier fours have no respawn timer
+ GLOB.key_to_time_of_xeno_death[key] = world.time
SSminimaps.remove_marker(src)
set_light_on(FALSE)
@@ -37,6 +36,7 @@
if(hud_used.alien_plasma_display)
hud_used.alien_plasma_display.icon_state = "power_display_empty"
update_icons()
+ hud_set_plasma()
death_cry()
diff --git a/code/modules/mob/living/carbon/xenomorph/egg.dm b/code/modules/mob/living/carbon/xenomorph/egg.dm
index 4d77621558e64..c0f8e7477f168 100644
--- a/code/modules/mob/living/carbon/xenomorph/egg.dm
+++ b/code/modules/mob/living/carbon/xenomorph/egg.dm
@@ -1,7 +1,7 @@
/obj/alien/egg
name = "theoretical egg"
density = FALSE
- flags_atom = CRITICAL_ATOM
+ atom_flags = CRITICAL_ATOM
max_integrity = 80
integrity_failure = 20
///What maturity stage are we in
@@ -21,6 +21,7 @@
advance_maturity(maturity_stage)
/obj/alien/egg/update_icon_state()
+ . = ..()
icon_state = initial(icon_state) + "[maturity_stage]"
/obj/alien/egg/obj_break(damage_flag)
@@ -82,7 +83,7 @@
name = "hugger egg"
icon_state = "egg_hugger"
density = FALSE
- flags_atom = CRITICAL_ATOM
+ atom_flags = CRITICAL_ATOM
max_integrity = 80
maturity_time = 15 SECONDS
stage_ready_to_burst = 2
@@ -119,37 +120,36 @@
hugger.go_active()
*/
-/obj/alien/egg/hugger/attack_alien(mob/living/carbon/xenomorph/xenomorph, damage_amount = xenomorph.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(xenomorph.status_flags & INCORPOREAL)
+/obj/alien/egg/hugger/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE
- if(!istype(xenomorph))
- return attack_hand(xenomorph)
+ if(!istype(xeno_attacker))
+ return attack_hand(xeno_attacker)
- if(!issamexenohive(xenomorph))
- xenomorph.do_attack_animation(src, ATTACK_EFFECT_SMASH)
- xenomorph.visible_message("[xenomorph] crushes \the [src].","We crush \the [src].")
+ if(!issamexenohive(xeno_attacker))
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ xeno_attacker.visible_message("[xeno_attacker] crushes \the [src].","We crush \the [src].")
burst(FALSE)
return
switch(maturity_stage)
if(1)
- to_chat(xenomorph, span_xenowarning("The child is not developed yet."))
+ to_chat(xeno_attacker, span_xenowarning("The child is not developed yet."))
if(2)
- to_chat(xenomorph, span_xenonotice("We retrieve the child."))
+ to_chat(xeno_attacker, span_xenonotice("We retrieve the child."))
burst()
if(3, 4)
- xenomorph.visible_message(span_xenonotice("\The [xenomorph] clears the hatched egg."), \
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] clears the hatched egg."), \
span_xenonotice("We clear the hatched egg."))
playsound(loc, "alien_resin_break", 25)
qdel(src)
/obj/alien/egg/hugger/attackby(obj/item/I, mob/user, params)
- . = ..()
+ if(istype(I, /obj/item/clothing/mask/facehugger))
+ return insert_new_hugger(I, user)
- if(!istype(I, /obj/item/clothing/mask/facehugger))
- return FALSE
- return insert_new_hugger(I, user)
+ return ..()
///Try to insert a new hugger into the egg
/obj/alien/egg/hugger/proc/insert_new_hugger(obj/item/clothing/mask/facehugger/facehugger, mob/user)
@@ -208,18 +208,18 @@
NS.start()
*/ //RUTGMC EDIT END
-/obj/alien/egg/gas/attack_alien(mob/living/carbon/xenomorph/xenomorph, damage_amount = xenomorph.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/alien/egg/gas/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(maturity_stage > stage_ready_to_burst)
- xenomorph.visible_message(span_xenonotice("\The [xenomorph] clears the hatched egg."), \
+ xeno_attacker.visible_message(span_xenonotice("\The [xeno_attacker] clears the hatched egg."), \
span_xenonotice("We clear the broken egg."))
playsound(loc, "alien_resin_break", 25)
qdel(src)
- if(!issamexenohive(xenomorph) || xenomorph.a_intent != INTENT_HELP)
- xenomorph.do_attack_animation(src, ATTACK_EFFECT_SMASH)
- xenomorph.visible_message(span_xenowarning("[xenomorph] crushes \the [src]."), span_xenowarning("We crush \the [src]."))
+ if(!issamexenohive(xeno_attacker) || xeno_attacker.a_intent != INTENT_HELP)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ xeno_attacker.visible_message(span_xenowarning("[xeno_attacker] crushes \the [src]."), span_xenowarning("We crush \the [src]."))
burst(TRUE)
return
- to_chat(xenomorph, span_warning("That egg is filled with gas and has no child to retrieve."))
+ to_chat(xeno_attacker, span_warning("That egg is filled with gas and has no child to retrieve."))
diff --git a/code/modules/mob/living/carbon/xenomorph/embryo.dm b/code/modules/mob/living/carbon/xenomorph/embryo.dm
index dcdc762b858d7..6f71a087a14d3 100644
--- a/code/modules/mob/living/carbon/xenomorph/embryo.dm
+++ b/code/modules/mob/living/carbon/xenomorph/embryo.dm
@@ -192,9 +192,9 @@
victim.update_burst()
- if(istype(victim.loc, /obj/vehicle/multitile/root))
- var/obj/vehicle/multitile/root/V = victim.loc
- V.handle_player_exit(src)
+ if(istype(victim.loc, /obj/vehicle/sealed))
+ var/obj/vehicle/sealed/armored/veh = victim.loc
+ forceMove(veh.exit_location(src))
else
forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container.
playsound(src, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25)
diff --git a/code/modules/mob/living/carbon/xenomorph/evo_datum.dm b/code/modules/mob/living/carbon/xenomorph/evo_datum.dm
index 9a5b6415091d4..15bda447ac49b 100644
--- a/code/modules/mob/living/carbon/xenomorph/evo_datum.dm
+++ b/code/modules/mob/living/carbon/xenomorph/evo_datum.dm
@@ -24,7 +24,7 @@
.["abilities"] = list()
for(var/ability in xeno.xeno_caste.actions)
var/datum/action/ability/xeno_action/xeno_ability = ability
- if(SSticker.mode && !(SSticker.mode.flags_xeno_abilities & initial(xeno_ability.gamemode_flags)))
+ if(SSticker.mode && !(SSticker.mode.xeno_abilities_flags & initial(xeno_ability.gamemode_flags)))
continue
.["abilities"]["[ability]"] = list(
"name" = initial(xeno_ability.name),
@@ -33,17 +33,17 @@
"cooldown" = (initial(xeno_ability.cooldown_duration) / 10)
)
.["evolves_to"] = list()
- for(var/evolves_into in xeno.xeno_caste.evolves_to)
+ for(var/evolves_into in xeno.get_evolution_options())
var/datum/xeno_caste/caste = GLOB.xeno_caste_datums[evolves_into][XENO_UPGRADE_BASETYPE]
var/list/caste_data = list(
"type_path" = caste.caste_type_path,
"name" = caste.display_name,
"abilities" = list(),
- "instant_evolve" = (caste.caste_flags & CASTE_INSTANT_EVOLUTION),
+ "instant_evolve" = (caste.caste_flags & CASTE_INSTANT_EVOLUTION || (HAS_TRAIT(xeno, TRAIT_CASTE_SWAP) || HAS_TRAIT(xeno, TRAIT_REGRESSING))),
)
for(var/ability in caste.actions)
var/datum/action/ability/xeno_action/xeno_ability = ability
- if(SSticker.mode && !(SSticker.mode.flags_xeno_abilities & initial(xeno_ability.gamemode_flags)))
+ if(SSticker.mode && !(SSticker.mode.xeno_abilities_flags & initial(xeno_ability.gamemode_flags)))
continue
caste_data["abilities"]["[ability]"] = list(
"name" = initial(xeno_ability.name),
@@ -74,5 +74,10 @@
switch(action)
if("evolve")
var/datum/xeno_caste/caste = GLOB.xeno_caste_datums[text2path(params["path"])][XENO_UPGRADE_BASETYPE]
- xeno.do_evolve(caste.caste_type_path, caste.display_name) // All the checks for can or can't are handled inside do_evolve
+ xeno.do_evolve(caste.caste_type_path, caste.display_name, (HAS_TRAIT(xeno, TRAIT_CASTE_SWAP) || HAS_TRAIT(xeno, TRAIT_REGRESSING))) // All the checks for can or can't are handled inside do_evolve
return TRUE
+
+/datum/evolution_panel/ui_close(mob/user)
+ . = ..()
+ REMOVE_TRAIT(user, TRAIT_CASTE_SWAP, TRAIT_CASTE_SWAP)
+ REMOVE_TRAIT(user, TRAIT_REGRESSING, TRAIT_REGRESSING)
diff --git a/code/modules/mob/living/carbon/xenomorph/evolution.dm b/code/modules/mob/living/carbon/xenomorph/evolution.dm
index 888cc62c646c3..d5b3566d4c074 100644
--- a/code/modules/mob/living/carbon/xenomorph/evolution.dm
+++ b/code/modules/mob/living/carbon/xenomorph/evolution.dm
@@ -2,15 +2,26 @@
//Recoded and consolidated by Abby -- ALL evolutions come from here now. It should work with any caste, anywhere
// refactored by spookydonut because the above two were shitcoders and i'm sure in time my code too will be considered shit.
-//All castes need an evolves_to() list in their defines
-//Such as evolves_to = list("Warrior", "Sentinel", "Runner", "Badass") etc
-// except use typepaths now so you dont have to have an entry for literally every evolve path
/mob/living/carbon/xenomorph/verb/Evolve()
set name = "Evolve"
set desc = "Evolve into a higher form."
set category = "Alien"
+ SStgui.close_user_uis(src, GLOB.evo_panel) // Closes all verbs using evo UI; evolution, caste swap and regress. They need to be refreshed with their respective castelists.
+ GLOB.evo_panel.ui_interact(src)
+
+/mob/living/carbon/xenomorph/verb/caste_swap()
+ set name = "Caste Swap"
+ set desc = "Change into another caste in the same tier."
+ set category = "Alien"
+
+ if(world.time - (GLOB.key_to_time_of_caste_swap[key] ? GLOB.key_to_time_of_caste_swap[key] : -INFINITY) < 9000) //casteswap timer, 15 minutes
+ to_chat(src, span_warning("Your caste swap timer is not done yet."))
+ return
+
+ SStgui.close_user_uis(src, GLOB.evo_panel)
+ ADD_TRAIT(src, TRAIT_CASTE_SWAP, TRAIT_CASTE_SWAP)
GLOB.evo_panel.ui_interact(src)
/mob/living/carbon/xenomorph/verb/regress()
@@ -18,42 +29,52 @@
set desc = "Regress into a lower form."
set category = "Alien"
- var/tiers_to_pick_from
+ SStgui.close_user_uis(src, GLOB.evo_panel)
+ ADD_TRAIT(src, TRAIT_REGRESSING, TRAIT_REGRESSING)
+ GLOB.evo_panel.ui_interact(src)
+
+///Creates a list of possible evolution options for a caste based on their tier.
+/mob/living/carbon/xenomorph/proc/get_evolution_options()
+ . = list()
+ if(HAS_TRAIT(src, TRAIT_CASTE_SWAP))
+ switch(tier)
+ if(XENO_TIER_ZERO, XENO_TIER_FOUR)
+ return
+ if(XENO_TIER_ONE)
+ return GLOB.xeno_types_tier_one
+ if(XENO_TIER_TWO)
+ return GLOB.xeno_types_tier_two
+ if(XENO_TIER_THREE)
+ return GLOB.xeno_types_tier_three
+ if(HAS_TRAIT(src, TRAIT_REGRESSING))
+ switch(tier)
+ if(XENO_TIER_ZERO, XENO_TIER_FOUR)
+ if(isxenoshrike(src))
+ return GLOB.xeno_types_tier_one
+ else
+ return
+ if(XENO_TIER_ONE)
+ return list(/mob/living/carbon/xenomorph/larva)
+ if(XENO_TIER_TWO)
+ return GLOB.xeno_types_tier_one
+ if(XENO_TIER_THREE)
+ return GLOB.xeno_types_tier_two
switch(tier)
- if(XENO_TIER_ZERO, XENO_TIER_FOUR, XENO_TIER_MINION)
-/* RU TGMC EDIT
- if(isxenoshrike(src))
- tiers_to_pick_from = GLOB.xeno_types_tier_one
- else
-RU TGMC EDIT */
- to_chat(src, span_warning("Your tier does not allow you to regress."))
- return
+ if(XENO_TIER_ZERO)
+ if(istype(xeno_caste, /datum/xeno_caste/larva_predalien))
+ return list(/mob/living/carbon/xenomorph/predalien)
+ if(!istype(xeno_caste, /datum/xeno_caste/hivemind))
+ return GLOB.xeno_types_tier_one
if(XENO_TIER_ONE)
- tiers_to_pick_from = list(/mob/living/carbon/xenomorph/larva)
+ return GLOB.xeno_types_tier_two + GLOB.xeno_types_tier_four + /mob/living/carbon/xenomorph/hivemind
if(XENO_TIER_TWO)
- tiers_to_pick_from = GLOB.xeno_types_tier_one
+ return GLOB.xeno_types_tier_three + GLOB.xeno_types_tier_four + /mob/living/carbon/xenomorph/hivemind
if(XENO_TIER_THREE)
- tiers_to_pick_from = GLOB.xeno_types_tier_two
- else
- CRASH("side_evolve() called without a valid tier")
-
- var/list/castes_to_pick = list()
- for(var/type in tiers_to_pick_from)
- var/datum/xeno_caste/available_caste = GLOB.xeno_caste_datums[type][XENO_UPGRADE_BASETYPE]
- castes_to_pick += available_caste.caste_name
- var/castepick = tgui_input_list(src, "We are growing into a beautiful alien! It is time to choose a caste.", null, castes_to_pick)
- if(!castepick) //Changed my mind
- return
-
- var/castetype
- for(var/type in tiers_to_pick_from)
- var/datum/xeno_caste/available_caste = GLOB.xeno_caste_datums[type][XENO_UPGRADE_BASETYPE]
- if(castepick != available_caste.caste_name)
- continue
- castetype = type
- break
+ return GLOB.xeno_types_tier_four + /mob/living/carbon/xenomorph/hivemind
+ if(XENO_TIER_FOUR)
+ if(istype(xeno_caste, /datum/xeno_caste/shrike))
+ return list(/mob/living/carbon/xenomorph/queen, /mob/living/carbon/xenomorph/king)
- do_evolve(castetype, castepick, TRUE)
///Handles the evolution or devolution of the xenomorph
/mob/living/carbon/xenomorph/proc/do_evolve(caste_type, forced_caste_name, regression = FALSE)
@@ -70,14 +91,14 @@ RU TGMC EDIT */
castepick = forced_caste_name
else
var/list/castes_to_pick = list()
- for(var/type in xeno_caste.evolves_to)
+ for(var/type in get_evolution_options())
var/datum/xeno_caste/Z = GLOB.xeno_caste_datums[type][XENO_UPGRADE_BASETYPE]
castes_to_pick += Z.caste_name
castepick = tgui_input_list(src, "We are growing into a beautiful alien! It is time to choose a caste.", null, castes_to_pick)
if(!castepick) //Changed my mind
return
- for(var/type in xeno_caste.evolves_to)
+ for(var/type in get_evolution_options())
var/datum/xeno_caste/XC = GLOB.xeno_caste_datums[type][XENO_UPGRADE_BASETYPE]
if(castepick == XC.caste_name)
new_mob_type = type
@@ -101,6 +122,12 @@ RU TGMC EDIT */
if(!generic_evolution_checks() || !caste_evolution_checks(new_mob_type, castepick, regression))
return
+ if(HAS_TRAIT(src, TRAIT_CASTE_SWAP))
+ GLOB.key_to_time_of_caste_swap[key] = world.time
+
+ if(xeno_flags & XENO_ZOOMED)
+ zoom_out()
+
SStgui.close_user_uis(src) //Force close all UIs upon evolution.
finish_evolve(new_mob_type)
@@ -140,10 +167,10 @@ RU TGMC EDIT */
new_xeno.fireloss = fireloss //Transfers the damage over.
new_xeno.updatehealth()
- if(xeno_mobhud)
+ if(xeno_flags & XENO_MOBHUD)
var/datum/atom_hud/H = GLOB.huds[DATA_HUD_XENO_STATUS]
H.add_hud_to(new_xeno) //keep our mobhud choice
- new_xeno.xeno_mobhud = TRUE
+ new_xeno.xeno_flags |= XENO_MOBHUD
if(lighting_alpha != new_xeno.lighting_alpha)
new_xeno.toggle_nightvision(lighting_alpha)
@@ -161,7 +188,7 @@ RU TGMC EDIT */
GLOB.round_statistics.total_xenos_created-- //so an evolved xeno doesn't count as two.
SSblackbox.record_feedback("tally", "round_statistics", -1, "total_xenos_created")
- if(queen_chosen_lead && (new_xeno.xeno_caste.can_flags & CASTE_CAN_BE_LEADER)) // xeno leader is removed by Destroy()
+ if((xeno_flags & XENO_LEADER) && (new_xeno.xeno_caste.can_flags & CASTE_CAN_BE_LEADER)) // xeno leader is removed by Destroy()
hive.add_leader(new_xeno)
new_xeno.hud_set_queen_overwatch()
if(hive.living_xeno_queen)
@@ -217,7 +244,7 @@ RU TGMC EDIT */
balloon_alert(src, "The restraints are too restricting to allow us to evolve")
return FALSE
- if(isnull(xeno_caste.evolves_to) || !(xeno_caste.caste_flags & CASTE_EVOLUTION_ALLOWED) || HAS_TRAIT(src, TRAIT_VALHALLA_XENO))
+ if(isnull(get_evolution_options()) || !(xeno_caste.caste_flags & CASTE_EVOLUTION_ALLOWED) || HAS_TRAIT(src, TRAIT_VALHALLA_XENO))
balloon_alert(src, "We are already the apex of form and function. Let's go forth and spread the hive!")
return FALSE
@@ -245,7 +272,7 @@ RU TGMC EDIT */
///Check if the xeno can currently evolve into a specific caste
/mob/living/carbon/xenomorph/proc/caste_evolution_checks(new_mob_type, castepick, regression = FALSE)
- if(!regression && !(new_mob_type in xeno_caste.evolves_to))
+ if(!regression && !(new_mob_type in get_evolution_options()))
balloon_alert(src, "We can't evolve to that caste from our current one")
return FALSE
@@ -308,7 +335,7 @@ RU TGMC EDIT */
balloon_alert(src, "The hive cannot support another Tier 3, wait for either more aliens to be born or someone to die")
return FALSE
var/potential_queens = length(hive.xenos_by_typepath[/mob/living/carbon/xenomorph/larva]) + length(hive.xenos_by_typepath[/mob/living/carbon/xenomorph/drone])
- if(SSticker.mode?.flags_round_type & MODE_XENO_RULER && !hive.living_xeno_ruler && potential_queens == 1)
+ if(SSticker.mode?.round_type_flags & MODE_XENO_RULER && !hive.living_xeno_ruler && potential_queens == 1)
if(isxenolarva(src) && new_mob_type != /mob/living/carbon/xenomorph/drone)
to_chat(src, span_xenonotice("The hive currently has no sister able to become a ruler! The survival of the hive requires from us to be a Drone!"))
return FALSE
diff --git a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm
index 0ad69d28491c0..b714759dbd863 100644
--- a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm
+++ b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm
@@ -19,10 +19,10 @@
item_state = "facehugger"
w_class = WEIGHT_CLASS_TINY //Note: can be picked up by aliens unlike most other items of w_class below 4
resistance_flags = NONE
- flags_inventory = COVEREYES|COVERMOUTH
- flags_armor_protection = FACE|EYES
- flags_atom = CRITICAL_ATOM
- flags_item = NOBLUDGEON
+ inventory_flags = COVEREYES|COVERMOUTH
+ armor_protection_flags = FACE|EYES
+ atom_flags = CRITICAL_ATOM
+ item_flags = NOBLUDGEON
throw_range = 1
worn_layer = FACEHUGGER_LAYER
layer = FACEHUGGER_LAYER
@@ -100,7 +100,8 @@
clear_hugger_source()
return ..()
-/obj/item/clothing/mask/facehugger/update_icon()
+/obj/item/clothing/mask/facehugger/update_icon_state()
+ . = ..()
if(stat == DEAD)
var/fertility = sterile ? "impregnated" : "dead"
icon_state = "[initial(icon_state)]_[fertility]"
@@ -115,18 +116,18 @@
//Deal with picking up facehuggers. "attack_alien" is the universal 'xenos click something while unarmed' proc.
-/obj/item/clothing/mask/facehugger/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/item/clothing/mask/facehugger/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- if(!issamexenohive(X) && stat != DEAD)
- X.do_attack_animation(src, ATTACK_EFFECT_SMASH)
- X.visible_message("[X] crushes \the [src]",
+ if(!issamexenohive(xeno_attacker) && stat != DEAD)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ xeno_attacker.visible_message("[xeno_attacker] crushes \the [src]",
"We crush \the [src]")
kill_hugger()
return
else
- attack_hand(X)
+ attack_hand(xeno_attacker)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clothing/mask/facehugger/attack_hand(mob/living/user)
@@ -293,12 +294,12 @@
if(stat == DEAD || stat == UNCONSCIOUS || !isturf(loc)) //It's dead or inactive or not on a turf don't bother
return
about_to_jump = TRUE
- update_overlays()
+ update_appearance(UPDATE_OVERLAYS)
///Remove the hugger's alert overlay
/obj/item/clothing/mask/facehugger/proc/remove_danger_overlay()
about_to_jump = FALSE
- update_overlays()
+ update_appearance(UPDATE_OVERLAYS)
/obj/item/clothing/mask/facehugger/proc/check_lifecycle()
@@ -647,13 +648,13 @@
kill_hugger()
/obj/item/clothing/mask/facehugger/attackby(obj/item/I, mob/user, params)
- if(I.flags_item & NOBLUDGEON || attached)
+ if(I.item_flags & NOBLUDGEON || attached)
return
kill_hugger()
/obj/item/clothing/mask/facehugger/bullet_act(obj/projectile/P)
..()
- if(P.ammo.flags_ammo_behavior & AMMO_XENO)
+ if(P.ammo.ammo_behavior_flags & AMMO_XENO)
return FALSE //Xeno spits ignore huggers.
if(P.damage && !(P.ammo.damage_type in list(OXY, STAMINA)))
kill_hugger()
@@ -704,33 +705,47 @@
/obj/item/clothing/mask/facehugger/combat
sterile = TRUE
combat_hugger = TRUE
- flags_equip_slot = NONE
-
+ equip_slot_flags = NONE
-/obj/item/clothing/mask/facehugger/combat/neuro
- name = "neuro hugger"
+/obj/item/clothing/mask/facehugger/combat/chem_injector
desc = "This strange creature has a single prominent sharp proboscis."
- color = COLOR_DARK_ORANGE
impact_time = 1 SECONDS
activate_time = 1.5 SECONDS
jump_cooldown = 1.5 SECONDS
proximity_time = 0.5 SECONDS
+ ///The type of chemical we inject
+ var/datum/reagent/toxin/injected_chemical_type
+ ///The amount of chemical we should inject, in units
+ var/amount_injected = 10
-/obj/item/clothing/mask/facehugger/combat/neuro/Attach(mob/M, mob/user)
+/obj/item/clothing/mask/facehugger/combat/chem_injector/Attach(mob/living/carbon/M, mob/user)
if(!combat_hugger_check_target(M))
return FALSE
- var/mob/living/victim = M
do_attack_animation(M)
- victim.apply_damage(100, STAMINA, BODY_ZONE_HEAD, BIO) //This should prevent sprinting
- victim.apply_damage(1, BRUTE, sharp = TRUE, updating_health = TRUE) //Token brute for the injection
- victim.reagents.add_reagent(/datum/reagent/toxin/xeno_neurotoxin, 10, no_overdose = TRUE)
- playsound(victim, 'sound/effects/spray3.ogg', 25, 1)
- victim.visible_message(span_danger("[src] penetrates [victim] with its sharp probscius!"),span_danger("[src] penetrates you with a sharp probscius before falling down!"))
+ M.apply_damage(1, BRUTE, sharp = TRUE, updating_health = TRUE) //Token brute for the injection
+ M.reagents.add_reagent(injected_chemical_type, amount_injected, no_overdose = TRUE)
+ playsound(M, 'sound/effects/spray3.ogg', 25, 1)
+ M.visible_message(span_danger("[src] penetrates [M] with its sharp probscius!"), span_danger("[src] penetrates you with a sharp probscius before falling down!"))
leaping = FALSE
go_idle() //We're a bit slow on the recovery
return TRUE
+/obj/item/clothing/mask/facehugger/combat/chem_injector/neuro
+ name = "neurotoxin hugger"
+ color = COLOR_DARK_ORANGE
+ injected_chemical_type = /datum/reagent/toxin/xeno_neurotoxin
+
+/obj/item/clothing/mask/facehugger/combat/chem_injector/neuro/Attach(mob/living/carbon/M)
+ if(!..())
+ return
+ M.apply_damage(100, STAMINA, BODY_ZONE_HEAD, BIO) //This should prevent sprinting
+
+/obj/item/clothing/mask/facehugger/combat/chem_injector/ozelomelyn
+ name = "ozelomelyn hugger"
+ injected_chemical_type = /datum/reagent/toxin/xeno_ozelomelyn
+ color = COLOR_MAGENTA
+
/obj/item/clothing/mask/facehugger/combat/acid
name = "acid hugger"
desc = "This repulsive looking thing is bloated with throbbing, putrescent green sacks of flesh."
diff --git a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm
index 7b8a7b22d1282..a5d1cae011382 100644
--- a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm
+++ b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm
@@ -27,6 +27,8 @@
var/tier2_xeno_limit
/// Queue of all clients wanting to join xeno side
var/list/client/candidates
+ /// Amount of special resin points used to build special resin walls by each hive.
+ var/special_build_points = 50
///Reference to upgrades available and purchased by this hive.
var/datum/hive_purchases/purchases = new
@@ -80,8 +82,8 @@
.["hive_larva_rate"] = SSsilo.current_larva_spawn_rate
.["hive_larva_burrowed"] = xeno_job.total_positions - xeno_job.current_positions
- var/psy_points = SSpoints.xeno_points_by_hive[hivenumber]
- .["hive_psy_points"] = !isnull(psy_points) ? psy_points : 0
+ .["hive_strategic_psy_points"] = !isnull(SSpoints.xeno_strategic_points_by_hive[hivenumber]) ? SSpoints.xeno_strategic_points_by_hive[hivenumber] : 0
+ .["hive_tactical_psy_points"] = !isnull(SSpoints.xeno_tactical_points_by_hive[hivenumber]) ? SSpoints.xeno_tactical_points_by_hive[hivenumber] : 0
var/hivemind_countdown = SSticker.mode?.get_hivemind_collapse_countdown()
.["hive_orphan_collapse"] = !isnull(hivemind_countdown) ? hivemind_countdown : 0
@@ -141,7 +143,7 @@
"health" = round(health * 100, 1),
"plasma" = round((xeno.plasma_stored / (caste.plasma_max * plasma_multi)) * 100, 1),
"can_be_leader" = CHECK_BITFIELD(initial(caste.can_flags), CASTE_CAN_BE_LEADER), //RUTGMC ADDITION
- "is_leader" = xeno.queen_chosen_lead,
+ "is_leader" = xeno.xeno_flags & XENO_LEADER,
"is_ssd" = !xeno.client,
"index" = GLOB.hive_ui_caste_index[caste.caste_type_path],
))
@@ -383,6 +385,12 @@
for(var/obj/structure/xeno/evotower/tower AS in evotowers)
. += tower.boost_amount
+///fetches number of bonus maturity points given to the hive
+/datum/hive_status/proc/get_upgrade_boost()
+ . = 0
+ for(var/obj/structure/xeno/evotower/tower AS in evotowers)
+ . += tower.maturty_boost_amount
+
// ***************************************
// *********** Adding xenos
// ***************************************
@@ -537,7 +545,7 @@
if(!hive.remove_xeno(src))
CRASH("failed to remove xeno from a hive")
- if(queen_chosen_lead || (src in hive.xeno_leader_list))
+ if((xeno_flags & XENO_LEADER) || (src in hive.xeno_leader_list))
hive.remove_leader(src)
SSdirection.stop_tracking(hive.hivenumber, src)
@@ -552,7 +560,7 @@
var/obj/machinery/nuclearbomb/nuke = thing
if(!nuke.timer)
CRASH("hive_status's setup_nuke_hud_timer called with invalid nuke object")
- nuke_hud_timer = new(null, get_all_xenos() , nuke.timer, "Nuke ACTIVE: ${timer}")
+ nuke_hud_timer = new(null, null, get_all_xenos() , nuke.timer, "Nuke ACTIVE: ${timer}")
/datum/hive_status/Destroy(force, ...)
. = ..()
@@ -606,12 +614,12 @@
// ***************************************
/datum/hive_status/proc/add_leader(mob/living/carbon/xenomorph/X)
xeno_leader_list += X
- X.queen_chosen_lead = TRUE
+ X.xeno_flags |= XENO_LEADER
X.give_rally_abilities()
/datum/hive_status/proc/remove_leader(mob/living/carbon/xenomorph/X)
xeno_leader_list -= X
- X.queen_chosen_lead = FALSE
+ X.xeno_flags &= ~XENO_LEADER
if(!isxenoshrike(X) && !isxenoqueen(X) && !isxenohivemind(X)) //These innately have the Rally Hive ability
X.remove_rally_hive_ability()
@@ -799,7 +807,7 @@
/datum/hive_status/normal/check_ruler()
- if(!(SSticker.mode?.flags_round_type & MODE_XENO_RULER))
+ if(!(SSticker.mode?.round_type_flags & MODE_XENO_RULER))
return TRUE
return living_xeno_ruler
@@ -901,7 +909,7 @@ to_chat will check for valid clients itself already so no need to double check f
/datum/hive_status/normal/handle_ruler_timer()
if(!isinfestationgamemode(SSticker.mode)) //Check just need for unit test
return
- if(!(SSticker.mode?.flags_round_type & MODE_XENO_RULER))
+ if(!(SSticker.mode?.round_type_flags & MODE_XENO_RULER))
return
if(SSmonitor.gamestate == SHUTTERS_CLOSED) //don't trigger orphan hivemind if the shutters are closed
return
@@ -919,7 +927,7 @@ to_chat will check for valid clients itself already so no need to double check f
D.orphan_hive_timer = addtimer(CALLBACK(D, TYPE_PROC_REF(/datum/game_mode, orphan_hivemind_collapse)), NUCLEAR_WAR_ORPHAN_HIVEMIND, TIMER_STOPPABLE)
- orphan_hud_timer = new(null, get_all_xenos(), D.orphan_hive_timer, "Orphan Hivemind Collapse: ${timer}", 150, -80)
+ orphan_hud_timer = new(null, null, get_all_xenos(), D.orphan_hive_timer, "Orphan Hivemind Collapse: ${timer}", 150, -80)
/datum/hive_status/normal/burrow_larva(mob/living/carbon/xenomorph/larva/L)
if(!is_ground_level(L.z))
@@ -948,7 +956,7 @@ to_chat will check for valid clients itself already so no need to double check f
if(!length(possible_mothers))
if(length(possible_silos))
return attempt_to_spawn_larva_in_silo(xeno_candidate, possible_silos, larva_already_reserved)
- if(SSticker.mode?.flags_round_type & MODE_SILO_RESPAWN && !SSsilo.can_fire) // Distress mode & prior to shutters opening, so let the queue bypass silos if needed
+ if(SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN && !SSsilo.can_fire) // Distress mode & prior to shutters opening, so let the queue bypass silos if needed
return do_spawn_larva(xeno_candidate, pick(GLOB.spawns_by_job[/datum/job/xenomorph]), larva_already_reserved)
to_chat(xeno_candidate, span_warning("There are no places currently available to receive new larvas."))
return FALSE
@@ -976,7 +984,7 @@ to_chat will check for valid clients itself already so no need to double check f
xeno_candidate.mob.reset_perspective(chosen_silo)
var/double_check = tgui_alert(xeno_candidate.mob, "Spawn here?", "Spawn location", list("Yes","Pick another silo","Abort"), timeout = 20 SECONDS)
if(double_check == "Pick another silo")
- return attempt_to_spawn_larva_in_silo(xeno_candidate, possible_silos)
+ return attempt_to_spawn_larva_in_silo(xeno_candidate, possible_silos, larva_already_reserved)
else if(double_check != "Yes")
xeno_candidate.mob.reset_perspective(null)
remove_from_larva_candidate_queue(xeno_candidate)
@@ -1052,8 +1060,9 @@ to_chat will check for valid clients itself already so no need to double check f
continue
qdel(structure)
- if(SSticker.mode?.flags_round_type & MODE_PSY_POINTS_ADVANCED)
- SSpoints.xeno_points_by_hive[hivenumber] = SILO_PRICE + XENO_TURRET_PRICE //Give a free silo when going shipside and a turret
+ if(SSticker.mode?.round_type_flags & MODE_PSY_POINTS_ADVANCED)
+ SSpoints.xeno_strategic_points_by_hive[hivenumber] = SILO_PRICE //Give a free silo when going shipside and a turret
+ SSpoints.xeno_tactical_points_by_hive[hivenumber] = (XENO_TURRET_PRICE*4)
/datum/hive_status/normal/proc/on_hijack_depart(datum/source, new_mode)
@@ -1097,9 +1106,12 @@ to_chat will check for valid clients itself already so no need to double check f
var/list/possible_mothers = list()
var/list/possible_silos = list()
SEND_SIGNAL(src, COMSIG_HIVE_XENO_MOTHER_PRE_CHECK, possible_mothers, possible_silos)
- if(stored_larva > 0 && !LAZYLEN(candidates) && !XENODEATHTIME_CHECK(waiter.mob) && (length(possible_mothers) || length(possible_silos) || (SSticker.mode?.flags_round_type & MODE_SILO_RESPAWN && SSmonitor.gamestate == SHUTTERS_CLOSED)))
- attempt_to_spawn_larva(waiter)
- return
+ if(stored_larva > 0 && !LAZYLEN(candidates) && !XENODEATHTIME_CHECK(waiter.mob) && (length(possible_mothers) || length(possible_silos) || (SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN && SSmonitor.gamestate == SHUTTERS_CLOSED)))
+ xeno_job.occupy_job_positions(1)
+ if(!attempt_to_spawn_larva(waiter, TRUE))
+ xeno_job.free_job_positions(1)
+ return FALSE
+ return TRUE
if(LAZYFIND(candidates, waiter))
remove_from_larva_candidate_queue(waiter)
return FALSE
@@ -1130,7 +1142,7 @@ to_chat will check for valid clients itself already so no need to double check f
var/list/possible_mothers = list()
var/list/possible_silos = list()
SEND_SIGNAL(src, COMSIG_HIVE_XENO_MOTHER_PRE_CHECK, possible_mothers, possible_silos)
- if(!length(possible_mothers) && !length(possible_silos) && (!(SSticker.mode?.flags_round_type & MODE_SILO_RESPAWN) || SSsilo.can_fire))
+ if(!length(possible_mothers) && !length(possible_silos) && (!(SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN) || SSsilo.can_fire))
return
var/datum/job/xeno_job = SSjob.GetJobType(/datum/job/xenomorph)
var/stored_larva = round(xeno_job.total_positions - xeno_job.current_positions)
diff --git a/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm b/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm
index 8843d0f67fc15..a2f8bb8352bad 100644
--- a/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm
+++ b/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm
@@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
var/datum/hive_upgrade/upgrade = new type
if(upgrade.name == "Error upgrade") //defaultname just skip it its probably organisation
continue
- if(!(SSticker.mode.flags_xeno_abilities & upgrade.flags_gamemode))
+ if(!(SSticker.mode.xeno_abilities_flags & upgrade.gamemode_flags))
continue
buyable_upgrades += upgrade
upgrades_by_name[upgrade.name] = upgrade
@@ -54,8 +54,9 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
.["upgrades"] = list()
for(var/datum/hive_upgrade/upgrade AS in buyable_upgrades)
.["upgrades"] += list(list("name" = upgrade.name, "desc" = upgrade.desc, "category" = upgrade.category,\
- "cost" = upgrade.psypoint_cost, "times_bought" = upgrade.times_bought, "iconstate" = upgrade.icon))
- .["psypoints"] = SSpoints.xeno_points_by_hive[X.hive.hivenumber]
+ "cost" = upgrade.psypoint_cost, "times_bought" = upgrade.times_bought, "iconstate" = upgrade.icon, "istactical" = (upgrade.upgrade_flags & UPGRADE_FLAG_USES_TACTICAL)))
+ .["strategicpoints"] = SSpoints.xeno_strategic_points_by_hive[X.hive.hivenumber]
+ .["tacticalpoints"] = SSpoints.xeno_tactical_points_by_hive[X.hive.hivenumber]
/datum/hive_purchases/ui_static_data(mob/user)
. = ..()
@@ -73,7 +74,7 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
if(!upgrade.on_buy(user))
return
log_game("[key_name(user)] has purchased \a [upgrade] Blessing for [upgrade.psypoint_cost] psypoints for the [user.hive.hivenumber] hive")
- if(upgrade.flags_upgrade & UPGRADE_FLAG_MESSAGE_HIVE)
+ if(upgrade.upgrade_flags & UPGRADE_FLAG_MESSAGE_HIVE)
xeno_message("[user] has purchased \a [upgrade] Blessing", "xenoannounce", 5, user.hivenumber)
/datum/hive_upgrade
@@ -86,9 +87,9 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
///Psy point cost, float
var/psypoint_cost = 10
///upgrade flag var
- var/flags_upgrade = NONE
+ var/upgrade_flags = NONE
///gamemode flags to whether this upgrade is purchasable
- var/flags_gamemode = ABILITY_ALL_GAMEMODE
+ var/gamemode_flags = ABILITY_ALL_GAMEMODE
///int of the times we bought this upgrade
var/times_bought = 0
///string for UI icon in buyable_icons.dmi for this upgrade
@@ -102,7 +103,10 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
*/
/datum/hive_upgrade/proc/on_buy(mob/living/carbon/xenomorph/buyer)
SHOULD_CALL_PARENT(TRUE)
- SSpoints.xeno_points_by_hive[buyer.hivenumber] -= psypoint_cost
+ if(upgrade_flags & UPGRADE_FLAG_USES_TACTICAL)
+ SSpoints.xeno_tactical_points_by_hive[buyer.hivenumber] -= psypoint_cost
+ else
+ SSpoints.xeno_strategic_points_by_hive[buyer.hivenumber] -= psypoint_cost
times_bought++
/*RUTGMC EDIT begin */
if(buyer.status_flags & INCORPOREAL)
@@ -120,16 +124,19 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
*/
/datum/hive_upgrade/proc/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE)
SHOULD_CALL_PARENT(TRUE)
- if((flags_upgrade & UPGRADE_FLAG_ONETIME) && times_bought)
+ if((upgrade_flags & UPGRADE_FLAG_ONETIME) && times_bought)
+ if(!silent)
+ to_chat(buyer, span_xenowarning("You have already bought this blessing!"))
return FALSE
/*RUTGMC EDIT begin*/
if(buyer.status_flags & INCORPOREAL)
to_chat(buyer, span_xenowarning("You can't build in this form!"))
return FALSE
/*RUTGMC EDIT end*/
- if(SSpoints.xeno_points_by_hive[buyer.hivenumber] < psypoint_cost)
+ var/points_requirement = (upgrade_flags & UPGRADE_FLAG_USES_TACTICAL) ? SSpoints.xeno_tactical_points_by_hive[buyer.hivenumber] : SSpoints.xeno_strategic_points_by_hive[buyer.hivenumber]
+ if(points_requirement < psypoint_cost)
if(!silent)
- to_chat(buyer, span_xenowarning("You need [psypoint_cost-SSpoints.xeno_points_by_hive[buyer.hivenumber]] more points to request this blessing!"))
+ to_chat(buyer, span_xenowarning("You need [points_requirement] more [(upgrade_flags & UPGRADE_FLAG_USES_TACTICAL) ? "tactical" : "strategic"] points to request this blessing!"))
return FALSE
return TRUE
@@ -185,7 +192,7 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
desc = "Constructs a silo that generates xeno larvas over time. Requires open space and time to place."
psypoint_cost = SILO_PRICE
icon = "larvasilo"
- flags_upgrade = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
building_type = /obj/structure/xeno/silo
/* RUTGMC DELETION, SILO SCALING
@@ -212,10 +219,10 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
/* RU TGMC EDIT
/datum/hive_upgrade/building/evotower
name = "Evolution Tower"
- desc = "Constructs a tower that increases the rate of evolution point and maturity point generation by 1.2 times per tower."
+ desc = "Constructs a tower that increases the rate of evolution point generation by 0.2 and maturity point generation by 0.8 times per tower."
psypoint_cost = 300
icon = "evotower"
- flags_upgrade = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
building_type = /obj/structure/xeno/evotower
/datum/hive_upgrade/building/psychictower
@@ -223,7 +230,7 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list(
desc = "Constructs a tower that increases the slots of higher tier Xenomorphs."
psypoint_cost = 300
icon = "maturitytower"
- flags_upgrade = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
building_type = /obj/structure/xeno/psychictower
RU TGMC EDIT */
/datum/hive_upgrade/building/pherotower
@@ -231,7 +238,8 @@ RU TGMC EDIT */
desc = "Constructs a tower that emanates a selectable type of pheromone."
psypoint_cost = 150
icon = "pherotower"
- flags_upgrade = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
building_type = /obj/structure/xeno/pherotower
building_loc = 0 //This results in spawning the structure under the user.
building_time = 5 SECONDS
@@ -239,11 +247,35 @@ RU TGMC EDIT */
/datum/hive_upgrade/building/spawner
name = "Spawner"
desc = "Constructs a spawner that generates ai xenos over time"
- psypoint_cost = 600
+ psypoint_cost = 400
icon = "spawner"
- flags_upgrade = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
building_type = /obj/structure/xeno/spawner
+/datum/hive_upgrade/building/acid_pool
+ name = "acid pool"
+ desc = "Constructs a pool that allows xenos to regenerate sunder in it while resting. Requires open space and time to place."
+ psypoint_cost = 200
+ icon = "pool"
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
+ building_type = /obj/structure/xeno/acid_pool
+
+/datum/hive_upgrade/building/acid_pool/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE)
+ . = ..()
+ if(!.)
+ return
+
+ var/turf/buildloc = get_step(buyer, building_loc)
+ if(!buildloc)
+ return FALSE
+
+ if(buildloc.density)
+ if(!silent)
+ to_chat(buyer, span_xenowarning("You cannot build in a dense location!"))
+ return FALSE
+
/datum/hive_upgrade/defence
category = "Defences"
@@ -252,7 +284,8 @@ RU TGMC EDIT */
desc = "Places a acid spitting resin turret under you. Must be at least 6 tiles away from other turrets, not near fog and on a weeded area."
icon = "acidturret"
psypoint_cost = XENO_TURRET_PRICE
- flags_gamemode = ABILITY_NUCLEARWAR
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
///How long to build one turret
var/build_time = 10 SECONDS
///What type of turret is built
@@ -310,12 +343,74 @@ RU TGMC EDIT */
psypoint_cost = 50
turret_type = /obj/structure/xeno/xeno_turret/sticky
+/datum/hive_upgrade/defence/gargoyle
+ name = "Gargoyle"
+ desc = "Constructs a gargoyle that alerts you when enemies approach."
+ psypoint_cost = 25
+ icon = "gargoyle"
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
+
+/datum/hive_upgrade/defence/gargoyle/can_buy(mob/living/carbon/xenomorph/buyer, silent)
+ . = ..()
+ if(!.)
+ return
+ var/turf/buildloc = get_turf(buyer)
+ if(!buildloc)
+ return FALSE
+
+ if(!buildloc.is_weedable())
+ if(!silent)
+ to_chat(buyer, span_warning("We can't do that here."))
+ return FALSE
+
+ var/obj/alien/weeds/alien_weeds = locate() in buildloc
+
+ if(!alien_weeds)
+ if(!silent)
+ to_chat(buyer, span_warning("We can only shape on weeds. We must find some resin before we start building!"))
+ return FALSE
+
+ if(!buildloc.check_alien_construction(buyer, silent) || !buildloc.check_disallow_alien_fortification(buyer, silent))
+ return FALSE
+
+/datum/hive_upgrade/defence/gargoyle/on_buy(mob/living/carbon/xenomorph/buyer)
+ if(!do_after(buyer, 3 SECONDS, NONE, buyer, BUSY_ICON_BUILD))
+ return FALSE
+
+ if(!can_buy(buyer, FALSE))
+ return FALSE
+
+ var/turf/buildloc = get_turf(buyer)
+
+ var/atom/built = new /obj/structure/xeno/resin_gargoyle(buildloc, buyer.hivenumber, buyer)
+ to_chat(buyer, span_notice("We build [built] for [psypoint_cost] psy points."))
+ log_game("[buyer] has built \a [built] in [AREACOORD(buildloc)], spending [psypoint_cost] psy points in the process")
+ xeno_message("[buyer] has built \a [built] at [get_area(buildloc)]!", "xenoannounce", 5, buyer.hivenumber)
+ return ..()
+
+/datum/hive_upgrade/defence/special_walls
+ name = "Special Resin Walls"
+ desc = "Gives your hive 50 special resin walls to build."
+ psypoint_cost = 100
+ icon = "specialresin"
+ gamemode_flags = ABILITY_NUCLEARWAR
+ upgrade_flags = UPGRADE_FLAG_USES_TACTICAL
+
+/datum/hive_upgrade/defence/special_walls/on_buy(mob/living/carbon/xenomorph/buyer)
+ GLOB.hive_datums[buyer.get_xeno_hivenumber()].special_build_points += 50
+ to_chat(buyer, span_notice("We buy 50 special resin points for [psypoint_cost] psy points."))
+ log_game("[buyer] has purchased 50 special resin points, spending [psypoint_cost] psy points in the process.")
+ xeno_message("[buyer] has purchased 50 special resin points!", "xenoannounce", 5, buyer.hivenumber)
+
+ return ..()
+
/datum/hive_upgrade/xenos
category = "Xenos"
/datum/hive_upgrade/primordial
category = "Xenos"
- flags_upgrade = UPGRADE_FLAG_ONETIME|UPGRADE_FLAG_MESSAGE_HIVE
+ upgrade_flags = UPGRADE_FLAG_ONETIME|UPGRADE_FLAG_MESSAGE_HIVE
/datum/hive_upgrade/primordial/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE)
. = ..()
diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm
index 1b021f0022f5a..a733a905aa3c8 100644
--- a/code/modules/mob/living/carbon/xenomorph/life.dm
+++ b/code/modules/mob/living/carbon/xenomorph/life.dm
@@ -3,8 +3,6 @@
#define XENO_STANDING_HEAL 0.2
#define XENO_CRIT_DAMAGE 5
-#define XENO_HUD_ICON_BUCKETS 16 // should equal the number of icons you use to represent health / plasma (from 0 -> X)
-
/mob/living/carbon/xenomorph/Life()
if(!loc)
@@ -19,10 +17,10 @@
SSmobs.stop_processing(src)
return
if(stat == UNCONSCIOUS)
- if(is_zoomed)
+ if(xeno_flags & XENO_ZOOMED)
zoom_out()
else
- if(is_zoomed)
+ if(xeno_flags & XENO_ZOOMED)
if(!can_walk_zoomed)
if(loc != zoom_turf)
zoom_out()
@@ -54,14 +52,13 @@
handle_critical_health_updates()
return
if((health >= maxHealth) || on_fire) //can't regenerate.
- updatehealth() //Update health-related stats, like health itself (using brute and fireloss), health HUD and status.
return
var/turf/T = loc
if(!istype(T))
return
var/ruler_healing_penalty = 0.5
- if(hive?.living_xeno_ruler?.loc?.z == T.z || xeno_caste.can_flags & CASTE_CAN_HEAL_WITHOUT_QUEEN || (SSticker?.mode.flags_round_type & MODE_XENO_RULER)) //if the living queen's z-level is the same as ours.
+ if(hive?.living_xeno_ruler?.loc?.z == T.z || xeno_caste.can_flags & CASTE_CAN_HEAL_WITHOUT_QUEEN || (SSticker?.mode.round_type_flags & MODE_XENO_RULER)) //if the living queen's z-level is the same as ours.
ruler_healing_penalty = 1
if(loc_weeds_type || xeno_caste.caste_flags & CASTE_INNATE_HEALING) //We regenerate on weeds or can on our own.
if(lying_angle || resting || xeno_caste.caste_flags & CASTE_QUICK_HEAL_STANDING)
@@ -119,25 +116,23 @@
/mob/living/carbon/xenomorph/proc/handle_living_plasma_updates()
var/turf/T = loc
- if(!T || !istype(T))
+ if(!istype(T)) //This means plasma doesn't update while you're in things like a vent, but since you don't have weeds in a vent or can actually take advantage of pheros, this is fine
return
- if(plasma_stored >= xeno_caste.plasma_max * xeno_caste.plasma_regen_limit)
+
+ if(!current_aura && (plasma_stored >= xeno_caste.plasma_max * xeno_caste.plasma_regen_limit)) //no loss or gain
return
if(current_aura)
if(plasma_stored < pheromone_cost)
- use_plasma(plasma_stored)
+ use_plasma(plasma_stored, FALSE)
QDEL_NULL(current_aura)
src.balloon_alert(src, "Stop emitting, no plasma")
else
- use_plasma(pheromone_cost)
-
- if(HAS_TRAIT(src, TRAIT_NOPLASMAREGEN))
- hud_set_plasma()
- return
+ use_plasma(pheromone_cost, FALSE)
- if(!loc_weeds_type && !(xeno_caste.caste_flags & CASTE_INNATE_PLASMA_REGEN))
- hud_set_plasma() // since we used some plasma via the aura
+ if(HAS_TRAIT(src, TRAIT_NOPLASMAREGEN) || !loc_weeds_type && !(xeno_caste.caste_flags & CASTE_INNATE_PLASMA_REGEN))
+ if(current_aura) //we only need to update if we actually used plasma from pheros
+ hud_set_plasma()
return
var/plasma_gain = xeno_caste.plasma_gain
@@ -151,8 +146,9 @@
SEND_SIGNAL(src, COMSIG_XENOMORPH_PLASMA_REGEN, plasma_mod)
+ plasma_mod[1] = clamp(plasma_mod[1], 0, xeno_caste.plasma_max * xeno_caste.plasma_regen_limit - plasma_stored)
+
gain_plasma(plasma_mod[1])
- hud_set_plasma() //update plasma amount on the plasma mob_hud
/mob/living/carbon/xenomorph/can_receive_aura(aura_type, atom/source, datum/aura_bearer/bearer)
. = ..()
@@ -171,10 +167,10 @@
if(warding_aura != (received_auras[AURA_XENO_WARDING] || 0))
if(warding_aura) //If either the new or old warding is 0, we can skip adjusting armor for it.
- soft_armor = soft_armor.modifyAllRatings(-warding_aura * 2.5)
+ soft_armor = soft_armor.modifyAllRatings(-warding_aura * 1.5)
warding_aura = received_auras[AURA_XENO_WARDING] || 0
if(warding_aura)
- soft_armor = soft_armor.modifyAllRatings(warding_aura * 2.5)
+ soft_armor = soft_armor.modifyAllRatings(warding_aura * 1.5)
recovery_aura = received_auras[AURA_XENO_RECOVERY] || 0
@@ -182,37 +178,7 @@
..()
/mob/living/carbon/xenomorph/handle_regular_hud_updates()
- if(!client)
- return FALSE
-
- // Sanity checks
- if(!maxHealth)
- stack_trace("[src] called handle_regular_hud_updates() while having [maxHealth] maxHealth.")
- return
- if(!xeno_caste.plasma_max)
- stack_trace("[src] called handle_regular_hud_updates() while having [xeno_caste.plasma_max] xeno_caste.plasma_max.")
- return
-
- // Health Hud
- if(hud_used?.healths)
- if(stat != DEAD)
- var/bucket = get_bucket(XENO_HUD_ICON_BUCKETS, maxHealth, health, get_crit_threshold(), list("full", "critical"))
- hud_used.healths.icon_state = "health[bucket]"
- else
- hud_used.healths.icon_state = "health_dead"
-
- // Plasma Hud
- if(hud_used?.alien_plasma_display)
- if(stat != DEAD)
- var/bucket = get_bucket(XENO_HUD_ICON_BUCKETS, xeno_caste.plasma_max, plasma_stored, 0, list("full", "empty"))
- hud_used.alien_plasma_display.icon_state = "power_display_[bucket]"
- else
- hud_used.alien_plasma_display.icon_state = "power_display_empty"
-
-
- interactee?.check_eye(src)
-
- return TRUE
+ return
/mob/living/carbon/xenomorph/proc/handle_environment() //unused while atmos is not on
var/env_temperature = loc.return_temperature()
@@ -234,7 +200,7 @@
stat = CONSCIOUS
return
health = maxHealth - getFireLoss() - getBruteLoss() //Xenos can only take brute and fire damage.
- med_hud_set_health()
+ med_hud_set_health() //todo: Make all damage update health so we can just kill pointless life updates entirely
update_stat()
update_wounds()
diff --git a/code/modules/mob/living/carbon/xenomorph/say.dm b/code/modules/mob/living/carbon/xenomorph/say.dm
index 31f2ea04cea50..5488227d915e0 100644
--- a/code/modules/mob/living/carbon/xenomorph/say.dm
+++ b/code/modules/mob/living/carbon/xenomorph/say.dm
@@ -5,7 +5,7 @@
This is also paired with [/mob/living/carbon/xenomorph/hivemind_end]
*/
/mob/living/carbon/xenomorph/proc/hivemind_start()
- return "Hivemind, [span_name("[name]")]"
+ return "Hivemind, [span_name("[name]")]"
/**
Called to create the suffix for xeno hivemind messages
@@ -56,7 +56,7 @@
if(!S?.client?.prefs || !(S.client.prefs.toggles_chat & CHAT_GHOSTHIVEMIND))
continue
var/track = FOLLOW_LINK(S, src)
- S.show_message("[track] [hivemind_start()] [span_message("hisses, '[message]'")][hivemind_end()]", 2)
+ S.show_message("[track] [hivemind_start()] [span_message("hisses, '[message]'")][hivemind_end()]", 2)
hive.hive_mind_message(src, message)
@@ -64,7 +64,7 @@
/mob/living/carbon/xenomorph/proc/receive_hivemind_message(mob/living/carbon/xenomorph/X, message)
var/follow_link = X != src ? "(F) " : ""
- show_message("[follow_link][X.hivemind_start()][span_message(" hisses, '[message]'")][X.hivemind_end()]", 2)
+ show_message("[follow_link][X.hivemind_start()][span_message(" hisses, '[message]'")][X.hivemind_end()]", 2)
/mob/living/carbon/xenomorph/get_saymode(message, talk_key)
diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm
index fdcfa5c149f06..c30a64881e9a6 100644
--- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm
+++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm
@@ -20,28 +20,25 @@
update_icons()
/mob/living/carbon/xenomorph/update_icons(state_change = TRUE)
- if(HAS_TRAIT(src, TRAIT_MOB_ICON_UPDATE_BLOCKED))
- return
+ SEND_SIGNAL(src, COMSIG_XENOMORPH_UPDATE_ICONS, state_change)
if(state_change)
if(stat == DEAD)
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Dead"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Dead"
else if(HAS_TRAIT(src, TRAIT_BURROWED))
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Burrowed"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Burrowed"
else if(lying_angle)
if((resting || IsSleeping()) && (!IsParalyzed() && !IsUnconscious() && health > 0))
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Sleeping"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Sleeping"
else
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Knocked Down"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Knocked Down"
else if(!handle_special_state())
if(m_intent == MOVE_INTENT_RUN)
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Running"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Running"
else
- icon_state = "[xeno_caste.caste_name][is_a_rouny ? " rouny" : ""] Walking"
+ icon_state = "[xeno_caste.caste_name][(xeno_flags & XENO_ROUNY) ? " rouny" : ""] Walking"
update_fire() //the fire overlay depends on the xeno's stance, so we must update it.
update_wounds()
- hud_set_plasma()
- med_hud_set_health()
hud_set_sunder()
hud_set_firestacks()
@@ -53,33 +50,33 @@
update_icons()
/mob/living/carbon/xenomorph/update_inv_r_hand()
- remove_overlay(X_R_HAND_LAYER)
+ remove_overlay(R_HAND_LAYER)
if(r_hand)
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
r_hand.screen_loc = ui_rhand
client.screen += r_hand
- overlays_standing[X_R_HAND_LAYER] = r_hand.make_worn_icon(inhands = TRUE, slot_name = slot_r_hand_str, default_icon = 'icons/mob/items_righthand_1.dmi', default_layer = X_R_HAND_LAYER)
- apply_overlay(X_R_HAND_LAYER)
+ overlays_standing[R_HAND_LAYER] = r_hand.make_worn_icon(inhands = TRUE, slot_name = slot_r_hand_str, default_icon = 'icons/mob/inhands/items/items_right.dmi', default_layer = R_HAND_LAYER)
+ apply_overlay(R_HAND_LAYER)
/mob/living/carbon/xenomorph/update_inv_l_hand()
- remove_overlay(X_L_HAND_LAYER)
+ remove_overlay(L_HAND_LAYER)
if(l_hand)
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
l_hand.screen_loc = ui_lhand
client.screen += l_hand
- overlays_standing[X_L_HAND_LAYER] = l_hand.make_worn_icon(inhands = TRUE, slot_name = slot_l_hand_str, default_icon = 'icons/mob/items_lefthand_1.dmi', default_layer = X_L_HAND_LAYER)
- apply_overlay(X_L_HAND_LAYER)
+ overlays_standing[L_HAND_LAYER] = l_hand.make_worn_icon(inhands = TRUE, slot_name = slot_l_hand_str, default_icon = 'icons/mob/inhands/items/items_left.dmi', default_layer = L_HAND_LAYER)
+ apply_overlay(L_HAND_LAYER)
/*
/mob/living/carbon/xenomorph/proc/create_shriekwave()
- overlays_standing[X_SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "shriek_waves") //Ehh, suit layer's not being used.
- apply_temp_overlay(X_SUIT_LAYER, 3 SECONDS)
+ overlays_standing[SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "shriek_waves") //Ehh, suit layer's not being used.
+ apply_temp_overlay(SUIT_LAYER, 3 SECONDS)
*/
/mob/living/carbon/xenomorph/proc/create_stomp()
- overlays_standing[X_SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "stomp") //Ehh, suit layer's not being used.
- apply_temp_overlay(X_SUIT_LAYER, 1.2 SECONDS)
+ overlays_standing[SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "stomp") //Ehh, suit layer's not being used.
+ apply_temp_overlay(SUIT_LAYER, 1.2 SECONDS)
/mob/living/carbon/xenomorph/update_fire()
if(!fire_overlay)
@@ -95,14 +92,14 @@
if(QDELETED(src))
return
- remove_overlay(X_WOUND_LAYER)
+ remove_overlay(WOUND_LAYER)
remove_filter("wounded_filter")
var/health_thresholds
wound_overlay.layer = layer + 0.3
wound_overlay.icon = src.icon
wound_overlay.vis_flags |= VIS_HIDE
- if(HAS_TRAIT(src, TRAIT_MOB_ICON_UPDATE_BLOCKED))
+ if(HAS_TRAIT(src, TRAIT_XENOMORPH_INVISIBLE_BLOOD))
wound_overlay.icon_state = "none"
return
if(health > health_threshold_crit)
@@ -134,8 +131,8 @@
if(xeno_caste.caste_flags & CASTE_HAS_WOUND_MASK)
var/image/wounded_mask = image(icon, null, "alpha_[overlay_to_show]")
wounded_mask.render_target = "*[REF(src)]"
- overlays_standing[X_WOUND_LAYER] = wounded_mask
- apply_overlay(X_WOUND_LAYER)
+ overlays_standing[WOUND_LAYER] = wounded_mask
+ apply_overlay(WOUND_LAYER)
add_filter("wounded_filter", 1, alpha_mask_filter(0, 0, null, "*[REF(src)]", MASK_INVERSE))
wound_overlay.vis_flags &= ~VIS_HIDE // Show the overlay
@@ -175,6 +172,7 @@
update_flame_light(owner.fire_luminosity)
/atom/movable/vis_obj/xeno_wounds/fire_overlay/update_icon_state()
+ . = ..()
if(!owner.on_fire)
icon_state = ""
return
diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm
index 6f2f6d125b12f..b1eeefe62821d 100644
--- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm
+++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm
@@ -22,6 +22,8 @@
// *** Melee Attacks *** //
///The amount of damage a xenomorph caste will do with a 'slash' attack.
var/melee_damage = 10
+ ///The amount of armour pen their melee attacks have
+ var/melee_ap = 0
///number of ticks between attacks for a caste.
var/attack_delay = CLICK_CD_MELEE
@@ -61,8 +63,6 @@
///Threshold amount of upgrade points to next maturity
//var/upgrade_threshold = 0 // RUTGMC DELETION
- ///Type paths to the castes that this xenomorph can evolve to
- var/list/evolves_to = list()
///Singular type path for the caste to deevolve to when forced to by the queen.
var/deevolves_to
@@ -92,6 +92,8 @@
var/sunder_recover = 0.5
///What is the max amount of sunder that can be applied to a xeno (100 = 100%)
var/sunder_max = 100
+ ///Multiplier on the weapons sunder, e.g 10 sunder on a projectile is reduced to 5 with a 0.5 multiplier.
+ var/sunder_multiplier = 1
// *** Ranged Attack *** //
///Delay timer for spitting
@@ -225,6 +227,8 @@ RU TGMC EDIT */
var/evolve_min_xenos = 0
// How many of this caste may be alive at once
var/maximum_active_caste = INFINITY
+ // Accuracy malus, 0 by default. Should NOT go over 70.
+ var/accuracy_malus = 0
///Add needed component to the xeno
/datum/xeno_caste/proc/on_caste_applied(mob/xenomorph)
@@ -279,11 +283,11 @@ RU TGMC EDIT */
///Hive datum we belong to
var/datum/hive_status/hive
///Xeno mob specific flags
- var/xeno_flags = NONE //TODO: There are loads of vars below that should be flags
+ var/xeno_flags = NONE
+
///State tracking of hive status toggles
var/status_toggle_flags = HIVE_STATUS_DEFAULTS
- var/list/overlays_standing[X_TOTAL_LAYERS]
var/atom/movable/vis_obj/xeno_wounds/wound_overlay
var/atom/movable/vis_obj/xeno_wounds/fire_overlay/fire_overlay
var/datum/xeno_caste/xeno_caste
@@ -322,18 +326,17 @@ RU TGMC EDIT */
///Increases by xeno_caste.regen_ramp_amount every decisecond. If you want to balance this, look at the xeno_caste defines mentioned above.
var/regen_power = 0
- var/is_zoomed = 0
var/zoom_turf = null
var/can_walk_zoomed = FALSE
///Type of weeds the xeno is standing on, null when not on weeds
var/obj/alien/weeds/loc_weeds_type
- ///Bonus or pen to time in between attacks. + makes slashes slower.
- var/attack_delay = 0
///This will track their "tier" to restrict/limit evolutions
var/tier = XENO_TIER_ONE
///which resin structure to build when we secrete resin
var/selected_resin = /turf/closed/wall/resin/regenerating
+ //which special resin structure to build when we secrete special resin
+ var/selected_special_resin = /turf/closed/wall/resin/regenerating/special/bulletproof
///which reagent to slash with using reagent slash
var/selected_reagent = /datum/reagent/toxin/xeno_hemodile
///which plant to place when we use sow
@@ -351,18 +354,11 @@ RU TGMC EDIT */
///Multiplicative melee damage modifier; referenced by attack_alien.dm, most notably attack_alien_harm
var/xeno_melee_damage_modifier = 1
- ///whether the xeno mobhud is activated or not.
- var/xeno_mobhud = FALSE
- ///whether the xeno has been selected by the queen as a leader.
- var/queen_chosen_lead = FALSE
//Charge vars
///Will the mob charge when moving ? You need the charge verb to change this
var/is_charging = CHARGE_OFF
- //Pounce vars
- var/usedPounce = 0
-
// Gorger vars
var/overheal = 0
@@ -401,10 +397,12 @@ RU TGMC EDIT */
///The xenos/silo/nuke currently tracked by the xeno_tracker arrow
var/atom/tracked
- ///Are we the roony version of this xeno
- var/is_a_rouny = FALSE
-
/// The type of footstep this xeno has.
var/footstep_type = FOOTSTEP_XENO_MEDIUM
COOLDOWN_DECLARE(xeno_health_alert_cooldown)
+
+ ///The resting cooldown
+ COOLDOWN_DECLARE(xeno_resting_cooldown)
+ ///The unresting cooldown
+ COOLDOWN_DECLARE(xeno_unresting_cooldown)
diff --git a/code/modules/mob/living/carbon/xenomorph/xenoattacks.dm b/code/modules/mob/living/carbon/xenomorph/xenoattacks.dm
index 2ca62e972e7cc..b6b812c508e13 100644
--- a/code/modules/mob/living/carbon/xenomorph/xenoattacks.dm
+++ b/code/modules/mob/living/carbon/xenomorph/xenoattacks.dm
@@ -69,66 +69,67 @@
//Hot hot Aliens on Aliens action.
//Actually just used for eating people.
-/mob/living/carbon/xenomorph/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(status_flags & INCORPOREAL || X.status_flags & INCORPOREAL) //Incorporeal xenos cannot attack or be attacked
+/mob/living/carbon/xenomorph/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(status_flags & INCORPOREAL || xeno_attacker.status_flags & INCORPOREAL) //Incorporeal xenos cannot attack or be attacked
return
- if(src == X)
+ if(src == xeno_attacker)
return TRUE
-
- if(isxenolarva(X)) //Larvas can't eat people
- X.visible_message(span_danger("[X] nudges its head against \the [src]."), \
+
+ if(isxenolarva(xeno_attacker)) //Larvas can't eat people
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] nudges its head against \the [src]."), \
span_danger("We nudge our head against \the [src]."))
return FALSE
- switch(X.a_intent)
+ switch(xeno_attacker.a_intent)
if(INTENT_HELP)
if(on_fire)
fire_stacks = max(fire_stacks - 1, 0)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 25, 1, 7)
- X.visible_message(span_danger("[X] tries to put out the fire on [src]!"), \
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] tries to put out the fire on [src]!"), \
span_warning("We try to put out the fire on [src]!"), null, 5)
if(fire_stacks <= 0)
- X.visible_message(span_danger("[X] has successfully extinguished the fire on [src]!"), \
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] has successfully extinguished the fire on [src]!"), \
span_notice("We extinguished the fire on [src]."), null, 5)
ExtinguishMob()
return TRUE
- X.visible_message(span_notice("\The [X] caresses \the [src] with its scythe-like arm."), \
+
+ xeno_attacker.visible_message(span_notice("\The [xeno_attacker] caresses \the [src] with its scythe-like arm."), \
span_notice("We caress \the [src] with our scythe-like arm."), null, 5)
if(INTENT_GRAB)
if(anchored)
return FALSE
- if(!X.start_pulling(src))
+ if(!xeno_attacker.start_pulling(src))
return FALSE
- X.visible_message(span_warning("[X] grabs \the [src]!"), \
+ xeno_attacker.visible_message(span_warning("[xeno_attacker] grabs \the [src]!"), \
span_warning("We grab \the [src]!"), null, 5)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 25, 1, 7)
if(INTENT_HARM, INTENT_DISARM)//Can't slash other xenos for now. SORRY // You can now! --spookydonut
- if(issamexenohive(X))
- X.do_attack_animation(src)
- X.visible_message(span_warning("\The [X] nibbles \the [src]."), \
+ if(issamexenohive(xeno_attacker))
+ xeno_attacker.do_attack_animation(src)
+ xeno_attacker.visible_message(span_warning("\The [xeno_attacker] nibbles \the [src]."), \
span_warning("We nibble \the [src]."), null, 5)
return TRUE
// Not at the base of the proc otherwise we can just nibble for free slashing effects
- SEND_SIGNAL(X, COMSIG_XENOMORPH_ATTACK_HOSTILE_XENOMORPH, src, damage_amount, X.xeno_caste.melee_damage * X.xeno_melee_damage_modifier)
+ SEND_SIGNAL(xeno_attacker, COMSIG_XENOMORPH_ATTACK_HOSTILE_XENOMORPH, src, damage_amount, xeno_attacker.xeno_caste.melee_damage * xeno_attacker.xeno_melee_damage_modifier)
// copypasted from attack_alien.dm
//From this point, we are certain a full attack will go out. Calculate damage and modifiers
- var/damage = X.xeno_caste.melee_damage
+ var/damage = xeno_attacker.xeno_caste.melee_damage
//Somehow we will deal no damage on this attack
if(!damage)
- X.do_attack_animation(src)
- playsound(X.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
- X.visible_message(span_danger("\The [X] lunges at [src]!"), \
+ xeno_attacker.do_attack_animation(src)
+ playsound(xeno_attacker.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] lunges at [src]!"), \
span_danger("We lunge at [src]!"), null, 5)
return FALSE
- X.visible_message(span_danger("\The [X] slashes [src]!"), \
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] slashes [src]!"), \
span_danger("We slash [src]!"), null, 5)
- log_combat(X, src, "slashed")
+ log_combat(xeno_attacker, src, "slashed")
- X.do_attack_animation(src, ATTACK_EFFECT_REDSLASH)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_REDSLASH)
playsound(loc, "alien_claw_flesh", 25, 1)
apply_damage(damage, BRUTE, blocked = MELEE, updating_health = TRUE)
diff --git a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm
index bbed0e3066a30..cea1d56235bb1 100644
--- a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm
+++ b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm
@@ -5,7 +5,6 @@
//This is so they can be easily transferred between them without copypasta
/mob/living/carbon/xenomorph/Initialize(mapload)
- setup_verbs()
if(mob_size == MOB_SIZE_BIG)
move_resist = MOVE_FORCE_EXTREMELY_STRONG
move_force = MOVE_FORCE_EXTREMELY_STRONG
@@ -55,10 +54,6 @@
regenerate_icons()
- hud_set_plasma()
- med_hud_set_health()
- hud_update_primo()
-
toggle_xeno_mobhud() //This is a verb, but fuck it, it just werks
update_spits()
@@ -81,6 +76,7 @@
AddElement(/datum/element/footstep, footstep_type, mob_size >= MOB_SIZE_BIG ? 0.8 : 0.5)
set_jump_component()
+ AddComponent(/datum/component/seethrough_mob)
/mob/living/carbon/xenomorph/register_init_signals()
. = ..()
@@ -109,7 +105,7 @@
maxHealth = xeno_caste.max_health * GLOB.xeno_stat_multiplicator_buff
if(restore_health_and_plasma)
// xenos that manage plasma through special means shouldn't gain it for free on aging
- plasma_stored = max(plasma_stored, xeno_caste.plasma_max * xeno_caste.plasma_regen_limit)
+ set_plasma(max(plasma_stored, xeno_caste.plasma_max * xeno_caste.plasma_regen_limit))
health = maxHealth
setXenoCasteSpeed(xeno_caste.speed)
@@ -156,17 +152,17 @@
var/rank_name
switch(playtime_mins)
if(0 to 600)
- rank_name = "Hatchling"
- if(601 to 1500) //10 hours
rank_name = "Young"
- if(1501 to 4200) //25 hours
+ if(601 to 1500) //10 hours
rank_name = "Mature"
- if(4201 to 10500) //70 hours
+ if(1501 to 4200) //25 hours
rank_name = "Elder"
- if(10501 to INFINITY) //175 hours
+ if(4201 to 10500) //70 hours
rank_name = "Ancient"
+ if(10501 to INFINITY) //175 hours
+ rank_name = "Prime"
else
- rank_name = "Hatchling"
+ rank_name = "Young"
var/prefix = (hive.prefix || xeno_caste.upgrade_name) ? "[hive.prefix][xeno_caste.upgrade_name] " : ""
name = prefix + "[rank_name ? "[rank_name] " : ""][xeno_caste.display_name] ([nicknumber])"
@@ -245,9 +241,10 @@
/mob/living/carbon/xenomorph/examine(mob/user)
. = ..()
. += xeno_caste.caste_desc
+ . += ""
if(stat == DEAD)
- . += "It is DEAD. Kicked the bucket. Off to that great hive in the sky."
+ . += "It is DEAD. Kicked the bucket. Off to that great hive in the sky."
else if(stat == UNCONSCIOUS)
. += "It quivers a bit, but barely moves."
else
@@ -264,6 +261,8 @@
if(1 to 24)
. += "It is heavily injured and limping badly."
+ . += ""
+
if(hivenumber != XENO_HIVE_NORMAL)
var/datum/hive_status/hive = GLOB.hive_datums[hivenumber]
. += "It appears to belong to the [hive.prefix]hive"
@@ -271,7 +270,8 @@
/mob/living/carbon/xenomorph/Destroy()
if(mind) mind.name = name //Grabs the name when the xeno is getting deleted, to reference through hive status later.
- if(is_zoomed) zoom_out()
+ if(xeno_flags & XENO_ZOOMED)
+ zoom_out()
GLOB.alive_xeno_list -= src
LAZYREMOVE(GLOB.alive_xeno_list_hive[hivenumber], src)
@@ -415,7 +415,7 @@
/mob/living/carbon/xenomorph/Moved(atom/old_loc, movement_dir)
- if(is_zoomed)
+ if(xeno_flags & XENO_ZOOMED)
if(!can_walk_zoomed)
zoom_out()
handle_weeds_on_movement()
@@ -471,23 +471,38 @@ Returns TRUE when loc_weeds_type changes. Returns FALSE when it doesn’t change
return
update_icon()
-/mob/living/carbon/xenomorph/lay_down()
+/mob/living/carbon/xenomorph/toggle_resting()
var/datum/action/ability/xeno_action/xeno_resting/resting_action = actions_by_path[/datum/action/ability/xeno_action/xeno_resting]
if(!resting_action || !resting_action.can_use_action())
return
+ if(resting)
+ if(!COOLDOWN_CHECK(src, xeno_resting_cooldown))
+ balloon_alert(src, "Cannot get up so soon after resting!")
+ return
+
+ if(!COOLDOWN_CHECK(src, xeno_unresting_cooldown))
+ balloon_alert(src, "Cannot rest so soon after getting up!")
+ return
return ..()
-/mob/living/carbon/xenomorph/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE)
+/mob/living/carbon/xenomorph/set_resting()
+ . = ..()
+ if(resting)
+ COOLDOWN_START(src, xeno_resting_cooldown, XENO_RESTING_COOLDOWN)
+ else
+ COOLDOWN_START(src, xeno_unresting_cooldown, XENO_UNRESTING_COOLDOWN)
+
+/mob/living/carbon/xenomorph/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK)
var/gravity = get_gravity()
if(gravity < 1) //low grav
duration *= 2.5 - gravity
cooldown *= 2 - gravity
height *= 2 - gravity
if(gravity <= 0.75)
- flags_pass |= PASS_DEFENSIVE_STRUCTURE
+ pass_flags |= PASS_DEFENSIVE_STRUCTURE
else if(gravity > 1) //high grav
duration *= gravity * 0.5
cooldown *= gravity
height *= gravity * 0.5
- AddComponent(/datum/component/jump, _jump_duration = duration, _jump_cooldown = cooldown, _stamina_cost = 0, _jump_height = height, _jump_sound = sound, _jump_flags = flags, _jumper_allow_pass_flags = flags_pass)
+ AddComponent(/datum/component/jump, _jump_duration = duration, _jump_cooldown = cooldown, _stamina_cost = 0, _jump_height = height, _jump_sound = sound, _jump_flags = flags, _jumper_allow_pass_flags = pass_flags)
diff --git a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm
index 1fcb5053c17fb..12f63918e1b11 100644
--- a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm
+++ b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm
@@ -135,7 +135,15 @@
. += "Sunder: [100-sunder]% armor left"
- //Very weak <= 1.0, weak <= 2.0, no modifier 2-3, strong <= 3.5, very strong <= 4.5
+ . += "Regeneration power: [max(regen_power * 100, 0)]%"
+
+ var/casteswap_value = ((GLOB.key_to_time_of_caste_swap[key] ? GLOB.key_to_time_of_caste_swap[key] : -INFINITY) + 15 MINUTES - world.time) * 0.1
+ if(casteswap_value <= 0)
+ . += "Caste Swap Timer: READY"
+ else
+ . += "Caste Swap Timer: [(casteswap_value / 60) % 60]:[add_leading(num2text(casteswap_value % 60), 2, "0")]"
+
+ //Very weak <= 1.0, Weak <= 2.0, Medium < 3.0, Strong < 4.0, Very strong >= 4.0
var/msg_holder = ""
if(frenzy_aura)
switch(frenzy_aura)
@@ -149,7 +157,7 @@
msg_holder = "Strong"
if(4.0 to INFINITY)
msg_holder = "Very strong"
- . += "[AURA_XENO_FRENZY] pheromone strength: [msg_holder]"
+ . += "[AURA_XENO_FRENZY] pheromone strength: [msg_holder] ([frenzy_aura])"
if(warding_aura)
switch(warding_aura)
if(-INFINITY to 1.0)
@@ -162,7 +170,7 @@
msg_holder = "Strong"
if(4.0 to INFINITY)
msg_holder = "Very strong"
- . += "[AURA_XENO_WARDING] pheromone strength: [msg_holder]"
+ . += "[AURA_XENO_WARDING] pheromone strength: [msg_holder] ([warding_aura])"
if(recovery_aura)
switch(recovery_aura)
if(-INFINITY to 1.0)
@@ -175,7 +183,7 @@
msg_holder = "Strong"
if(4.0 to INFINITY)
msg_holder = "Very strong"
- . += "[AURA_XENO_RECOVERY] pheromone strength: [msg_holder]"
+ . += "[AURA_XENO_RECOVERY] pheromone strength: [msg_holder] ([recovery_aura])"
//A simple handler for checking your state. Used in pretty much all the procs.
/mob/living/carbon/xenomorph/proc/check_state()
@@ -191,16 +199,25 @@
return FALSE
return TRUE
-/mob/living/carbon/xenomorph/proc/use_plasma(value)
+/mob/living/carbon/xenomorph/proc/set_plasma(value, update_plasma = TRUE)
+ plasma_stored = clamp(value, 0, xeno_caste.plasma_max)
+ if(!update_plasma)
+ return
+ hud_set_plasma()
+
+/mob/living/carbon/xenomorph/proc/use_plasma(value, update_plasma = TRUE)
plasma_stored = max(plasma_stored - value, 0)
update_action_button_icons()
+ if(!update_plasma)
+ return
+ hud_set_plasma()
-/mob/living/carbon/xenomorph/proc/gain_plasma(value)
+/mob/living/carbon/xenomorph/proc/gain_plasma(value, update_plasma = TRUE)
plasma_stored = min(plasma_stored + value, xeno_caste.plasma_max)
update_action_button_icons()
-
-
-
+ if(!update_plasma)
+ return
+ hud_set_plasma()
//Strip all inherent xeno verbs from your caste. Used in evolution.
/mob/living/carbon/xenomorph/proc/remove_inherent_verbs()
@@ -230,7 +247,7 @@
// Upgrade is increased based on marine to xeno population taking stored_larva as a modifier.
var/datum/job/xeno_job = SSjob.GetJobType(/datum/job/xenomorph)
var/stored_larva = xeno_job.total_positions - xeno_job.current_positions
- upgrade_stored += 1 + (stored_larva/6) + hive.get_evolution_boost() //Do this regardless of whether we can upgrade so age accrues at primo
+ upgrade_stored += 1 + (stored_larva/6) + hive.get_upgrade_boost() //Do this regardless of whether we can upgrade so age accrues at primo
if(!upgrade_possible())
return
if(upgrade_stored < xeno_caste.upgrade_threshold)
@@ -312,17 +329,16 @@
/mob/living/carbon/xenomorph/proc/zoom_in(tileoffset = 5, viewsize = 4.5) //RU TGMC EDIT
if(stat || resting)
- if(is_zoomed)
- is_zoomed = 0
+ if(xeno_flags & XENO_ZOOMED)
zoom_out()
return
return
- if(is_zoomed)
+ if(xeno_flags & XENO_ZOOMED)
return
if(!client)
return
zoom_turf = get_turf(src)
- is_zoomed = 1
+ xeno_flags |= XENO_ZOOMED
client.view_size.set_view_radius_to(viewsize) //convert diameter to radius
var/viewoffset = 32 * tileoffset
switch(dir)
@@ -340,7 +356,7 @@
client.pixel_y = 0
/mob/living/carbon/xenomorph/proc/zoom_out()
- is_zoomed = 0
+ xeno_flags &= ~XENO_ZOOMED
zoom_turf = null
if(!client)
return
@@ -363,7 +379,7 @@
//When the Queen's pheromones are updated, or we add/remove a leader, update leader pheromones
/mob/living/carbon/xenomorph/proc/handle_xeno_leader_pheromones(mob/living/carbon/xenomorph/queen/Q)
QDEL_NULL(leader_current_aura)
- if(QDELETED(Q) || !queen_chosen_lead || !Q.current_aura || Q.loc.z != loc.z) //We are no longer a leader, or the Queen attached to us has dropped from her ovi, disabled her pheromones or even died
+ if(QDELETED(Q) || !(xeno_flags & XENO_LEADER) || !Q.current_aura || Q.loc.z != loc.z) //We are no longer a leader, or the Queen attached to us has dropped from her ovi, disabled her pheromones or even died
to_chat(src, span_xenowarning("Our pheromones wane. The Queen is no longer granting us her pheromones."))
else
leader_current_aura = SSaura.add_emitter(src, Q.current_aura.aura_types.Copy(), Q.current_aura.range, Q.current_aura.strength, Q.current_aura.duration, Q.current_aura.faction, Q.current_aura.hive_number)
@@ -398,11 +414,6 @@
take_damage(2 * X.xeno_caste.acid_spray_structure_damage, BURN, ACID)
return FALSE // not normal density flag
-/obj/vehicle/multitile/root/cm_armored/acid_spray_act(mob/living/carbon/xenomorph/X)
- take_damage_type(X.xeno_caste.acid_spray_structure_damage, ACID, src)
- healthcheck()
- return TRUE
-
/mob/living/carbon/acid_spray_act(mob/living/carbon/xenomorph/X)
ExtinguishMob()
if(isnestedhost(src))
@@ -432,7 +443,11 @@
ExtinguishMob()
/obj/flamer_fire/acid_spray_act(mob/living/carbon/xenomorph/X)
- Destroy()
+ qdel(src)
+
+/obj/hitbox/acid_spray_act(mob/living/carbon/xenomorph/X)
+ take_damage(X.xeno_caste.acid_spray_structure_damage, BURN, ACID)
+ return TRUE
// Vent Crawl
/mob/living/carbon/xenomorph/proc/vent_crawl()
@@ -450,13 +465,13 @@
set desc = "Toggles the health and plasma hud appearing above Xenomorphs."
set category = "Alien"
- xeno_mobhud = !xeno_mobhud
+ xeno_flags ^= XENO_MOBHUD
var/datum/atom_hud/H = GLOB.huds[DATA_HUD_XENO_STATUS]
- if(xeno_mobhud)
+ if(xeno_flags & XENO_MOBHUD)
H.add_hud_to(src)
else
H.remove_hud_from(src)
- to_chat(src, span_notice("You have [xeno_mobhud ? "enabled" : "disabled"] the Xeno Status HUD."))
+ to_chat(src, span_notice("You have [(xeno_flags & XENO_MOBHUD) ? "enabled" : "disabled"] the Xeno Status HUD."))
/mob/living/carbon/xenomorph/proc/recurring_injection(mob/living/carbon/C, datum/reagent/toxin = /datum/reagent/toxin/xeno_neurotoxin, channel_time = XENO_NEURO_CHANNEL_TIME, transfer_amount = XENO_NEURO_AMOUNT_RECURRING, count = 4)
@@ -490,17 +505,12 @@
return TRUE
return FALSE
-/mob/living/carbon/xenomorph/proc/setup_verbs()
- add_verb(src, /mob/living/proc/lay_down)
-
-/mob/living/carbon/xenomorph/hivemind/setup_verbs()
- return
-
/mob/living/carbon/xenomorph/adjust_sunder(adjustment)
. = ..()
if(.)
return
- sunder = clamp(sunder + adjustment, 0, xeno_caste.sunder_max)
+ sunder = clamp(sunder + (adjustment > 0 ? adjustment * xeno_caste.sunder_multiplier : adjustment), 0, xeno_caste.sunder_max)
+//Applying sunder is an adjustment value above 0, healing sunder is an adjustment value below 0. Use multiplier when taking sunder, not when healing.
/mob/living/carbon/xenomorph/set_sunder(new_sunder)
. = ..()
diff --git a/code/modules/mob/living/carbon/xenomorph/xenoupgrade.dm b/code/modules/mob/living/carbon/xenomorph/xenoupgrade.dm
index c642082b6cb48..7fa2cb9f9bbbf 100644
--- a/code/modules/mob/living/carbon/xenomorph/xenoupgrade.dm
+++ b/code/modules/mob/living/carbon/xenomorph/xenoupgrade.dm
@@ -25,7 +25,7 @@
if(found)
continue
var/datum/action/ability/xeno_action/action = new allowed_action_path()
- if(!SSticker.mode || (SSticker.mode.flags_xeno_abilities & action.gamemode_flags))
+ if(!SSticker.mode || (SSticker.mode.xeno_abilities_flags & action.gamemode_flags))
action.give_action(src)
for(var/datum/action/ability/xeno_action/action_already_added AS in actions_already_added)
@@ -39,7 +39,7 @@
activable_ability.select()
break
- if(queen_chosen_lead)
+ if(xeno_flags & XENO_LEADER)
give_rally_abilities() //Give them back their rally hive ability
if(current_aura) //Updates pheromone strength
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index af09465c5c4be..a9624e0e360cf 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -98,6 +98,7 @@
set_armor_datum()
AddElement(/datum/element/gesture)
AddElement(/datum/element/keybinding_update)
+ AddElement(/datum/element/directional_attack)
/mob/living/Destroy()
for(var/datum/status_effect/effect AS in status_effects)
@@ -130,48 +131,8 @@
return
-/mob/proc/get_contents()
- return
-
-
-//Recursive function to find everything a mob is holding.
-/mob/living/get_contents(obj/item/storage/Storage = null)
- var/list/L = list()
-
- if(Storage) //If it called itself
- L += Storage.return_inv()
-
- for(var/obj/item/gift/G in Storage.return_inv()) //Check for gift-wrapped items
- L += G.gift
- if(istype(G.gift, /obj/item/storage))
- L += get_contents(G.gift)
-
- for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items
- L += D.wrapped
- if(istype(D.wrapped, /obj/item/storage)) //this should never happen
- L += get_contents(D.wrapped)
- return L
-
- else
-
- L += contents
- for(var/obj/item/storage/S in contents) //Check for storage items
- L += get_contents(S)
-
- for(var/obj/item/gift/G in contents) //Check for gift-wrapped items
- L += G.gift
- if(istype(G.gift, /obj/item/storage))
- L += get_contents(G.gift)
-
- for(var/obj/item/smallDelivery/D in contents) //Check for package wrapped items
- L += D.wrapped
- if(istype(D.wrapped, /obj/item/storage)) //this should never happen
- L += get_contents(D.wrapped)
- return L
-
-
/mob/living/proc/check_contents_for(A)
- var/list/L = get_contents()
+ var/list/L = GetAllContents()
for(var/obj/O in L)
if(O.type == A)
@@ -234,9 +195,9 @@
s_active.close(src)
-/mob/living/Moved(oldLoc, dir)
+/mob/living/Moved(atom/old_loc, movement_dir, forced = FALSE, list/old_locs)
. = ..()
- update_camera_location(oldLoc)
+ update_camera_location(old_loc)
/mob/living/forceMove(atom/destination)
@@ -255,14 +216,6 @@
/mob/living/proc/update_camera_location(oldLoc)
return
-
-/mob/living/vv_get_dropdown()
- . = ..()
- . += "---"
- .["Add Language"] = "?_src_=vars;[HrefToken()];addlanguage=[REF(src)]"
- .["Remove Language"] = "?_src_=vars;[HrefToken()];remlanguage=[REF(src)]"
-
-
/mob/proc/resist_grab()
return //returning 1 means we successfully broke free
@@ -375,8 +328,10 @@
mob_swap_mode = PHASING
else if((move_resist >= MOVE_FORCE_VERY_STRONG || move_resist > L.move_force) && a_intent == INTENT_HELP) //Larger mobs can shove aside smaller ones. Xenos can always shove xenos
mob_swap_mode = SWAPPING
- ///if we're moving diagonally, but the mob isn't on the diagonal destination turf we have no reason to shuffle/push them
- if(moving_diagonally && (get_dir(src, L) in GLOB.cardinals) && get_step(src, dir).Enter(src, loc))
+ /* If we're moving diagonally, but the mob isn't on the diagonal destination turf and the destination turf is enterable we have no reason to shuffle/push them
+ * However we also do not want mobs of smaller move forces being able to pass us diagonally if our move resist is larger, unless they're the same faction as us
+ */
+ if(moving_diagonally && (get_dir(src, L) in GLOB.cardinals) && (L.faction == faction || L.move_resist <= move_force) && get_step(src, dir).Enter(src, loc))
mob_swap_mode = PHASING
if(mob_swap_mode)
//switch our position with L
@@ -483,6 +438,11 @@
stop_pulling() //being thrown breaks pulls.
if(pulledby)
pulledby.stop_pulling()
+ if(LAZYLEN(buckled_mobs) && !flying)
+ unbuckle_all_mobs(force = TRUE)
+ if(buckled)
+ buckled.unbuckle_mob(src)
+
return ..()
/**
@@ -772,33 +732,6 @@ below 100 is not dizzy
else
stop_pulling()
-
-/mob/living/vv_edit_var(var_name, var_value)
- switch(var_name)
- if("maxHealth")
- if(!isnum(var_value) || var_value <= 0)
- return FALSE
- if("stat")
- if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
- GLOB.dead_mob_list -= src
- GLOB.alive_living_list += src
- if((stat < DEAD) && (var_value == DEAD))//Kill he
- GLOB.alive_living_list -= src
- GLOB.dead_mob_list += src
- . = ..()
- switch(var_name)
- if("eye_blind")
- set_blindness(var_value)
- if("eye_blurry")
- set_blurriness(var_value)
- if("maxHealth")
- updatehealth()
- if("resize")
- update_transform()
- if("lighting_alpha")
- sync_lighting_plane_alpha()
-
-
/mob/living/can_interact_with(datum/D)
return D == src || D.Adjacent(src)
@@ -871,19 +804,15 @@ below 100 is not dizzy
///Swap the active hand
/mob/living/proc/swap_hand()
var/obj/item/wielded_item = get_active_held_item()
- if(wielded_item && (wielded_item.flags_item & WIELDED)) //this segment checks if the item in your hand is twohanded.
+ if(wielded_item && (wielded_item.item_flags & WIELDED)) //this segment checks if the item in your hand is twohanded.
var/obj/item/weapon/twohanded/offhand/offhand = get_inactive_held_item()
- if(offhand && (offhand.flags_item & WIELDED))
+ if(offhand && (offhand.item_flags & WIELDED))
wielded_item.unwield(src) //Get rid of it.
hand = !hand
SEND_SIGNAL(src, COMSIG_CARBON_SWAPPED_HANDS)
if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
- hud_used.l_hand_hud_object.update_icon(hand)
- hud_used.r_hand_hud_object.update_icon(!hand)
- if(hand) //This being 1 means the left hand is in use
- hud_used.l_hand_hud_object.add_overlay("hand_active")
- else
- hud_used.r_hand_hud_object.add_overlay("hand_active")
+ hud_used.l_hand_hud_object.update_icon()
+ hud_used.r_hand_hud_object.update_icon()
return
///Swap to the hand clicked on the hud
@@ -946,7 +875,7 @@ below 100 is not dizzy
get_up()
///Sets up the jump component for the mob. Proc args can be altered so different mobs have different 'default' jump settings
-/mob/living/proc/set_jump_component(duration = 0.5 SECONDS, cooldown = 1 SECONDS, cost = 8, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE)
+/mob/living/proc/set_jump_component(duration = 0.5 SECONDS, cooldown = 1 SECONDS, cost = 8, height = 16, sound = null, flags = JUMP_SHADOW, pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK)
var/gravity = get_gravity()
if(gravity < 1) //low grav
duration *= 2.5 - gravity
@@ -954,11 +883,122 @@ below 100 is not dizzy
cost *= gravity * 0.5
height *= 2 - gravity
if(gravity <= 0.75)
- flags_pass |= PASS_DEFENSIVE_STRUCTURE
+ pass_flags |= PASS_DEFENSIVE_STRUCTURE
else if(gravity > 1) //high grav
duration *= gravity * 0.5
cooldown *= gravity
cost *= gravity
height *= gravity * 0.5
- AddComponent(/datum/component/jump, _jump_duration = duration, _jump_cooldown = cooldown, _stamina_cost = cost, _jump_height = height, _jump_sound = sound, _jump_flags = flags, _jumper_allow_pass_flags = flags_pass)
+ AddComponent(/datum/component/jump, _jump_duration = duration, _jump_cooldown = cooldown, _stamina_cost = cost, _jump_height = height, _jump_sound = sound, _jump_flags = flags, _jumper_allow_pass_flags = pass_flags)
+
+/mob/living/vv_edit_var(var_name, var_value)
+ switch(var_name)
+ if (NAMEOF(src, maxHealth))
+ if (!isnum(var_value) || var_value <= 0)
+ return FALSE
+ if(NAMEOF(src, health)) //this doesn't work. gotta use procs instead.
+ return FALSE
+ if(NAMEOF(src, stat))
+ if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
+ GLOB.dead_mob_list -= src
+ GLOB.alive_living_list += src
+ if((stat < DEAD) && (var_value == DEAD))//Kill he
+ GLOB.alive_living_list -= src
+ GLOB.dead_mob_list += src
+ if(NAMEOF(src, resting))
+ set_resting(var_value)
+ . = TRUE
+ if(NAMEOF(src, lying_angle))
+ set_lying_angle(var_value)
+ . = TRUE
+ if(NAMEOF(src, eye_blind))
+ set_blindness(var_value)
+ if(NAMEOF(src, eye_blurry))
+ set_blurriness(var_value)
+ if(NAMEOF(src, lighting_alpha))
+ sync_lighting_plane_alpha()
+ if(NAMEOF(src, resize))
+ if(var_value == 0) //prevents divisions of and by zero.
+ return FALSE
+ update_transform(var_value/resize)
+ . = TRUE
+
+ if(!isnull(.))
+ datum_flags |= DF_VAR_EDITED
+ return
+
+ . = ..()
+
+ switch(var_name)
+ if(NAMEOF(src, maxHealth))
+ updatehealth()
+
+/mob/living/vv_get_header()
+ . = ..()
+ var/refid = REF(src)
+ . += {"
+ [VV_HREF_TARGETREF(refid, VV_HK_GIVE_DIRECT_CONTROL, "[ckey || "no ckey"]")] / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]
+
+ BRUTE:[getBruteLoss()]
+ FIRE:[getFireLoss()]
+ TOXIN:[getToxLoss()]
+ OXY:[getOxyLoss()]
+ CLONE:[getCloneLoss()]
+ STAMINA:[getStaminaLoss()]
+
+ "}
+
+/mob/living/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_ADD_LANGUAGE, "Add Language")
+ VV_DROPDOWN_OPTION(VV_HK_REMOVE_LANGUAGE, "Remove Language")
+ VV_DROPDOWN_OPTION(VV_HK_GIVE_SPEECH_IMPEDIMENT, "Impede Speech (Slurring, stuttering, etc)")
+
+/mob/living/vv_do_topic(list/href_list)
+ . = ..()
+
+ if(!.)
+ return
+
+ if(href_list[VV_HK_ADD_LANGUAGE])
+ if(!check_rights(NONE))
+ return
+ var/choice = tgui_input_list(usr, "Grant which language?", "Languages", GLOB.all_languages)
+ if(!choice)
+ return
+ grant_language(choice)
+ if(href_list[VV_HK_REMOVE_LANGUAGE])
+ if(!check_rights(NONE))
+ return
+ var/choice = tgui_input_list(usr, "Remove which language?", "Known Languages", src.language_holder.languages)
+ if(!choice)
+ return
+ remove_language(choice)
+ if(href_list[VV_HK_GIVE_SPEECH_IMPEDIMENT])
+ if(!check_rights(NONE))
+ return
+ admin_give_speech_impediment(usr)
+
+/// Admin only proc for giving a certain speech impediment to this mob
+/mob/living/proc/admin_give_speech_impediment(mob/admin)
+ if(!admin || !check_rights(NONE))
+ return
+
+ var/list/impediments = list()
+ for(var/datum/status_effect/possible as anything in typesof(/datum/status_effect/speech))
+ if(!initial(possible.id))
+ continue
+
+ impediments[initial(possible.id)] = possible
+
+ var/chosen = tgui_input_list(admin, "What speech impediment?", "Impede Speech", impediments)
+ if(!chosen || !ispath(impediments[chosen], /datum/status_effect/speech) || QDELETED(src) || !check_rights(NONE))
+ return
+
+ var/duration = tgui_input_number(admin, "How long should it last (in seconds)? Max is infinite duration.", "Duration", 0, INFINITY, 0 SECONDS)
+ if(!isnum(duration) || duration <= 0 || QDELETED(src) || !check_rights(NONE))
+ return
+
+ adjust_timed_status_effect(duration * 1 SECONDS, impediments[chosen])
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index de2ad13aae925..8dcb7ea20555a 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -1,8 +1,58 @@
+/mob/living/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_MOB_SLAM_DAMAGE, is_sharp = FALSE)
+ if(!isliving(grab.grabbed_thing))
+ return
+ if(grab.grabbed_thing == src)
+ return
+ if(user == src)
+ return
+
+ var/mob/living/grabbed_mob = grab.grabbed_thing
+ step_towards(grabbed_mob, src)
+ user.drop_held_item()
+ var/state = user.grab_state
+
+ if(state >= GRAB_AGGRESSIVE)
+ var/own_stun_chance = 0
+ var/grabbed_stun_chance = 0
+ if(grabbed_mob.mob_size > mob_size)
+ own_stun_chance = 25
+ grabbed_stun_chance = 10
+ else if(grabbed_mob.mob_size < mob_size)
+ own_stun_chance = 0
+ grabbed_stun_chance = 25
+ else
+ own_stun_chance = 25
+ grabbed_stun_chance = 25
+
+ if(prob(own_stun_chance))
+ Paralyze(1 SECONDS)
+ if(prob(grabbed_stun_chance))
+ grabbed_mob.Paralyze(1 SECONDS)
+
+ var/damage = (user.skills.getRating(SKILL_CQC) * CQC_SKILL_DAMAGE_MOD)
+ switch(state)
+ if(GRAB_PASSIVE)
+ damage += base_damage
+ grabbed_mob.visible_message(span_warning("[user] slams [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "slammed", "", "against [src]")
+ if(GRAB_AGGRESSIVE)
+ damage += base_damage * 1.5
+ grabbed_mob.visible_message(span_danger("[user] bashes [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "bashed", "", "against [src]")
+ if(GRAB_NECK)
+ damage += base_damage * 2
+ grabbed_mob.visible_message(span_danger("[user] crushes [grabbed_mob] against [src]!"))
+ log_combat(user, grabbed_mob, "crushed", "", "against [src]")
+ grabbed_mob.apply_damage(damage, blocked = MELEE, updating_health = TRUE)
+ apply_damage(damage, blocked = MELEE, updating_health = TRUE)
+ playsound(src, 'sound/weapons/heavyhit.ogg', 40)
+ return TRUE
+
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0)
return 0 //only carbon liveforms have this proc
/mob/living/emp_act(severity)
- var/list/L = src.get_contents()
+ var/list/L = GetAllContents()
for(var/obj/O in L)
O.emp_act(severity)
..()
@@ -21,9 +71,6 @@
var/obj/O = AM
O.stop_throw()
apply_damage(O.throwforce*(speed * 0.2), O.damtype, BODY_ZONE_CHEST, MELEE, is_sharp(O), has_edge(O), TRUE, O.penetration)
- if(O.item_fire_stacks)
- fire_stacks += O.item_fire_stacks
- IgniteMob()
visible_message(span_warning(" [src] has been hit by [AM]."), null, null, 5)
if(ismob(AM.thrower))
@@ -138,6 +185,21 @@
adjust_fire_stacks(rand(1,2))
IgniteMob()
+/mob/living/lava_act()
+ if(resistance_flags & INDESTRUCTIBLE)
+ return FALSE
+ if(stat == DEAD)
+ return FALSE
+ if(status_flags & GODMODE)
+ return TRUE //while godmode will stop the damage, we don't want the process to stop in case godmode is removed
+
+ var/lava_damage = 20
+ take_overall_damage(max(modify_by_armor(lava_damage, FIRE), lava_damage * 0.3), BURN, updating_health = TRUE, max_limbs = 3) //snowflakey interaction to stop complete lava immunity
+ if(!CHECK_BITFIELD(pass_flags, PASS_FIRE))//Pass fire allow to cross lava without igniting
+ adjust_fire_stacks(20)
+ IgniteMob()
+ return TRUE
+
/mob/living/flamer_fire_act(burnlevel)
if(!burnlevel)
return
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 605adb03c0e02..165474af2a3c2 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -1,6 +1,6 @@
/mob/living
see_invisible = SEE_INVISIBLE_LIVING
- flags_atom = CRITICAL_ATOM|PREVENT_CONTENTS_EXPLOSION|BUMP_ATTACKABLE
+ atom_flags = CRITICAL_ATOM|PREVENT_CONTENTS_EXPLOSION|BUMP_ATTACKABLE
///0 for no override, sets see_invisible = see_override in silicon & carbon life process via update_sight()
var/see_override = 0
///Badminnery resize
@@ -124,7 +124,10 @@
var/grab_resist_level = 0
var/datum/job/job
var/comm_title = ""
- ///how much blood the mob has
+ /**
+ * How much blood the mob has.
+ * !!! Use the adjust_blood_volume() and set_blood_volume() to set this variable instead of directly modifying it!!!
+ */
var/blood_volume = 0
///Multiplier.
var/heart_multi = 1
diff --git a/code/modules/mob/living/living_health_procs.dm b/code/modules/mob/living/living_health_procs.dm
index f06b770cc759c..ee301c667dc85 100644
--- a/code/modules/mob/living/living_health_procs.dm
+++ b/code/modules/mob/living/living_health_procs.dm
@@ -92,6 +92,7 @@
updateStamina(feedback)
/mob/living/proc/updateStamina(feedback = TRUE)
+ hud_used?.staminas?.update_icon()
if(staminaloss < max(health * 1.5,0) || !(COOLDOWN_CHECK(src, last_stamina_exhaustion))) //If we're on cooldown for stamina exhaustion, don't bother
return
@@ -105,21 +106,6 @@
adjust_blurriness(STAMINA_EXHAUSTION_DEBUFF_STACKS)
COOLDOWN_START(src, last_stamina_exhaustion, LIVING_STAMINA_EXHAUSTION_COOLDOWN - (skills.getRating(SKILL_STAMINA) * STAMINA_SKILL_COOLDOWN_MOD)) //set the cooldown.
-
-/mob/living/carbon/human/updateStamina(feedback = TRUE)
- . = ..()
- if(!hud_used?.staminas)
- return
- if(stat == DEAD)
- hud_used.staminas.icon_state = "stamloss200"
- return
- var/relative_stamloss = getStaminaLoss()
- if(relative_stamloss < 0 && max_stamina)
- relative_stamloss = round(((relative_stamloss * 14) / max_stamina), 1)
- else
- relative_stamloss = round(((relative_stamloss * 7) / (maxHealth * 2)), 1)
- hud_used.staminas.icon_state = "stamloss[relative_stamloss]"
-
/// Adds an entry to our stamina_regen_modifiers and updates stamina_regen_multiplier
/mob/living/proc/add_stamina_regen_modifier(mod_name, mod_value)
if(stamina_regen_modifiers[mod_name] == mod_value)
@@ -205,6 +191,20 @@
return
remove_movespeed_modifier(MOVESPEED_ID_DROWSINESS)
+///Adjusts the blood volume, with respect to the minimum and maximum values
+/mob/living/proc/adjust_blood_volume(amount)
+ if(!amount)
+ return
+
+ blood_volume = clamp(blood_volume + amount, 0, BLOOD_VOLUME_MAXIMUM)
+
+///Sets the blood volume, with respect to the minimum and maximum values
+/mob/living/proc/set_blood_volume(amount)
+ if(!amount)
+ return
+
+ blood_volume = clamp(amount, 0, BLOOD_VOLUME_MAXIMUM)
+
// heal ONE limb, organ gets randomly selected from damaged ones.
/mob/living/proc/heal_limb_damage(brute, burn, robo_repair = FALSE, updating_health = FALSE)
@@ -254,7 +254,6 @@
/mob/living/carbon/human/on_revive()
. = ..()
- revive_grace_time = initial(revive_grace_time)
GLOB.alive_human_list += src
LAZYADD(GLOB.alive_human_list_faction[faction], src)
GLOB.dead_human_list -= src
@@ -374,7 +373,7 @@
/mob/living/carbon/xenomorph/revive(admin_revive = FALSE)
- plasma_stored = xeno_caste.plasma_max
+ set_plasma(xeno_caste.plasma_max)
sunder = 0
if(stat == DEAD)
hive?.on_xeno_revive(src)
@@ -397,7 +396,8 @@
ADD_TRAIT(src, TRAIT_IS_RESURRECTING, REVIVE_TO_CRIT_TRAIT)
if(should_zombify && (istype(wear_ear, /obj/item/radio/headset/mainship)))
var/obj/item/radio/headset/mainship/radio = wear_ear
- radio.safety_protocol(src)
+ if(istype(radio))
+ radio.safety_protocol(src)
addtimer(CALLBACK(src, PROC_REF(finish_revive_to_crit), should_offer_to_ghost, should_zombify), 10 SECONDS)
///Check if we have a mind, and finish the revive if we do
@@ -427,3 +427,4 @@
overlay_fullscreen_timer(2 SECONDS, 20, "roundstart2", /atom/movable/screen/fullscreen/spawning_in)
REMOVE_TRAIT(src, TRAIT_IS_RESURRECTING, REVIVE_TO_CRIT_TRAIT)
SSmobs.start_processing(src)
+
diff --git a/code/modules/mob/living/living_helpers.dm b/code/modules/mob/living/living_helpers.dm
index ce974aedf2c26..bde1bbef01453 100644
--- a/code/modules/mob/living/living_helpers.dm
+++ b/code/modules/mob/living/living_helpers.dm
@@ -32,10 +32,10 @@
/mob/living/restrained(ignore_checks)
. = ..()
- var/flags_to_check = RESTRAINED_NECKGRAB | RESTRAINED_XENO_NEST | RESTRAINED_STRAIGHTJACKET | RESTRAINED_RAZORWIRE | RESTRAINED_PSYCHICGRAB
+ var/to_check_flags = RESTRAINED_NECKGRAB | RESTRAINED_XENO_NEST | RESTRAINED_STRAIGHTJACKET | RESTRAINED_RAZORWIRE | RESTRAINED_PSYCHICGRAB
if(ignore_checks)
- DISABLE_BITFIELD(flags_to_check, ignore_checks)
- return (. || CHECK_BITFIELD(restrained_flags, flags_to_check))
+ DISABLE_BITFIELD(to_check_flags, ignore_checks)
+ return (. || CHECK_BITFIELD(restrained_flags, to_check_flags))
/mob/living/get_policy_keywords()
diff --git a/code/modules/mob/living/living_verbs.dm b/code/modules/mob/living/living_verbs.dm
index 0c323f442effa..bd456755bc2bd 100644
--- a/code/modules/mob/living/living_verbs.dm
+++ b/code/modules/mob/living/living_verbs.dm
@@ -3,13 +3,9 @@
set category = "IC"
do_resist()
-
-//RUTGMC EDIT BEGIN - Moved to modular_RUtgmc\code\modules\mob\living\living_verbs.dm
-/*
-/mob/living/proc/lay_down()
- set name = "Rest"
- set category = "IC"
-
+/* // RUTGMC CHANGE
+///Handles trying to toggle resting state
+/mob/living/proc/toggle_resting()
if(incapacitated(TRUE))
return
@@ -17,19 +13,21 @@
if(is_ventcrawling)
return FALSE
set_resting(TRUE, FALSE)
- else if(do_actions)
- to_chat(src, span_warning("You are still in the process of standing up."))
return
- else if(do_after(src, 2 SECONDS, IGNORE_LOC_CHANGE|IGNORE_HELD_ITEM, src))
- get_up()
+ if(do_actions)
+ balloon_alert(src, "Busy!")
+ return
+ get_up()
+///Handles getting up, doing a basic check before relaying it to the actual proc that does it
/mob/living/proc/get_up()
if(!incapacitated(TRUE))
set_resting(FALSE, FALSE)
else
to_chat(src, span_notice("You fail to get up."))
-*/ // RUTGMC EDIT END
+*/ //RUTGMC CHANGE
+///Actually handles toggling the resting state
/mob/living/proc/set_resting(rest, silent = TRUE)
if(status_flags & INCORPOREAL)
return
@@ -47,11 +45,7 @@
if(!silent)
to_chat(src, span_notice("You get up."))
SEND_SIGNAL(src, COMSIG_XENOMORPH_UNREST)
- update_resting()
-
-
-/mob/living/proc/update_resting()
- hud_used?.rest_icon?.update_icon(src)
+ hud_used?.rest_icon?.update_icon()
/mob/living/verb/ghost()
diff --git a/code/modules/mob/living/logout.dm b/code/modules/mob/living/logout.dm
index 0960b0e702323..d8d92c9dca5cb 100644
--- a/code/modules/mob/living/logout.dm
+++ b/code/modules/mob/living/logout.dm
@@ -12,4 +12,4 @@
else if(!isclientedaghost(src))
set_afk_status(MOB_RECENTLY_DISCONNECTED, AFK_TIMER)
if(!QDELETED(src) && stat != DEAD)
- LAZYDISTINCTADD(GLOB.ssd_living_mobs, src)
+ LAZYOR(GLOB.ssd_living_mobs, src)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 5850166dc29c5..a8e77af688a3e 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -138,19 +138,6 @@
GLOB.ai_list -= src
QDEL_NULL(builtInCamera)
QDEL_NULL(track)
- UnregisterSignal(src, COMSIG_ORDER_SELECTED)
- UnregisterSignal(src, COMSIG_MOB_CLICK_ALT)
-
- UnregisterSignal(SSdcs, COMSIG_GLOB_OB_LASER_CREATED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_CAS_LASER_CREATED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_RAILGUN_LASER_CREATED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_SHUTTLE_TAKEOFF)
- UnregisterSignal(SSdcs, COMSIG_GLOB_DROPSHIP_CONTROLS_CORRUPTED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_MINI_DROPSHIP_DESTROYED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_DISK_GENERATED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_NUKE_START)
- UnregisterSignal(SSdcs, COMSIG_GLOB_CLONE_PRODUCED)
- UnregisterSignal(SSdcs, COMSIG_GLOB_HOLOPAD_AI_CALLED)
QDEL_NULL(mini)
return ..()
@@ -255,7 +242,6 @@
to_chat(src, span_notice("Camera lights activated."))
camera_light_on = !camera_light_on
-
/mob/living/silicon/ai/proc/light_cameras()
var/list/obj/machinery/camera/add = list()
var/list/obj/machinery/camera/remove = list()
@@ -277,6 +263,14 @@
C.Togglelight(1)
lit_cameras |= C
+/mob/living/silicon/ai/proc/supply_interface()
+ var/datum/supply_ui/SU
+ if(!SU)
+ SU = new(src)
+ SU.shuttle_id = SHUTTLE_SUPPLY
+ SU.home_id = "supply_home"
+ SU.faction = src.faction
+ return SU.interact(src)
/mob/living/silicon/ai/proc/camera_visibility(mob/camera/aiEye/moved_eye)
GLOB.cameranet.visibility(moved_eye, client, all_eyes, moved_eye.use_static)
@@ -289,11 +283,11 @@
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A)))
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
- raw_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
var/start = "Relayed Speech: "
var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
var/hrefpart = ""
var/jobpart
+ var/speech_part = lang_treat(speaker, message_language, raw_message, spans, message_mode)
if(iscarbon(speaker))
var/mob/living/carbon/S = speaker
@@ -302,8 +296,10 @@
else
jobpart = "Unknown"
- var/rendered = "[start][span_name("[hrefpart][namepart] ([jobpart]) ")][span_message("[raw_message]")]"
+ var/rendered = "[start][span_name("[hrefpart][namepart] ([jobpart]) ")][span_message("[speech_part]")]"
+
+ create_chat_message(speaker, message_language, raw_message, spans, message_mode)
show_message(rendered, 2)
@@ -345,20 +341,19 @@
else
clear_fullscreen("remote_view", 0)
-/* RUTGMC DELETION
+
/mob/living/silicon/ai/update_sight()
- . = ..()
if(HAS_TRAIT(src, TRAIT_SEE_IN_DARK))
see_in_dark = max(see_in_dark, 8)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
eyeobj.see_in_dark = max(eyeobj.see_in_dark, 8)
eyeobj.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- return
+ return ..()
+ see_in_dark = initial(see_in_dark)
+ lighting_alpha = initial(lighting_alpha)
eyeobj.see_in_dark = initial(eyeobj.see_in_dark)
eyeobj.lighting_alpha = initial(eyeobj.lighting_alpha)
- see_in_dark = initial(see_in_dark)
- lighting_alpha = initial(lighting_alpha) // yes you really have to change both the eye and the ai vars
-*/
+ return ..()
/mob/living/silicon/ai/get_status_tab_items()
. = ..()
@@ -383,7 +378,8 @@
. += "Current alert level: [GLOB.marine_main_ship.get_security_level()]"
- . += "Number of living marines: [SSticker.mode.count_humans_and_xenos()[1]]"
+ if(SSticker.mode)
+ . += "Number of living marines: [SSticker.mode.count_humans_and_xenos()[1]]"
if(GLOB.marine_main_ship?.rail_gun?.last_firing_ai + COOLDOWN_RAILGUN_FIRE > world.time)
. += "Railgun status: Cooling down, next fire in [(GLOB.marine_main_ship?.rail_gun?.last_firing_ai + COOLDOWN_RAILGUN_FIRE - world.time)/10] seconds."
@@ -394,6 +390,9 @@
. += "AI bioscan status: Instruments recalibrating, next scan in [(last_ai_bioscan + COOLDOWN_AI_BIOSCAN - world.time)/10] seconds." //about 10 minutes
else
. += "AI bioscan status: Instruments are ready to scan the planet."
+ var/status_value = SSevacuation?.get_status_panel_eta()
+ if(status_value)
+ . += "Evacuation in: [status_value]"
/mob/living/silicon/ai/fully_replace_character_name(oldname, newname)
. = ..()
diff --git a/code/modules/mob/living/silicon/ai/freelook/read_me.dm b/code/modules/mob/living/silicon/ai/freelook/README.md
similarity index 97%
rename from code/modules/mob/living/silicon/ai/freelook/read_me.dm
rename to code/modules/mob/living/silicon/ai/freelook/README.md
index 0f92bf94e6cd6..4528926265596 100644
--- a/code/modules/mob/living/silicon/ai/freelook/read_me.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/README.md
@@ -1,12 +1,4 @@
-// CREDITS
-/*
-Initial code credit for this goes to Uristqwerty.
-Debugging, functionality, all comments and porting by Giacom.
-
-Everything about freelook (or what we can put in here) will be stored here.
-
-
-WHAT IS THIS?
+# WHAT IS THIS?
This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
@@ -17,7 +9,7 @@ This creates several features, such as.. no more see-through-wall cameras, easie
the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.
-HOW IT WORKS
+# HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/Initialize(mapload) and Destroy().
@@ -27,7 +19,7 @@ These turfs are then sorted out based on what the cameras can and cannot see. If
the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.
-HOW IT UPDATES
+# HOW IT UPDATES
The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.
@@ -41,10 +33,15 @@ measures, such as an UPDATE_BUFFER which stops a chunk from updating too many ti
sight; for example, we don't update glass airlocks or floors.
-WHERE IS EVERYTHING?
+# WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
-*/
+## CREDITS
+
+Initial code credit for this goes to Uristqwerty.
+Debugging, functionality, all comments and porting by Giacom.
+
+Everything about freelook (or what we can put in here) will be stored here.
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 5f4ef743db403..44bb9a62424ff 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -198,3 +198,8 @@
/mob/camera/aiEye/proc/unregister_facedir_signals(mob/user)
UnregisterSignal(user, list(COMSIG_KB_MOB_FACENORTH_DOWN, COMSIG_KB_MOB_FACEEAST_DOWN, COMSIG_KB_MOB_FACESOUTH_DOWN, COMSIG_KB_MOB_FACEWEST_DOWN))
+
+/mob/camera/aiEye/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, sound/S, distance_multiplier, mob/sound_reciever)
+ if(istype(parent_cameranet) && !parent_cameranet.checkTurfVis(get_turf(src)))
+ return
+ return ..(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, S, distance_multiplier, ai)
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
index 680244b23c8fd..652c6bb19198f 100644
--- a/code/modules/mob/living/silicon/ai/multicam.dm
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -222,7 +222,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
if(!silent)
to_chat(src, span_warning("Cannot place more than [max_multicams] multicamera windows."))
return
- var/atom/movable/screen/movable/pic_in_pic/ai/C = new /atom/movable/screen/movable/pic_in_pic/ai()
+ var/atom/movable/screen/movable/pic_in_pic/ai/C = new()
C.set_view_size(3, 3, FALSE)
C.set_view_center(get_turf(eyeobj))
C.set_ai(src)
diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm
index db7e8e950f486..1d0b5e1310393 100644
--- a/code/modules/mob/living/silicon/ai/say.dm
+++ b/code/modules/mob/living/silicon/ai/say.dm
@@ -114,7 +114,7 @@
log_game("[key_name(src)] made a vocal announcement with the following message: [message].")
log_talk(message, LOG_SAY, tag="VOX Announcement")
- to_chat(src, span_notice("The following vocal announcement has been made: [message]."))
+ minor_announce(capitalize(message), "[name] announces:", receivers = (GLOB.alive_human_list + GLOB.ai_list + GLOB.observer_list), should_play_sound = FALSE)
for(var/word in words) //play vox sounds to the rest of our zlevel
play_vox_word(word, src.z, null)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index f3a37e5f0297c..ccd70bbe026d4 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -18,6 +18,7 @@
/mob/living/silicon/Initialize(mapload)
. = ..()
+ GLOB.silicon_mobs += src
radio = new(src)
if(SStts.tts_enabled)
voice = pick(SStts.available_speakers)
@@ -25,6 +26,7 @@
/mob/living/silicon/Destroy()
QDEL_NULL(radio)
+ GLOB.silicon_mobs -= src
return ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index c3e48b988a810..5d8dadf6c6fa6 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -141,7 +141,7 @@
slot_l_hand_str = 'icons/mob/inhands/items/animals_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/items/animals_right.dmi',
)
- flags_armor_features = ARMOR_NO_DECAP
+ armor_features_flags = ARMOR_NO_DECAP
soft_armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 10, BIO = 5, FIRE = 50, ACID = 50)
var/mob/living/simple_animal/cat/cat
diff --git a/code/modules/mob/living/simple_animal/friendly/parrot.dm b/code/modules/mob/living/simple_animal/friendly/parrot.dm
index cf94b7f4e534e..f9f88241e19f1 100644
--- a/code/modules/mob/living/simple_animal/friendly/parrot.dm
+++ b/code/modules/mob/living/simple_animal/friendly/parrot.dm
@@ -156,8 +156,8 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list(
if(stat != DEAD && user.a_intent == INTENT_HELP)
handle_automated_speech(1) //assured speak/emote
-/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- return attack_hand(X)
+/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ return attack_hand(xeno_attacker)
/mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/M)
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index c9cb366bca4c1..b92cdf747865a 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -386,7 +386,7 @@
var/obj/projectile/P = new(startloc)
playsound(src, projectilesound, 100, 1)
P.generate_bullet(GLOB.ammo_list[ammotype])
- P.fire_at(targeted_atom, src)
+ P.fire_at(targeted_atom, src, src)
/mob/living/simple_animal/hostile/proc/CanSmashTurfs(turf/T)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 5104d3f4295db..9a50d11f8d745 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -197,22 +197,22 @@
return TRUE
-/mob/living/simple_animal/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/mob/living/simple_animal/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(!.)
return
- if(X.a_intent == INTENT_DISARM)
+ if(xeno_attacker.a_intent == INTENT_DISARM)
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- visible_message(span_danger("[X] [response_disarm] [name]!"), \
- span_userdanger("[X] [response_disarm] [name]!"))
- log_combat(X, src, "disarmed")
+ visible_message(span_danger("[xeno_attacker] [response_disarm] [name]!"), \
+ span_userdanger("[xeno_attacker] [response_disarm] [name]!"))
+ log_combat(xeno_attacker, src, "disarmed")
else
var/damage = rand(15, 30)
- visible_message(span_danger("[X] has slashed at [src]!"), \
- span_userdanger("[X] has slashed at [src]!"))
+ visible_message(span_danger("[xeno_attacker] has slashed at [src]!"), \
+ span_userdanger("[xeno_attacker] has slashed at [src]!"))
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
attack_threshold_check(damage)
- log_combat(X, src, "attacked")
+ log_combat(xeno_attacker, src, "attacked")
return TRUE
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index a9aa21994f39e..ea2f0bd67c1e2 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -11,7 +11,6 @@
ghostize()
clear_fullscreens()
if(mind)
- stack_trace("Found a reference to an undeleted mind in mob/Destroy(). Mind name: [mind.name]. Mind mob: [mind.current]")
mind = null
if(hud_used)
QDEL_NULL(hud_used)
@@ -34,6 +33,11 @@
GLOB.dead_mob_list += src
set_focus(src)
prepare_huds()
+ for(var/v in GLOB.active_alternate_appearances)
+ if(!v)
+ continue
+ var/datum/atom_hud/alternate_appearance/AA = v
+ AA.onNewMob(src)
. = ..()
if(islist(skills))
set_skills(getSkills(arglist(skills)))
@@ -240,13 +244,13 @@
return FALSE
equip_to_slot(W, slot) //This proc should not ever fail.
//This will unwield items -without- triggering lights.
- if(CHECK_BITFIELD(W.flags_item, TWOHANDED))
+ if(CHECK_BITFIELD(W.item_flags, TWOHANDED))
W.unwield(src)
return TRUE
else
equip_to_slot(W, slot) //This proc should not ever fail.
//This will unwield items -without- triggering lights.
- if(CHECK_BITFIELD(W.flags_item, TWOHANDED))
+ if(CHECK_BITFIELD(W.item_flags, TWOHANDED))
W.unwield(src)
return TRUE
@@ -307,7 +311,7 @@
var/obj/item/found = I.do_quick_equip(src)
if(!found)
return FALSE
- if(CHECK_BITFIELD(found.flags_inventory, NOQUICKEQUIP))
+ if(CHECK_BITFIELD(found.inventory_flags, NOQUICKEQUIP))
return FALSE
temporarilyRemoveItemFromInventory(found)
put_in_hands(found)
@@ -318,6 +322,37 @@
. += "---"
.["Player Panel"] = "?_src_=vars;[HrefToken()];playerpanel=[REF(src)]"
+/mob/vv_edit_var(var_name, var_value)
+ switch(var_name)
+ if(NAMEOF(src, control_object))
+ var/obj/O = var_value
+ if(!istype(O) || (O.obj_flags & DANGEROUS_POSSESSION))
+ return FALSE
+ if(NAMEOF(src, machine))
+ set_machine(var_value)
+ . = TRUE
+ if(NAMEOF(src, focus))
+ set_focus(var_value)
+ . = TRUE
+ if(NAMEOF(src, stat))
+ set_stat(var_value)
+ . = TRUE
+
+ if(!isnull(.))
+ datum_flags |= DF_VAR_EDITED
+ return
+
+ var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
+ var/diff
+ if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value))
+ remove_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT)
+ diff = var_value - cached_multiplicative_slowdown
+
+ . = ..()
+
+ if(. && slowdown_edit && isnum(diff))
+ update_movespeed()
+
/client/verb/changes()
set name = "Changelog"
@@ -789,6 +824,7 @@
//This would go on on_revive() but that is a mob/living proc
var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[ckey]
personal_statistics.times_revived++
+ personal_statistics.mission_times_revived++
SEND_SIGNAL(src, COMSIG_MOB_STAT_CHANGED, ., new_stat)
/// Cleanup proc that's called when a mob loses a client, either through client destroy or logout
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index f1f3482670a8e..7d5a782d81d0d 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -6,7 +6,7 @@
animate_movement = SLIDE_STEPS
datum_flags = DF_USE_TAG
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
resistance_flags = NONE
//Mob
@@ -77,6 +77,8 @@
var/list/fullscreens = list()
///contains /atom/movable/screen/alert only, used by alerts.dm
var/list/alerts = list()
+ ///List of queued interactions on this mob
+ var/list/queued_interactions
var/list/datum/action/actions = list()
var/list/actions_by_path = list()
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index b416799643b3c..b31dc5f2511d6 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -4,8 +4,8 @@
name = "grab"
icon_state = "reinforce"
icon = 'icons/mob/screen/generic.dmi'
- flags_atom = NONE
- flags_item = NOBLUDGEON|DELONDROP|ITEM_ABSTRACT
+ atom_flags = NONE
+ item_flags = NOBLUDGEON|DELONDROP|ITEM_ABSTRACT
layer = ABOVE_HUD_LAYER
plane = ABOVE_HUD_PLANE
item_state = "nothing"
@@ -61,7 +61,7 @@
if(user.grab_state > GRAB_KILL)
return
user.changeNext_move(CLICK_CD_GRABBING)
- if(!do_after(user, 2 SECONDS, NONE, victim, BUSY_ICON_HOSTILE, extra_checks = CALLBACK(user, TYPE_PROC_REF(/datum, Adjacent), victim)) || !user.pulling)
+ if(!do_after(user, max(2 SECONDS - (user.skills.getRating(SKILL_CQC) * 0.5 SECONDS), 1 SECONDS), NONE, victim, BUSY_ICON_HOSTILE, extra_checks = CALLBACK(user, TYPE_PROC_REF(/datum, Adjacent), victim)) || !user.pulling)
return
user.advance_grab_state()
if(user.grab_state == GRAB_NECK)
@@ -74,6 +74,7 @@
var/mob/living/victim = pulling
playsound(loc, 'sound/weapons/thudswoosh.ogg', 25, TRUE, 7)
setGrabState(grab_state + 1)
+ victim.grab_resist_level -= 1
switch(grab_state)
if(GRAB_AGGRESSIVE)
log_combat(src, victim, "aggressive grabbed")
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 97b1823a88a2d..6794ea95a60e8 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -252,10 +252,10 @@ GLOBAL_LIST_INIT(organ_rel_size, list(
/mob/proc/abiotic(full_body)
- if(full_body && ((l_hand && !( l_hand.flags_item & ITEM_ABSTRACT )) || (r_hand && !( r_hand.flags_item & ITEM_ABSTRACT ))))
+ if(full_body && ((l_hand && !( l_hand.item_flags & ITEM_ABSTRACT )) || (r_hand && !( r_hand.item_flags & ITEM_ABSTRACT ))))
return TRUE
- if((src.l_hand && !( src.l_hand.flags_item & ITEM_ABSTRACT )) || (src.r_hand && !( src.r_hand.flags_item & ITEM_ABSTRACT )))
+ if((src.l_hand && !( src.l_hand.item_flags & ITEM_ABSTRACT )) || (src.r_hand && !( src.r_hand.item_flags & ITEM_ABSTRACT )))
return TRUE
return FALSE
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 654a57c6173a9..c5f5c182dc6a3 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -184,7 +184,7 @@
if(istype(src,/mob/living/carbon/human/)) // Only humans can wear magboots, so we give them a chance to.
var/mob/living/carbon/human/H = src
- if((istype(turf,/turf/open/floor)) && !(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.flags_inventory & NOSLIPPING)))
+ if((istype(turf,/turf/open/floor)) && !(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.inventory_flags & NOSLIPPING)))
continue
@@ -361,7 +361,7 @@
if(hud_used?.static_inventory)
for(var/atom/movable/screen/mov_intent/selector in hud_used.static_inventory)
- selector.update_icon(src)
+ selector.update_icon()
return TRUE
diff --git a/code/modules/mob/mob_movespeed.dm b/code/modules/mob/mob_movespeed.dm
index 967a4c1f4a54f..47019380785eb 100644
--- a/code/modules/mob/mob_movespeed.dm
+++ b/code/modules/mob/mob_movespeed.dm
@@ -61,17 +61,6 @@ Key procs
update_movespeed(FALSE)
return TRUE
-///Handles the special case of editing the movement var
-/mob/vv_edit_var(var_name, var_value)
- var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
- var/diff
- if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value))
- remove_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT)
- diff = var_value - cached_multiplicative_slowdown
- . = ..()
- if(. && slowdown_edit && isnum(diff))
- add_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT, TRUE, 100, NONE, TRUE, diff)
-
///Is there a movespeed modifier for this mob
/mob/proc/has_movespeed_modifier(id)
return LAZYACCESS(movespeed_modification, id)
diff --git a/code/modules/mob/mob_verbs.dm b/code/modules/mob/mob_verbs.dm
index ddcfab3cf347b..bf6a7005b2cad 100644
--- a/code/modules/mob/mob_verbs.dm
+++ b/code/modules/mob/mob_verbs.dm
@@ -82,7 +82,7 @@
return
var/mob/new_player/M = new /mob/new_player()
- if(SSticker.mode?.flags_round_type & MODE_TWO_HUMAN_FACTIONS)
+ if(SSticker.mode?.round_type_flags & MODE_TWO_HUMAN_FACTIONS)
M.faction = faction
if(!client)
qdel(M)
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 5b019faae00e3..bc80a844dd0fc 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -173,7 +173,7 @@
DIRECT_OUTPUT(usr, browse(null, "window=xenosunbalanced"))
if(href_list["showpoll"])
- handle_playeR_DBRANKSing()
+ handle_playeR_POLLSing()
return
if(href_list["viewpoll"])
@@ -195,7 +195,7 @@
if(!GLOB.enter_allowed)
dat += "
You may no longer join the round.
"
var/forced_faction
- if(SSticker.mode.flags_round_type & MODE_TWO_HUMAN_FACTIONS)
+ if(SSticker.mode.round_type_flags & MODE_TWO_HUMAN_FACTIONS)
if(faction in SSticker.mode.get_joinable_factions(FALSE))
forced_faction = faction
else
@@ -455,7 +455,7 @@
to_chat(src, span_warning("The round is either not ready, or has already finished."))
return
- if(SSticker.mode.flags_round_type & MODE_NO_LATEJOIN)
+ if(SSticker.mode.round_type_flags & MODE_NO_LATEJOIN)
to_chat(src, span_warning("Sorry, you cannot late join during [SSticker.mode.name]. You have to start at the beginning of the round. You may observe or try to join as an alien, if possible."))
return
diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm
index 8fdf495ae35fa..570b13273c086 100644
--- a/code/modules/mob/new_player/poll.dm
+++ b/code/modules/mob/new_player/poll.dm
@@ -2,7 +2,7 @@
* Shows a list of currently running polls a player can vote/has voted on
*
*/
-/mob/new_player/proc/handle_playeR_DBRANKSing()
+/mob/new_player/proc/handle_playeR_POLLSing()
var/list/output = list("
Player polls
")
var/rs = REF(src)
for(var/p in GLOB.polls)
diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm
index 79b8c359da1a5..5c275bf383fd2 100644
--- a/code/modules/mob/update_icons.dm
+++ b/code/modules/mob/update_icons.dm
@@ -61,9 +61,6 @@
/mob/proc/update_inv_ears()
return
-/mob/proc/update_targeted()
- return
-
/mob/proc/update_burst()
return
diff --git a/code/modules/orbits/spaceship.dm b/code/modules/orbits/spaceship.dm
index 211830a9cf303..d058fe16f2c3b 100644
--- a/code/modules/orbits/spaceship.dm
+++ b/code/modules/orbits/spaceship.dm
@@ -161,7 +161,7 @@ GLOBAL_VAR_INIT(current_orbit,STANDARD_ORBIT)
message_admins("[ADMIN_TPMONTY(usr)] Has sent the ship [direction == "UP" ? "UPWARD" : "DOWNWARD"] in orbit")
var/message = "Prepare for orbital change in 10 seconds.\nMoving [direction] the gravity well.\nSecure all belongings and prepare for engine ignition."
- priority_announce(message, title = "Orbit Change")
+ minor_announce(message, title = "Orbit Change")
addtimer(CALLBACK(src, PROC_REF(do_change_orbit), current_orbit, direction), 10 SECONDS)
/obj/machinery/computer/navigation/proc/can_change_orbit(current_orbit, direction, silent = FALSE)
@@ -195,7 +195,7 @@ GLOBAL_VAR_INIT(current_orbit,STANDARD_ORBIT)
engine_shudder()
var/message = "Arriving at new orbital level. Prepare for engine ignition and stabilization."
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(priority_announce), message, "Orbit Change"), 290 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(minor_announce), message, "Orbit Change"), 290 SECONDS)
addtimer(CALLBACK(src, PROC_REF(orbit_gets_changed), current_orbit, direction), 3 MINUTES)
/obj/machinery/computer/navigation/proc/orbit_gets_changed(current_orbit, direction)
diff --git a/code/modules/organs/limb_objects.dm b/code/modules/organs/limb_objects.dm
index 75f4c607be4d9..b7d806af28330 100644
--- a/code/modules/organs/limb_objects.dm
+++ b/code/modules/organs/limb_objects.dm
@@ -93,7 +93,7 @@
overlays.Add(facial) // icon.Blend(facial, ICON_OVERLAY)
- if(H.h_style && !(H.head && (H.head.flags_inv_hide & HIDETOPHAIR)))
+ if(H.h_style && !(H.head && (H.head.inv_hide_flags & HIDETOPHAIR)))
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_list[H.h_style]
if(hair_style)
var/icon/hair = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm
index 91e88a3c8b201..8f447083d25c7 100644
--- a/code/modules/organs/limbs.dm
+++ b/code/modules/organs/limbs.dm
@@ -194,7 +194,7 @@ RU TGMC EDIT */
//Possibly trigger an internal wound, too.
var/local_damage = brute_dam + burn_dam + brute
- if(brute > 15 && local_damage > 30 && prob(brute*0.5) && !(limb_status & LIMB_ROBOT) && !(SSticker.mode?.flags_round_type & MODE_NO_PERMANENT_WOUNDS))
+ if(brute > 15 && local_damage > 30 && prob(brute*0.5) && !(limb_status & LIMB_ROBOT) && !(SSticker.mode?.round_type_flags & MODE_NO_PERMANENT_WOUNDS))
new /datum/wound/internal_bleeding(min(brute - 15, 15), src)
owner.custom_pain("You feel something rip in your [display_name]!", 1)
@@ -269,7 +269,7 @@ RU TGMC EDIT */
owner.updatehealth()
return update_icon()
var/obj/item/clothing/worn_helmet = owner.head
- if(body_part == HEAD && worn_helmet && (worn_helmet.flags_armor_features & ARMOR_NO_DECAP)) //Early return if the body part is a head but target is wearing decap-protecting headgear.
+ if(body_part == HEAD && worn_helmet && (worn_helmet.armor_features_flags & ARMOR_NO_DECAP)) //Early return if the body part is a head but target is wearing decap-protecting headgear.
if(updating_health)
owner.updatehealth()
return update_icon()
@@ -558,51 +558,51 @@ Note that amputating the affected organ does in fact remove the infection from t
remove_limb_flags(LIMB_BLEEDING)
-/datum/limb/proc/set_limb_flags(flags_to_set)
- if(flags_to_set == limb_status)
+/datum/limb/proc/set_limb_flags(to_set_flags)
+ if(to_set_flags == limb_status)
return
. = limb_status
- var/flags_to_change = . & ~flags_to_set //Flags to remove
- if(flags_to_change)
- remove_limb_flags(flags_to_change)
- flags_to_change = flags_to_set & ~(flags_to_set & .) //Flags to add
- if(flags_to_change)
- add_limb_flags(flags_to_change)
+ var/to_change_flags = . & ~to_set_flags //Flags to remove
+ if(to_change_flags)
+ remove_limb_flags(to_change_flags)
+ to_change_flags = to_set_flags & ~(to_set_flags & .) //Flags to add
+ if(to_change_flags)
+ add_limb_flags(to_change_flags)
-/datum/limb/proc/remove_limb_flags(flags_to_remove)
- if(!(limb_status & flags_to_remove))
+/datum/limb/proc/remove_limb_flags(to_remove_flags)
+ if(!(limb_status & to_remove_flags))
return //Nothing old to remove.
. = limb_status
- limb_status &= ~flags_to_remove
- var/changed_flags = . & flags_to_remove
+ limb_status &= ~to_remove_flags
+ var/changed_flags = . & to_remove_flags
if((changed_flags & LIMB_DESTROYED))
SEND_SIGNAL(src, COMSIG_LIMB_UNDESTROYED)
-/datum/limb/proc/add_limb_flags(flags_to_add)
- if(flags_to_add == (limb_status & flags_to_add))
+/datum/limb/proc/add_limb_flags(to_add_flags)
+ if(to_add_flags == (limb_status & to_add_flags))
return //Nothing new to add.
. = limb_status
- limb_status |= flags_to_add
- var/changed_flags = ~(. & flags_to_add) & flags_to_add
+ limb_status |= to_add_flags
+ var/changed_flags = ~(. & to_add_flags) & to_add_flags
if((changed_flags & LIMB_DESTROYED))
SEND_SIGNAL(src, COMSIG_LIMB_DESTROYED)
-/datum/limb/foot/remove_limb_flags(flags_to_remove)
+/datum/limb/foot/remove_limb_flags(to_remove_flags)
. = ..()
if(isnull(.))
return
- var/changed_flags = . & flags_to_remove
+ var/changed_flags = . & to_remove_flags
if((changed_flags & LIMB_DESTROYED) && owner.has_legs())
REMOVE_TRAIT(owner, TRAIT_LEGLESS, TRAIT_LEGLESS)
-/datum/limb/foot/add_limb_flags(flags_to_add)
+/datum/limb/foot/add_limb_flags(to_add_flags)
. = ..()
if(isnull(.))
return
- var/changed_flags = ~(. & flags_to_add) & flags_to_add
+ var/changed_flags = ~(. & to_add_flags) & to_add_flags
if((changed_flags & LIMB_DESTROYED) && !owner.has_legs())
ADD_TRAIT(owner, TRAIT_LEGLESS, TRAIT_LEGLESS)
@@ -668,6 +668,11 @@ Note that amputating the affected organ does in fact remove the infection from t
return limb_name
return null
+///Amputates the limb in the specified limb zone
+/mob/living/carbon/human/proc/amputate_limb(limb_zone)
+ var/datum/limb/limb_to_drop = get_limb(limb_zone)
+ limb_to_drop?.droplimb(TRUE, TRUE)
+
//Handles dismemberment
/datum/limb/proc/droplimb(amputation, delete_limb = FALSE)
if(limb_status & LIMB_DESTROYED)
@@ -922,23 +927,19 @@ Note that amputating the affected organ does in fact remove the infection from t
// todo this proc sucks lmao just redo it from scratch
//for arms and hands
/datum/limb/proc/process_grasp(obj/item/c_hand, hand_name)
- if (!c_hand)
+ if(!c_hand)
return
if(!is_usable())
- owner.dropItemToGround(c_hand)
- owner.emote("me", 1, "drop[owner.p_s()] what [owner.p_they()] [owner.p_were()] holding in [owner.p_their()] [hand_name], [owner.p_their()] [display_name] unresponsive!")
- return
- if(is_broken())
- if(prob(15))
- owner.dropItemToGround(c_hand)
- var/emote_scream = pick("screams in pain and", "lets out a sharp cry and", "cries out and")
- owner.emote("me", 1, "[(owner.species && owner.species.species_flags & NO_PAIN) ? "" : emote_scream ] drops what [owner.p_they()] [owner.p_were()] holding in their [hand_name]!")
- return
- if(is_malfunctioning())
- if(prob(20))
- owner.dropItemToGround(c_hand)
- owner.emote("me", 1, "drops what they were holding, [owner.p_their()] [hand_name] malfunctioning!")
+ if(owner.dropItemToGround(c_hand))
+ owner.emote("me", 1, "drops what [owner.p_they()] [owner.p_were()] holding in [owner.p_their()] [hand_name], [owner.p_their()] [display_name] unresponsive!")
+ else if(is_broken() && prob(15))
+ if(owner.dropItemToGround(c_hand))
+ var/emote_scream = owner.species?.species_flags & NO_PAIN ? "" : pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
+ owner.emote("me", 1, "[emote_scream]drops what [owner.p_they()] [owner.p_were()] holding in [owner.p_their()] [hand_name]!")
+ else if(is_malfunctioning() && prob(20))
+ if(owner.dropItemToGround(c_hand))
+ owner.emote("me", 1, "drops what [owner.p_they()] [owner.p_were()] holding, [owner.p_their()] [hand_name] malfunctioning!")
new /datum/effect_system/spark_spread(owner, owner, 5, 0, TRUE, 1 SECONDS)
///applies a splint stack to this limb. should probably be more generic but #notit
diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm
index ea5469ecdb3ca..f78e8d1432b31 100644
--- a/code/modules/organs/organ_internal.dm
+++ b/code/modules/organs/organ_internal.dm
@@ -42,7 +42,7 @@
return
var/mob/living/carbon/human/human = carbon_mob
var/datum/limb/limb = human.get_limb(parent_limb)
- LAZYDISTINCTADD(limb.internal_organs, src)
+ LAZYOR(limb.internal_organs, src)
///Signal handler to prevent hard del
/datum/internal_organ/proc/clean_owner()
@@ -50,7 +50,7 @@
owner = null
/datum/internal_organ/proc/take_damage(amount, silent= FALSE)
- if(SSticker.mode?.flags_round_type & MODE_NO_PERMANENT_WOUNDS)
+ if(SSticker.mode?.round_type_flags & MODE_NO_PERMANENT_WOUNDS)
return
if(amount <= 0)
heal_organ_damage(-amount)
diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm
index 1b2c9a05c2786..50d6b60e91876 100644
--- a/code/modules/organs/wound.dm
+++ b/code/modules/organs/wound.dm
@@ -73,7 +73,7 @@
parent_limb.createwound(CUT, 0.1)
if(!quickclot || !thwei) //Quickclot/thwei stops bleeding, magic!
- parent_limb.owner.blood_volume = max(0, parent_limb.owner.blood_volume - damage/30)
+ parent_limb.owner.set_blood_volume(parent_limb.owner.blood_volume - damage/30)
if(prob(1))
parent_limb.owner.custom_pain("You feel a stabbing pain in your [parent_limb.display_name]!", 1)
diff --git a/code/modules/paperwork/beginner_tutorials.dm b/code/modules/paperwork/beginner_tutorials.dm
new file mode 100644
index 0000000000000..61235612899a2
--- /dev/null
+++ b/code/modules/paperwork/beginner_tutorials.dm
@@ -0,0 +1,747 @@
+//Each beginner loadout in quick_load_beginners.dm has a instruction pamphlet.
+
+/obj/item/paper/tutorial/beginner_rifleman
+ name = "Rifleman Tutorial"
+ info = {"As a rifleman, you are suited for virtually all theatres of combat.\
+ Your AR-12 assault rifle is accurate and effective at all ranges, and its powerful underbarrel grenade launcher poses even further danger to mid-range threats.\
+ Inside your backpack is a box of flares to refill your flare pouch, gauze and ointment for brute (slashes) and burn (acid) wounds respectively,\
+ and backup magazines for your AR 12.\
+ Your belt contains backup magazines for your AR-12, while your body armor contains additional grenades to reload your underbarrel grenade launcher.\
+ Your left pocket contains a flare gun holster and several flares.\
+ Your right pocket contains a first aid kit, with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your helmet contains two protein bars, in case you get hungry, and your boots contain a standard-issue combat knife for clearing weeds or breaking things.
+
+ Try to spend as much time as possible near other marines - being alone is very dangerous.\
+ Your versatility is an immense strength and makes you the ideal battle buddy for virtually any other marine.\
+ You can easily work with a shotgunner to clear close quarters areas, or perhaps with a machine gunner to hold a fortified position, or even take point in front of a marksman.\
+ When not in immediate danger, use your flare gun to keep your surroundings lit, as your and your fellow marines' lives may very well depend on it.
+
+ TIPS
+
+ BKTT is an acronym used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix for any situation\
+ that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process through your system,\
+ and too many at once risks a dangerous overdose.\
+ Your gauze and ointment are body-part specific, unlike medication, but once you start applying one, you will keep applying it to all body parts that require treatment\
+ as long as you hold still. You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your AR-12, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons. The "Take Aim" button toggles aim mode, a feature that slows your rate of fire\
+ in exchange for allowing you to shoot through allied marines. (Note that your grenades will NOT go through marines!)\
+ The second option changes the firing mode, between Single Automatic, Burst, and Burst Automatic.\
+ Automatic modes will keep firing as long as you hold down the mouse button.\
+ The third option enables your underbarrel grenade launcher. Once enabled, you can use right-click to launch a grenade out!
+
+ On running out of ammo, the empty magazine will automatically eject from the rifle.\
+ To reload, simply grab a new magazine with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the rifle,\
+ which can be done without an empty hand and with a different magazine still in the gun.\
+ You can reload the underbarrel launcher by right-clicking on the gun while holding a valid grenade (like the HEDP grenades in your webbing).
+
+ Your flare gun can be rapidly reloaded by just right-clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left-clicking on it while holding a flare box.
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ Your P23 has a pistol lace attached.\
+ By toggling it in the top left while wielding it, it becomes impossible for you to drop - or for it to be knocked out of your hand by a xenomorph.\
+ Similarly, your AR-12 has a magnetic harness, which means if you drop it or otherwise lose it, it'll automatically snap back to your armor.
+
+ Because your AR-12 can effectively engage at all ranges, your optimal range is whatever your opponent's optimal range isn't.\
+ Try keeping the distance from ferocious melee enemies, while getting too close for comfort with squishier ranged ones."}
+
+/obj/item/paper/tutorial/beginner_machinegunner
+ name = "Machinegunner Tutorial"
+ info = {"As a machinegunner, you are the backbone of a marine force. While you possess heavy armor reinforced with\
+ Tyr-pattern plating (strengthening its defense even further against melee attacks), your slow move speed and the unwieldy nature of your MG-60 machinegun\
+ means you should not be spearheading any pushes. Aim mode is your best friend - combined with your bipod, you are very apt at sitting just behind the front line,\
+ eliminating threats and keeping the marines in front of you safe.\
+ Your backpack contains several additional box magazines, allowing you to carry almost two THOUSAND rounds on your person at any time.\
+ Your left pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your right pocket contains a flare gun holster and several flares. Your suit storage contains two plasma pistols, which are low in damage but can start fires.\
+ Your webbing contains an MRE to eat and both gauze and ointment, your helmet contains two protein bars for further eating,\
+ and your boots contain a standard-issue combat knife for clearing weeds or breaking things.
+
+ Your full strength is hard to utilize on your own or in the very front of battle.\
+ Your ideal positions are either safely behind a barricade guarding a front or flank from assault,\
+ or behind your fellow marines, shooting over them with aim mode to protect them from enemies.\
+ Keep in mind that your heavy armor and weapon means you move rather slowly - so if you get the order to leave a position, get moving early to avoid being left behind.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process through your system,\
+ and too many at once risks a dangerous overdose.\
+ Your gauze and ointment are body-part specific, unlike medication, but once you start applying one,\
+ you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine\
+ that is so heavily injured they are unconscious on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your MG-60, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons. The "Take Aim" button toggles aim mode, a feature that slows your rate of fire\
+ in exchange for allowing you to shoot through allied marines. The bipod button will deploy your bipod, increasing fire rate and accuracy significantly\
+ for as long as you remain stationary.
+
+ On running out of ammo, the empty magazine will automatically eject from the machine gun.\
+ To reload, simply grab a new magazine with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the machine gun, which can be done without an empty hand\
+ and with a different magazine still in the gun.
+
+ Your flare gun can be rapidly reloaded by just right-clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you from the dark.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ On your belt is a belt harness. By left clicking on your belt harness with your machine gun, you can attach them.\
+ If you drop your machine gun, or have a xenomorph make you drop it, your machine gun will automatically return to your armor if it's attached.
+
+ If you are facehugged, quickly take out your plasma pistol and shoot the ground with it, then walk into the fire.\
+ While this will cause you to be set on fire, facehuggers will detach in the presence of fire, preventing you from becoming infected.\
+ You can press B (or click resist in the bottom right) once the facehugger has detached to stop, drop, and roll, extinguishing the fire.
+
+ Your impressive magazine size means you don't need to reload often.\
+ You can suppress one spot for an impressive amount of time, and you have the ammo and damage to clear out resin walls.
+
+ The more bullets you shoot, the better a marine you are. It's actually that simple."}
+
+/obj/item/paper/tutorial/beginner_marksman
+ name = "Marksman Tutorial"
+ info = {"As a marksman, you are a master of precision and range, and should utilize both of these advantages as much as possible.\
+ Your DMR-37 is incredibly accurate at long ranges and packs a devastating punch. Due to your ability to engage at long range - and conversely,\
+ your inability to engage properly at short range - you should be staying as far from conflict as possible while still remaining in your rifle's effective range.\
+ Your backpack and both of your pouches contain spare magazines for your DMR. Your backpack also contains an MRE to eat, and both gauze and ointment for treating injuries.\
+ Your armor contains Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and an inaprovaline injector for helping other marines in critical condition.\
+ Your webbing contains the MK88 Mod 4, a fully automatic handgun for self-defense, as well as spare magazines for it.\
+ Your helmet contains protein bars to eat, and your boots contain a survival knife for clearing weeds and breaking things.
+
+ With your DMR, aim to support other marines from afar using your scope and aim mode.\
+ Your range means that many xenomorphs might not realize you're watching over an area until you're already shooting at them - use this to your advantage.\
+ Your rate of fire is relatively slow compared to automatic weapons, so make each of your shots count.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ On running out of ammo, the empty magazine will automatically eject from the DMR.\
+ To reload, simply grab a new magazine with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the DMR,\
+ which can be done without an empty hand and with a different magazine still in the gun.
+
+ While holding your DMR-37, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons.\
+ The "Take Aim" button toggles aim mode, a feature that slows your rate of fire in exchange for allowing you to shoot through allied marines.\
+ The scope button will zoom your screen out and towards the direction you're currently facing, allowing you to see (and shoot at) targets much farther away.
+
+ On your belt is a belt harness. By left clicking on your belt harness with your DMR, you can attach them. If you drop your DMR,\
+ or have a xenomorph make you drop it, your DMR will automatically return to your armor if it's attached.
+
+ Try holding your fire until your target is already engaging someone else. While this may seem counter-intuitive,\
+ it allows you to wait until they've already committed to a fight (that's likely to damage them) and may cause them to not notice your presence until it's too late,\
+ increasing the odds of securing a kill.
+
+ Do not attempt to use your DMR at too close of a range, as marksman weapons have a chance to miss against enemies that are near you.\
+ Instead, try switching to your MK88 Mod 4, your fully automatic handgun that's much more effective at close range.\
+ Use your strengths in overwatching the battlefield to assist in securing valuable kills. "}
+
+/obj/item/paper/tutorial/beginner_shotgunner
+ name = "Shotgunner Tutorial"
+ info = {"As a shotgunner, you are the spearhead of the marine force.\
+ Your semiautomatic SH-39 fires slugs that will devastate any target at short to medium range, dealing heavy damage as well as leaving them stunned and staggered.\
+ Your role is to be at the front of any marine push, side by side with your fellow marines as you charge into danger. Your shotgun shell rig on your belt,\
+ as well as your backpack, hold many additional slugs to reload your shotgun with.\
+ Your backpack also contains an MRE to eat, and both gauze and ointment for treating injuries, as well as inaprovaline.\
+ Your left pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage),\
+ Tramadol (which is a painkiller), Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage),\
+ as well as splints and inaprovaline. Your right pocket contains a flare gun holster and several flares.\
+ Your webbing contains a plasma pistol, a low damage sidearm that starts fires wherever it hits.\
+ Your suit storage contains boxes of additional flares. Your helmet contains protein bars to eat, and your boot contains a combat knife for clearing weeds and breaking things.
+
+ You should be close to the enemy constantly to take full advantage of your shotgun.\
+ This does not mean you should run off alone, as this is a good way to get yourself killed;\
+ rather, be in front of other marines, clearing away enemies to allow them to safely advance and cover you.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your SH-39, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.
+
+ Your flare gun can be rapidly reloaded by just right-clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ If you are facehugged, quickly take out your plasma pistol and shoot the ground with it, then walk into the fire.\
+ While this will cause you to be set on fire, facehuggers will detach in the presence of fire, preventing you from becoming infected.\
+ You can press B (or click resist in the bottom right) once the facehugger has detached to stop, drop, and roll, extinguishing the fire.
+
+ To reload your shotgun, take out a handful of shells with a free hand and click your gun with them while it's in your other hand.
+
+ Shotguns can take a variety of rounds, in case slugs aren't your style. Buckshot rounds have more stopping power but fall off at mid range,\
+ while flechette rounds are less generally effective in exchange for drastically improved performance against heavily armored targets.\
+ The requisitions-exclusive incendiary slugs aren't quite as powerful as standard slugs but set anything they hit on fire!
+
+ The green M50 signal flares in your body armor don't last as long as normal flares but deploying them signals to CAS (close air support)\
+ that you're requesting an airstrike in the region, also granting them the ability to see and shoot at xenomorphs in the area.
+
+ Using the powerful knockback of your shotgun to knock xenomorphs TOWARDS other marines is a good way to get kills\
+ - most xenomorphs can't deal with that many marines at once!
+
+ Shotguns don't have access to aimmode, so be careful near other marines so you don't risk shooting them.
+
+ You have incredibly high per-shot damage. Waiting a little bit to allow a xenomorph to get closer before opening fire can lure it\
+ into a false sense of safety, potentially scoring you a kill."}
+
+/obj/item/paper/tutorial/beginner_shocktrooper
+ name = "Shocktrooper Tutorial"
+ info = {"As a shock trooper, you are a versatile yet powerful frontliner, and aim to change up tactics often to gain the advantage.\
+ You use the multimodal laser rifle, an experimental battery-powered weapon with an underbarrel flamethrower.\
+ Your belt contains spare energy cells for your laser rifle. Your right pocket and body armor contain a powerpack to recharge energy cells.\
+ Your body armor also contains a box of flares. Your left pocket contains a flare gun holster and several flares.\
+ Your backpack contains a large amount of miniature fuel tanks for use with your underbarrel flamethrower, as well as an inaprovaline autoinjector.\
+ Your webbing contains Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller), Tricordrazine (heals all damage, but slowly),\
+ and gauze and ointment, which also heal brute and burn damage, respectively. Your helmet contains protein bars and your boots contain an MRE, in case you get hungry.
+
+ Switching between the different modes of your laser rifle is key to mastery on the battlefield.\
+ Like other frontliners, you aim to lead the push into enemy territory, clearing the path forward and facing xenomorphs head-on.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ On running out of ammo, the empty battery will automatically eject from the rifle.\
+ To reload, simply grab a new battery with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the battery from its storage directly onto the rifle,\
+ which can be done without an empty hand and with a different battery still in the gun.\
+ You can click a powercell to your powerpacks to recharge them. They have four times the energy of a normal magazine.\
+ To refuel your underbarrel flamethrower, right-click the gun with an empty hand to remove the old tank, then right-click the gun again with a fresh tank.
+
+ While holding your laser rifle, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons.\
+ By pressing toggle mini flamethrower, you enable your underbarrel flamethrower, which you can now shoot with right-click.
+
+ Your flare gun can be rapidly reloaded by just right clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ By pressing unique action (default: space bar), you can cycle between the different modes of your laser gun.\
+ Standard mode rapidly fires laser beams, Overcharge mode fires more powerful beams at a lower rate of fire, weakening mode slows the target mildly\
+ as well as draining their plasma, and microwave applies a stacking debuff (up to five times) that deals armor-piercing damage over time.\
+ Note that different modes consume battery charge at different rates.
+
+ Laser weapons, unlike traditional ballistics, can fire through windows unimpeded.\
+ Use this with stronger windows, such as ballistic glass, to attack the enemy without them being able to attack you back."}
+
+/obj/item/paper/tutorial/beginner_hazmat
+ name = "Hazmat Tutorial"
+ info = {"As a HAZMAT, you excel in situations too dangerous for other marines. Your Mimir type armor grants you complete immunity to toxic gas,\
+ from acid to neurotoxin. It also provides an increased resistance against acid in general, for dealing with ranged xenomorphs.\
+ Your AR-11 is somewhat unwieldy and inaccurate, but packs both potent bursts and an impressive 70-round magazine.\
+ Your backpack, left pouch, and suit storage are all filled with spare magazines for your AR-11.\
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your webbing contains flares for lighting areas, gauze and ointment for treating wounds, and a miniature fire extinguisher.\
+ Your helmet contains protein bars and your boots contain an MRE, for if you get hungry.
+
+ Unlike other marines, you have no reason to fear toxic gas - and thanks to your tactical sensor, you pose quite a threat to xenomorphs while in it.\
+ Hide in smoke and use your sensor to fire at xenomorphs that can't see you back.\
+ In the absence of smoke, your AR-11 is still quite powerful, and can be used in many situations, though its inaccuracy makes it somewhat less potent at longer ranges.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your AR-11, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons.\
+ The "Take Aim" button toggles aim mode, a feature that slows your rate of fire in exchange for allowing you to shoot through allied marines.\
+ The second option changes the firing mode, between Single Automatic, Burst, and Burst Automatic. Automatic modes will keep firing as long as you hold down the mouse button.\
+ The tactical sensor option toggles your tactical sensor - you should keep this on always.
+
+ Your tactical sensor will periodically blip, detecting moving targets in an area a little bigger than your screen.\
+ Green circles are friendly targets (or anyone wearing a marine ID), while red circles accompanied with an audible blip are unknown (almost always hostile) targets.\
+ This sensor works even without vision, such as through any form of smoke and through walls.
+
+ On running out of ammo, the empty magazine will automatically eject from the rifle.\
+ To reload, simply grab a new magazine with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the rifle, which can be done without an empty hand\
+ and with a different magazine still in the gun.
+
+ Your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.\
+ However, note that xenomorphs will often determine a marine's position in a smoke cloud by their light, so you should turn OFF your light if hiding in smoke!
+
+ On your belt is a belt harness. By left-clicking on your belt harness with your AR-11, you can attach them.\
+ If you drop your AR, or have a xenomorph make you drop it, your AR will automatically return to your armor if it's attached.
+
+ While you're no machinegunner, you have over 700 rounds on you. Don't be afraid to shoot at anything that blips on your tactical sensor\
+ (as long as there aren't friendlies in the way!)"}
+
+/obj/item/paper/tutorial/beginner_cqc
+ name = "CQC Tutorial"
+ info = {"As a CQC marine, you are incredibly mobile, and should be using and abusing your speed to dart in and out of danger.\
+ You are effective both spearheading the assault and pushing into flanks.\
+ Your AR-18 carbine isn't the most dangerous rifle, nor does it have a particularly high magazine size, but it's incredibly lightweight\
+ compared to almost any other weapon, and its relative accuracy and stability even while moving and high fire rate allow it to pose\
+ a surprise threat to almost any xenomorphs. Your belt, body armor, and backpack all contain spare magazines for your AR-18.\
+ Your backpack also contains an MRE (in case you get hungry) as well as gauze and ointment to treat injuries with.\
+ Your left pocket contains a flare gun and several flares.\
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your webbing contains gauze and ointment for healing, an MRE for eating, and two boxes of flares.\
+ Your helmet contains protein bars for eating, and your boots contain a combat knife for clearing weeds and breaking things.
+
+ Your speed is your greatest strength. You should be using it to rush into combat and chase after already injured enemies,\
+ only to rapidly retreat before things turn south. You're ideal at scouting locations, quickly reinforcing threatened positions, and being everywhere at once.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your AR-18, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons.\
+ The "Take Aim" button toggles aim mode, a feature that slows your rate of fire in exchange for allowing you to shoot through allied marines.\
+ The second option changes the firing mode, between Single Automatic, Burst, and Burst Automatic.\
+ Automatic modes will keep firing as long as you hold down the mouse button. The tactical sensor option toggles your tactical sensor - you should keep this on always.
+
+ On running out of ammo, the empty magazine will automatically eject from the rifle.\
+ To reload, simply grab a new magazine with an empty hand and click your gun with it.\
+ Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the rifle, which can be done without\
+ an empty hand and with a different magazine still in the gun.
+
+ Your flare gun can be rapidly reloaded by just right-clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ Don't be afraid to charge headfirst into danger if you think you can save a teammate or get a kill - you have the speed to get back out, after all.\
+ The ALT key by default allows humans or clones to sprint at the cost of stamina, to go even faster!
+
+ While your rifle runs out of ammo quickly, its rapid-fire four-round bursts deal impressive damage. Combined with your speed, you are the master of ambushing."}
+
+/obj/item/paper/tutorial/beginner_chad
+ name = "Grenadier Tutorial"
+ info = {"As a grenadier, you are the master of area denial. Your six-chamber GL-70 grenade launcher boasts unparalleled room-clearing potential,\
+ and impressive lethality - just take care to avoid harming your fellow marines.\
+ Your belt, backpack, both pockets, and body armor are all filled with HEDP grenades to reload your grenade launcher with.\
+ Your webbing contains Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller), Tricordrazine (heals all damage, but slowly),\
+ and gauze and ointment, which also heal brute and burn damage respectively. Your backpack also contains an inaprovaline injector.\
+ Your helmet contains two protein bars, in case you get hungry, and your boots contain a derringer, a two-shot sidearm for when the first six grenades didn't kill the bug.
+
+ Your power is as much of a liability as it is a utility if you aren't careful.\
+ Before you get happy on the trigger, make SURE there aren't going to be marines in the blast radius, unless you want to end up filled with bullet holes\
+ (which your Hod accident prevention plating will partially block!) With that warning out of the way, you can kill even the beefiest of xenomorphs with good aim.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ While holding your grenade launcher, press Z to wield it. You MUST wield your grenade launcher to use it!
+
+ To reload your grenade launcher, grab a grenade from one of your storages and left-click the grenade launcher with it while it's in your other hand.
+
+ Hlin-pattern armor plating, orderable from requisitions, makes you practically immune to explosives. Get trigger happy!\
+ (Don't get TOO trigger happy, though - your fellow marines are NOT immune.)
+
+ Your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ As a grenadier, you hold the power to clear rooms and control territory like no other. Victory is just a well-placed grenade away."}
+
+/obj/item/paper/tutorial/builder
+ name = "Builder Tutorial"
+ info = {"The Builder loadout is designed around you establishing defenses, barricades made from metal, plasteel or sandbags.\
+ You are the frontline - without you marines will be exposed to attacks from any and all directions.\
+ Your backpack contains some materials, a box of flares, and extra drums for your gun, as well as gauze and ointment to treat injuries with.
+ Your left pocket contains a tool pouch for all the tools you'll need to perform your engineering duties.\
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your helmet contains protein bars for eating, and your boots contain an MRE for further eating.\
+ The optical mesons on your eyewear slot give you the ability to see the shape of rooms behind solid walls, though you can't see anything (including xenomorphs!)\
+ behind those walls.\
+ Use your quicker build speed and tools to aid and repair barricades, and fix APCs for generating the nuclear disks to win the round!\
+ Your suit storage contains materials, and your loadout also containsa MG42 Light machine gun for self defense and suppression,\
+ and a radiopack for ordering more material to entrench and establish a fortified defensive position.
+
+ TIPS
+
+ In your webbing you will find a spare powercell and a handheld cell crank charger to charge them, when fixing apcs swap the empty battery for\
+ your full one. Insert the empty one into your crank, press Z to start charging, and charge it for the next disk!
+
+ When building defensive barricades it is best to not make them "flush" with nearby doors or walls.\
+ Instead pull back 1 tile and build it there; this prevents xenos from hiding around the corner behind the walls and smacking your cades freely without repercussion.
+
+ All metal barricades can be upgraded, the basic upgrade is barbed wire.\
+ This damages xenos when they attack the barricade and prevents them (and marines!) from climbing over the barricade.\
+ Press Z with metal sheets in your hand to open up a radial menu where you can select to build barbed wire.\
+ You can also build razorwire, which you can deploy to the tile in front of you by using it in-hand. Razorwire can trap charging xenomorphs momentarily to\
+ allow marines to shoot them.\
+ You can click a barricade with a piece of metal to open a radial menu to upgrade it. Cades have to be at full health to upgrade, so you might need to click them with
+ a welder first to fix any damages.\
+ Caustic armor increases the cade's resistance to acid spit and prevents it from being melted.\
+ Concussive armor increases the cade's resistance to explosions and Warlock's gravity crush ability.\
+ Ballistic armor increases the cade's resistance to projectile and melee damage and xenomorph charges.\
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol\
+ used as an all-rounder combat medicine mix for any situation that heals all different types of damage.\
+ Make sure not to take more than two of each pill at a time - medicine takes a while to process through your system,
+ and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ Through your building expertise, marines can hold various critical locations, ensuring steady progress towards mission completion."}
+
+/obj/item/paper/tutorial/flamer
+ name = "Flamer Tutorial"
+ info = {"As a Flamethrower specialist, your job is to burn, burn some more and BURN again.\
+ You are equipped with a flamethrower bag that refills your flamethrower every time you insert it back into the bag,\
+ and also have a laser carbine for more practical and pragmatic self-defense. Also comes with a large box of claymore anti-personnel mines,\
+ and some general materials for helping fortify positions in the suit storage.
+ Your backpack contains some materials, a box of flares, and extra drums for your gun, as well as gauze and ointment to treat injuries with.
+ Your left pocket contains a tool pouch for all the tools you'll need to perform your engineering duties.\
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your helmet contains protein bars for eating, and your boots contain an MRE for further eating.\
+ The optical mesons on your eyewear slot give you the ability to see the shape of rooms behind solid walls, though you can't see anything (including xenomorphs!)\
+ behind those walls.\
+ Removing resin walls will help open up the battlefield for your fellow marines, ensuring greater vision and mobility, and, hopefully, a greater number of successful\
+ fights against xenomorphs.\
+
+ TIPS
+
+ Your flamethrower is best used to clear resin walls, it is a poor weapon for self defense and is best used to help carve a path through\
+ enemy mazes and to deny areas of movement without punishing xenos for trekking through the flames.
+
+ Red resin walls are fire-resistant and require you to engage them in close quarters with a melee weapon to detroy them - the bayonet on your laser carbine is good for this,\
+ just be careful about any xenomorphs lurking in the mazes!
+
+ Requisitions offers many useful upgrades to your kit. You can request a SURT pyrotechnic module for your armor that will make you unable to be set on fire.\
+ You can also request X Fuel, a fuel for flamethrowers that burns hotter for longer and appears blue.\
+
+ Your laser carbine is good for short-range defense. You can toggle the modes of it using unique action (default: space bar).\
+ The spread mode deals greater armor penetration and damage but is slow to fire. Impact mode knocks back targets. Cripple mode will slow enemies down.
+
+ In your webbing you will find a spare powercell and a handheld cell crank charger to charge them, when fixing apcs swap the empty battery for\
+ your full one. Insert the empty one into your crank, press Z to start charging, and charge it for the next disk!
+
+ Your claymore mines are useful for denying an area from being easily flanked and can cause serious disruption for (or even kill)\
+ backlining xenomorphs trying to cause you a bad day.
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose.\
+ Your gauze and ointment are body-part specific, unlike medication, but once you start applying one, you will keep applying\
+ it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ By removing resin structures with your flamethrower, you ensure area denial and dominance, flushing xenomorphs out and providing favorable battle circumstances for your\
+ fellow marines."}
+
+/obj/item/paper/tutorial/plasmacutter
+ name = "Plasma Cutter Tutorial"
+ info = {"Tired of watching marines endlessly pour into a maze or terribly held choke point? This is the class for you then!\
+ With your plasma cutter, you will be able to easily delete resin walls from existence, and carve through metal, reinforced, or even solid rock walls!\
+ With this kit you'll be able to widen choke points and eradicate mazes with ease.\
+ This loadout also comes with a few materials for defenses in your suit storage, and a MP19 SMG for self-defense in your technician welderpack.\
+ Your left pocket contains a tool pouch for all the tools you'll need to perform your engineering duties.\
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your helmet contains protein bars for eating, and your boots contain an MRE for further eating.\
+ The optical mesons on your eyewear slot give you the ability to see the shape of rooms behind solid walls, though you can't see anything (including xenomorphs!)\
+ behind those walls.\
+ Removing chokes and flanks will help your team to take better angles and more successfully push objectives.\
+
+ TIPS
+
+ Your Plasma Cutter (often abbreviated to PC) is a very versatile tool but it contains a limited charge of 7500;\
+ for resin walls the charge is rather miniscule at 100 Charge but a much heavier or thicker metallic or rock wall will cost you 1000 Charge,\
+ so make sure to keep track of how much charge your battery contains!\
+ Do remember to keep your welding module or goggles on when using it, however, as the Plasma Cutter will damage your eyes!
+
+ In your webbing you will find a spare powercell and a handheld cell crank charger to charge them, when fixing apcs swap the empty battery for\
+ your full one. Insert the empty one into your crank, press Z to start charging, and charge it for the next disk!
+
+ Your Plasma Cutter can be used as a melee weapon in emergency situations, while not the best by any means it can work in a pinch\
+ and if you manage to smack a xenomorph you'll get rewarded with draining them of a small amount of plasma and earning a bit of charge for your Plasma Cutter.\
+ Use this to destroy mazes and punish xenomorphss for trying to attack you by refilling your battery.
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still.\
+ Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ Your ability to treat terrain as a sandbox has infinite potential for assisting your allies."}
+
+/obj/item/paper/tutorial/lifesaver
+ name = "Lifesaver Tutorial"
+ info = {"As the lifesaver, you are a MEDIC first and foremost. You should be prioritizing healing marines over trying to fight xenomorphs yourself.\
+ Your belt contains many pill bottles - examine them to find out what they do with shift+click, and draw from them with right-click.\
+ Your belt also contains splints, which are used on fractured bones, and a medical analyzer, which will tell you exactly what's wrong with a person.\
+ Avoid giving someone more than one pill of a given medicine at a time; many pills overdose at three, and some at two, and some marines might go and take a pill themselves,\
+ so one is safest. In your armor storage are an assortment of autoinjectors. Combat injectors should be used on marines in active danger, Quick Clot Plus helps deal\
+ with internal bleeding, Peridaxon Plus heals organs, and Dexalin Plus helps with deoxygenation.\
+ Your right pouch contains three stacks of trauma and burn kits, which will cause a body part they're applied to to heal brute or burn damage over time respectively.\
+ It also contains a hypospray full of MeraDerm, a medicine mixture that heals both brute and burn damage quickly.\
+ Your webbing contains Oxycodone, a painkiller; Nanoblood, a blood replacement; a stasis bag to hold patients you aren't actively treating in to prevent their\
+ condition from worsening; tweezers to remove shrapnel; a roller bed to roll around patients with; and a medivac to evacuate patients.\
+ Your boots and helmet contain food.
+
+ Stay away from the frontlines - let patients come to (or be dragged to) you instead of putting yourself in danger.\
+ Try to remain in a safe location, as xenomorphs do not obey the Geneva Convention and will in fact deliberately target you and your patients as often as possible.
+
+ TIPS
+
+ Your gloves are defibrillators. By clicking on any dead target with their exosuit removed (drag their sprite onto your sprite to remove it)\
+ you will attempt to bring them back to life, healing them somewhat and then resuscitating them if they're healed enough.\
+ Drag your gloves to your backpack to recharge them. This even works on robots!\
+ Make sure your intent is help while doing this or you might just punch them right after they revive, taking them out again.
+
+ While holding your repeater, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons.\
+ The "Take Aim" button toggles aim mode, a feature that slows your rate of fire in exchange for allowing you to shoot through allied marines.
+
+ As your rifle is bolt-action, it needs to be racked after every shot. Do this by pressing your Unique Action key, which defaults to the spacebar.
+
+ Your backpack contains ammo packets. You can click on your shotgun shell pouch to quickly transfer ammo into the pouch.\
+ You can then reload your repeater by clicking it while it's in your hand with the handful of bullets.
+
+ Before you do ANYTHING to a patient, use your medical analyzer on them. Not analyzing is the number one cause of overdoses.\
+ Right-clicking with the analyzer instead shows them their own health scan, useful for getting their attention or informing them that they're fully healed.
+
+ When you dispense your equipment, a medivac beacon will appear on the floor.\
+ Pick this up, take your medivac and click it on the beacon so it says linked!\
+ Once done, you should go to your ship's medical bay and place the beacon by pressing Z with it in hand.\
+ Once groundside, you can now medivac people for treatment shipside.\
+ Shipside can fix bone fractures, clone damage, facehugging, and anything else you can't.\
+ To evac someone, deploy your medivac by pressing Z with it in hand, drag them onto it to buckle them to it, then right click to send them up.\
+ Drag the medivac to you to pick it back up once you're done.
+
+ Marines will "go cold" after five minutes of being dead, rendering them permanently unrevivable.\
+ This timer can be extended via your stasis bag or with CPR, which other marines can perform while you work by left-clicking the corpse on help intent\
+ while neither of them are wearing a mask.
+
+ Accidentally overdose a marine? They're full of deadly neurotoxin? Don't panic - use Hypervene.\
+ While uncomfortable for the marine, this medication (located in your medical belt) will rapidly purge their system.
+
+ You can use Meralyne and Dermaline at the same time as Bicaridine and kelotane, for an accelerated healing rate. Keep the Corps well and the rest will follow."}
+
+/obj/item/paper/tutorial/hypobelt
+ name = "Hypobelt Tutorial"
+ info = {"As the hypobelt medic, you are the master of rapid healing.\
+ Your belt is full of hyposprays which instantly apply a dose of medicine when you click a marine with them.\
+ Examine them with shift+click to read their labels to find out what they do.\
+ Avoid injecting someone more than once or twice with the same medicine to prevent an overdose!\
+ Your pouch contains three stacks of trauma and burn kits, which will cause a body part they're applied to to heal brute or burn damage over time respectively.\
+ It also contains a hypospray full of MeraDerm, a medicine mixture that heals both brute and burn damage quickly.\
+ These hyposprays can be refilled by the bottles in the syringe cases of your belt.\
+ Your webbing is filled with splints for treating fractures.\
+ Your body armor contains Oxycodone, a painkiller; a stasis bag to hold patients you aren't actively treating in to prevent their condition from worsening;\
+ tweezers to remove shrapnel; a roller bed to roll around patients with; and a medivac to evacuate patients.\
+ Your boots and helmet contain food.
+
+ Your light armor and quick injectors make you adept at rapidly getting marines back into the action.\
+ However, take care to avoid danger; xenomorphs WILL target you, and you will go down fast without proper protection.
+
+ TIPS
+
+ Your gloves are medical analyzers, which you can use on a patient by left clicking them.\
+ Before you do ANYTHING to a patient, use your medical analyzer on them.\
+ Not analyzing is the number one cause of overdoses.\
+ Right-click with the analyzer instead shows them their own health scan, useful for getting their attention or informing them that they're fully healed.
+
+ In your backpack is a defibrillator. By holding it and clicking on any dead target with their exosuit removed (drag their sprite onto your sprite to remove it)\
+ you will attempt to bring them back to life, healing them somewhat and then resuscitating them if they're healed enough.\
+ Drag your defib to your backpack to recharge them. This even works on robots!
+
+ When you dispense your equipment, a medivac beacon will appear on the floor.\
+ Pick this up, take your medivac and click it on the beacon so it says linked!\
+ Once done, you should go to your ship's medical bay and place the beacon by pressing Z with it in hand.\
+ Once groundside, you can now medivac people for treatment shipside. Shipside can fix bone fractures, clone damage, facehugging, and anything else you can't.\
+ To evac someone, deploy your medivac by pressing Z with it in hand, drag them onto it to buckle them to it, then right-click to send them up.\
+ Drag the medivac to you to pick it back up once you're done.
+
+ Marines will "go cold" after five minutes of being dead, rendering them permanently unrevivable.\
+ This timer can be extended via your stasis bag or with CPR, which other marines can perform while you work by left-clicking the corpse\
+ on help intent while neither of them are wearing a mask.
+
+ Accidentally overdose a marine? They're full of deadly neurotoxin? Don't panic - use Hypervene.\
+ While uncomfortable for the marine, this medication (located in your medical belt) will rapidly purge their system.
+
+ You can use Meralyne and Dermaline at the same time as Bicaridine and kelotane, for an accelerated healing rate.
+
+ As your shotgun is pump-action, you'll need to pump it after every shot by pressing Unique Action (default space bar).
+
+ You can reload your shotgun by grabbing a handful of slugs from your backpack and clicking your shotgun with them.
+
+ Remember your primary goal is to keep the force healthy and allow them to continue with progressing the operation."}
+
+/obj/item/paper/tutorial/smartmachinegunner
+ name = "Smartmachinegunner Tutorial"
+ info = {"As the smartmachinegunner, you are the very backbone of your squad, and should be behind another marine or three at all times.\
+ Your SG-29 is capable of firing directly through your teammates without risk of harm, so staying safe and behind your allies is essential\
+ to gaining full value out of it. Your backpack and body armor contain both fire extinguisher and spare ammo, with your backpack also containing\
+ a plasma pistol to start fires with, inaprovaline, and a cloak grenade to escape skirmishes. Your left pouch contains a flare gun holster and several flares.\
+ Your right pouch contains a first aid kit complete with Bicaridine (heals brute damage), Kelotane (heals burn damage), Tramadol (a painkiller),\
+ Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage), as well as splints and inaprovaline.\
+ Your webbing contains flares for creating lights and gauze and ointment for treating injuries.\
+ Your helmet and boots contain food, in case you get hungry.
+
+ You should NEVER be at the front of a group of marines.\
+ Aim to provide covering fire for those who are in front, and let them protect you in turn by, well, being in front of you.\
+ Remember that your SG-29 fires through marines, so you don't need to worry about friendly fire.
+
+ TIPS
+
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose.\
+ Your gauze and ointment are body-part specific, unlike medication, but once you start applying one, you will keep applying it to all body parts that\
+ require treatment as long as you hold still. Your splints are used to alleviate the effects of bone fractures, by applying them to a fractured limb.\
+ Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is so heavily injured they are unconscious\
+ on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right-clicking on the packet, even while it's in storage.
+
+ Your flare gun can be rapidly reloaded by just right-clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ On your belt is a belt harness. By left clicking on your belt harness with your machine gun, you can attach them.\
+ If you drop your machine gun, or have a xenomorph make you drop it, your machine gun will automatically return to your armor if it's attached.
+
+ If you are facehugged, quickly take out your plasma pistol and shoot the ground with it, then walk into the fire.\
+ While this will cause you to be set on fire, facehuggers will detach in the presence of fire, preventing you from becoming infected.\
+ You can press B (or click resist in the bottom right) once the facehugger has detached to stop, drop, and roll, extinguishing the fire.
+
+ Your impressive magazine size means you don't need to reload often. You can suppress one spot for an impressive amount of time,\
+ and you have the ammo and damage to clear out resin walls.
+
+ While holding your SG-29, use Z to wield your weapon with both hands, increasing accuracy and stability and reducing recoil.\
+ In the top left of your screen are several weapon-specific buttons. The tactical sensor option toggles your tactical sensor - you should keep this on always.
+
+ Your tactical sensor will periodically blip, detecting moving targets in an area a little bigger than your screen.\
+ Green circles are friendly targets (or anyone wearing a marine ID), while red circles accompanied with an audible blip are unknown (almost always hostile) targets.\
+ This sensor works even without vision, such as through any form of smoke and through walls.
+
+ On running out of ammo, the empty magazine will automatically eject from the smartgun. To reload, simply grab a new magazine with an empty hand\
+ and click your gun with it. Alternatively, you can perform a tactical reload by click-dragging the magazine from its storage directly onto the rifle,\
+ which can be done without an empty hand and with a different magazine still in the gun.
+
+ STAY BEHIND OTHER MARINES. I cannot stress this enough. You are a priority target for xenomorphs due to your ability to provide covering fire from behind other marines.
+
+ Your massive drum size of 250 rounds means you don't need to reload often. Because of this, you should avoid reloading in dangerous areas if you can help it,\
+ instead waiting until you're back behind fortifications or other marines.
+
+ Your ammunition refills will come from Requisitions. To request something, say :u followed by a clear and polite request as to what you would like to receive.\
+ For example, if you ran out of ammo, you might say ":u RO, requesting SG-85 bins to the FC's beacon."\
+ After some amount of time, you will likely get a response in the requisitions channel (pay attention!) along the lines of "Yourname, your order is ready. Sending."\
+ After some time, you should hear a WOOSH noise, and a box will teleport to the beacon with what you requested.\
+ Note that requisitions is the ONLY place you can get more smartgun ammo!
+
+ You are the most mobile among smartgunners - use this to your advantage. You are the best at providing cover fire for a mobile squad."}
+
+/obj/item/paper/tutorial/smartminigunner
+ name = "Smartminigunner Tutorial"
+ info = {"As the smartminigunner, you are the very embodiment of BRRT. With your huge SG-85 smart minigun,\
+ you can fire ten rounds per second for one hundred straight seconds, providing powerful covering fire for other marines.\
+ No enemy wants to get stuck in your line of fire. Instead of a backpack you carry a back mounted powerpack that feeds and powers your SG-85.\
+ In your body armor are two bins to refill your powerpack with. Your left pouch contains a flare gun holster and several flares. \
+ Your right pouch contains a first aid kit, complete with Bicaridine (heals brute damage), Kelotane (heals burn damage),\
+ Tramadol (a painkiller), Tricordrazine (heals all damage, but slowly), and Dylovene (heals toxin damage),\
+ as well as splints and inaprovaline. Your webbing contains flares for creating lights and gauze and ointment for treating injuries.\
+ Your helmet and boots contain food, in case you get hungry.
+
+ Your minigun boasts both high levels of armor piercing and the ability to shoot through allies - use both to your advantage.\
+ Note that the heavy nature of your minigun and your brief windup before you can fire means you're best positioned defensively, firing at the toughest targets within range.
+
+ TIPS
+ BKTT is an acronym that is used to describe the combination of Bicaridine, Kelotane, Tricordizine, and Tramadol used as an all-rounder combat medicine mix\
+ for any situation that heals all different types of damage. Make sure not to take more than two of each pill at a time - medicine takes a while to process\
+ through your system, and too many at once risks a dangerous overdose. Your gauze and ointment are body-part specific, unlike medication, but once you start\
+ applying one, you will keep applying it to all body parts that require treatment as long as you hold still. Your splints are used to alleviate the effects of bone fractures,\
+ by applying them to a fractured limb. Your inaprovaline autoinjector is not to be applied to yourself - rather, it should be applied to an alive marine that is\
+ so heavily injured they are unconscious on the ground (referred to as "critical condition") to rescue them from that state.\
+ You can remove pills from their packets directly by right clicking on the packet, even while it's in storage.
+
+ Your flare gun can be rapidly reloaded by just right clicking the flare pouch with it in hand.\
+ Your flare pouch can be refilled by left clicking on it while holding a flare box.\
+ Flare any dark area you can see to reduce the risk of a xenomorph ambushing you.\
+ On a similar note, your suit's light can be toggled in the top left - you should almost always keep this on to help your visibility.
+
+ On your belt is a belt harness. By left clicking on your belt harness with your minigun, you can attach them.\
+ If you drop your minigun, or have a xenomorph make you drop it, your machine gun will automatically return to your armor if it's attached.\
+ On the same note, by left clicking your powerpack, you hook up your minigun, allowing it to draw from it for ammo.\
+ If you drop your minigun, even if it's saved by the belt harness, you will have to re-attach it to the powerpack.
+
+ To reload your power back, take it into your hand, then grab an ammo bin with your other hand and click the power pack with it.
+
+ While holding your SG-85, use Z to wield your weapon with both hands, which is required to fire it. In the top left of your screen are several weapon-specific buttons.\
+ The tactical sensor option toggles your tactical sensor - you should keep this on always.
+
+ Your tactical sensor will periodically blip, detecting moving targets in an area a little bigger than your screen.\
+ Green circles are friendly targets (or anyone wearing a marine ID), while red circles accompanied with an audible blip are unknown (almost always hostile) targets.\
+ This sensor works even without vision, such as through any form of smoke and through walls.
+
+ Your ammunition refills will come from Requisitions. To request something, say :u followed by a clear and polite request as to what you would like to receive.\
+ For example, if you ran out of ammo, you might say ":u RO, requesting SG-85 bins to the FC's beacon."\
+ After some amount of time, you will likely get a response in the requisitions channel (pay attention!) along the lines of "Yourname, your order is ready. Sending."\
+ After some time, you should hear a WOOSH noise, and a box will teleport to the beacon with what you requested.\
+ Note that requisitions is the ONLY place you can get more smartgun ammo!
+
+ STAY BEHIND OTHER MARINES. I cannot stress this enough. You are a priority target for xenomorphs due to your ability to provide covering fire from behind other marines.
+
+ You almost never need to reload - you have enough rounds to fire for almost two straight minutes.\
+ Because of this, you should exclusively reload when it is completely safe to do so, as other marines are counting on you to protect them.
+
+ Your minigun boasts an incredibly high amount of armor piercing. Aim for particularly durable targets, like Crushers and Kings, as you'll likely do a lot more damage."}
diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm
index 27357cecf4b78..8639ccf0610c1 100644
--- a/code/modules/paperwork/carbonpaper.dm
+++ b/code/modules/paperwork/carbonpaper.dm
@@ -10,7 +10,8 @@
var/iscopy = 0
-/obj/item/paper/carbon/update_icon()
+/obj/item/paper/carbon/update_icon_state()
+ . = ..()
if(iscopy)
if(info)
icon_state = "cpaper_words"
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index f00baa297f248..6065552478f12 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -12,7 +12,7 @@
throw_range = 10
var/obj/item/tool/pen/haspen //The stored pen.
var/obj/item/toppaper //The topmost piece of paper.
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/clipboard/Initialize(mapload)
. = ..()
@@ -35,18 +35,21 @@
return
-/obj/item/clipboard/update_icon()
- overlays.Cut()
+/obj/item/clipboard/update_overlays()
+ . = ..()
+
if(toppaper)
- overlays += toppaper.icon_state
- overlays += toppaper.overlays
+ . += toppaper.icon_state
+ . += toppaper.overlays
if(haspen)
- overlays += "clipboard_pen"
- overlays += "clipboard_over"
+ . += "clipboard_pen"
+ . += "clipboard_over"
/obj/item/clipboard/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo))
user.drop_held_item()
diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm
index 0fbcadd084357..9afd5eb71c681 100644
--- a/code/modules/paperwork/filingcabinet.dm
+++ b/code/modules/paperwork/filingcabinet.dm
@@ -39,6 +39,8 @@
/obj/structure/filingcabinet/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper) || istype(I, /obj/item/folder) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
if(!user.transferItemToLoc(I, src))
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 746aebeffcd47..58832643e9f75 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -43,14 +43,16 @@
if(updateicon)
update_icon()
-/obj/item/folder/update_icon()
- overlays.Cut()
+/obj/item/folder/update_overlays()
+ . = ..()
if(length(contents))
- overlays += "folder_paper"
- return
+ . += "folder_paper"
+
/obj/item/folder/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
if(!user.transferItemToLoc(I, src))
return
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index b37b62ba8e55d..b85eab4f19b10 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -16,8 +16,8 @@
w_class = WEIGHT_CLASS_TINY
throw_range = 1
throw_speed = 1
- flags_equip_slot = ITEM_SLOT_HEAD
- flags_armor_protection = HEAD
+ equip_slot_flags = ITEM_SLOT_HEAD
+ armor_protection_flags = HEAD
attack_verb = list("bapped")
var/info //What's actually written on the paper.
@@ -51,9 +51,8 @@
update_icon()
updateinfolinks()
-/obj/item/paper/update_icon()
- if(icon_state == "paper_talisman")
- return
+/obj/item/paper/update_icon_state()
+ . = ..()
if(info)
icon_state = "paper_words"
return
@@ -106,22 +105,26 @@
user.visible_message(span_notice("You show the paper to [M]. "), \
span_notice(" [user] holds up a paper and shows it to [M]. "))
examine(M)
+ return
- else if(user.zone_selected == "mouth") // lipstick wiping
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H == user)
- to_chat(user, span_notice("You wipe off the lipstick with [src]."))
- H.lip_style = null
- H.update_body()
- else
- user.visible_message(span_warning("[user] begins to wipe [H]'s lipstick off with \the [src]."), \
- span_notice("You begin to wipe off [H]'s lipstick."))
- if(do_after(user, 10, NONE, H, BUSY_ICON_FRIENDLY))
- user.visible_message(span_notice("[user] wipes [H]'s lipstick off with \the [src]."), \
- span_notice("You wipe off [H]'s lipstick."))
- H.lip_style = null
- H.update_body()
+ if(user.zone_selected == "mouth") // lipstick wiping
+ if(!ishuman(M))
+ return
+ var/mob/living/carbon/human/H = M
+ if(H == user)
+ to_chat(user, span_notice("You wipe off the lipstick with [src]."))
+ H.makeup_style = null
+ H.update_body()
+ return
+
+ user.visible_message(span_warning("[user] begins to wipe [H]'s lipstick off with \the [src]."), \
+ span_notice("You begin to wipe off [H]'s lipstick."))
+ if(!do_after(user, 10, NONE, H, BUSY_ICON_FRIENDLY))
+ return
+ user.visible_message(span_notice("[user] wipes [H]'s lipstick off with \the [src]."), \
+ span_notice("You wipe off [H]'s lipstick."))
+ H.makeup_style = null
+ H.update_body()
/obj/item/paper/proc/addtofield(id, text, links = 0)
var/locid = 0
@@ -282,6 +285,8 @@
/obj/item/paper/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo))
if(istype(I, /obj/item/paper/carbon))
@@ -354,8 +359,9 @@
icon_state = "commendation"
fields = 5
-/obj/item/paper/commendation/update_icon() //it looks fancy and we want it to stay fancy.
+/obj/item/paper/commendation/update_icon_state() //it looks fancy and we want it to stay fancy.
return
+
/*Let this be a lesson about pre-made forms.
when building your paper, use the above parsed pen code in parsepencode(). no square bracket anything in the info field.
@@ -432,9 +438,10 @@ then, for every time you included a field, increment fields. */
name = "paper scrap"
icon_state = "scrap"
-/obj/item/paper/crumpled/update_icon()
+/obj/item/paper/crumpled/update_icon_state()
return
+
/obj/item/paper/crumpled/bloody/
icon_state = "scrap_bloodied"
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index 36bfd5eddd392..aa1760c18863a 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -19,6 +19,8 @@
/obj/item/paper_bundle/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
@@ -196,36 +198,51 @@
usr.dropItemToGround(src)
qdel(src)
-/obj/item/paper_bundle/update_icon()
+/obj/item/paper_bundle/update_icon_state()
+ . = ..()
if(length(contents))
var/obj/item/I = contents[1]
icon_state = I.icon_state
- overlays = I.overlays
+
+/obj/item/paper_bundle/update_desc(updates)
+ . = ..()
+ var/paper_number = 0
+ var/photo = FALSE
+ for(var/obj/thing in src)
+ if(istype(thing, /obj/item/paper))
+ paper_number++
+ else if(istype(thing, /obj/item/photo))
+ photo = TRUE
+ if(paper_number>1)
+ desc = "[paper_number] papers clipped to each other."
+ else
+ desc = "A single sheet of paper."
+ if(photo)
+ desc += "There is a photo attached to it."
+
+
+/obj/item/paper_bundle/update_overlays()
+ . = ..()
+ if(length(contents))
+ var/obj/item/I = contents[1]
+ . = I.overlays
underlays = 0
- var/i = 0
- var/photo
+ var/paper_number = 0
for(var/obj/O in src)
var/image/IMG = image('icons/obj/items/paper.dmi')
if(istype(O, /obj/item/paper))
IMG.icon_state = O.icon_state
- IMG.pixel_x -= min(1*i, 2)
- IMG.pixel_y -= min(1*i, 2)
- pixel_x = min(0.5*i, 1)
- pixel_y = min( 1*i, 2)
+ IMG.pixel_x -= min(1*paper_number, 2)
+ IMG.pixel_y -= min(1*paper_number, 2)
+ pixel_x = min(0.5*paper_number, 1)
+ pixel_y = min( 1*paper_number, 2)
underlays += IMG
- i++
+ paper_number++
else if(istype(O, /obj/item/photo))
var/obj/item/photo/PH = O
IMG = PH.picture.picture_icon
- photo = 1
- overlays += IMG
- if(i>1)
- desc = "[i] papers clipped to each other."
- else
- desc = "A single sheet of paper."
- if(photo)
- desc += "\nThere is a photo attached to it."
- overlays += image('icons/obj/items/paper.dmi', "clip")
+ . += IMG
+ . += image('icons/obj/items/paper.dmi', "clip")
/obj/item/paper_bundle/proc/attach_doc(obj/item/I, mob/living/user, no_message)
if(I.loc == user)
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index c3fd7b637b407..2610bf0c48831 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -48,6 +48,8 @@
/obj/structure/paper_bin/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
if(!user.transferItemToLoc(I, src))
@@ -66,7 +68,8 @@
. += span_notice("There are no papers in the bin.")
-/obj/structure/paper_bin/update_icon()
+/obj/structure/paper_bin/update_icon_state()
+ . = ..()
if(amount < 1)
icon_state = "paper_bin0"
else
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index fa8cf4b795dcc..b6e184960de89 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -134,6 +134,8 @@
/obj/machinery/photocopier/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/paper))
if(!copier_empty())
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index a4f224c4c2def..3a3c3f234c4ee 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -103,7 +103,8 @@
return ..()
-/obj/item/photo/update_icon()
+/obj/item/photo/update_icon_state()
+ . = ..()
if(!istype(picture) || !picture.picture_image)
return
var/icon/I = picture.get_small_icon()
@@ -171,7 +172,7 @@
light_color = COLOR_WHITE
light_power = FLASH_LIGHT_POWER
w_class = WEIGHT_CLASS_SMALL
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
interaction_flags = INTERACT_REQUIRES_DEXTERITY
var/flash_enabled = TRUE
var/state_on = "camera"
@@ -213,6 +214,8 @@
/obj/item/camera/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/camera_film))
if(pictures_left)
diff --git a/code/modules/power/apc/apc.dm b/code/modules/power/apc/apc.dm
new file mode 100644
index 0000000000000..fd28cb01f026e
--- /dev/null
+++ b/code/modules/power/apc/apc.dm
@@ -0,0 +1,655 @@
+//The Area Power Controller (APC), formerly Power Distribution Unit (PDU)
+//One per area, needs wire conection to power network
+
+//Controls power to devices in that area
+//May be opened to change power cell
+//Three different channels (lighting/equipment/environ) - may each be set to on, off, or auto
+
+
+/obj/machinery/power/apc
+ name = "area power controller"
+ desc = "A control terminal for the area electrical systems."
+ icon = 'icons/obj/machines/apc.dmi'
+ icon_state = "apc0"
+ anchored = TRUE
+ use_power = NO_POWER_USE
+ req_access = list(ACCESS_CIVILIAN_ENGINEERING)
+ resistance_flags = UNACIDABLE
+ interaction_flags = INTERACT_MACHINE_TGUI
+ light_range = 1
+ light_power = 0.5
+ ///The area we're affecting
+ var/area/area
+ ///The power cell inside the APC
+ var/obj/item/cell/cell
+ ///The charge of the APC when first spawned
+ var/start_charge = 90
+ ///The type of cell to spawn this APC with
+ var/cell_type = /obj/item/cell/apc
+ ///The current state of the APC cover
+ var/opened = APC_COVER_CLOSED
+ ///Is the APC shorted?
+ var/shorted = FALSE
+ ///State of the lighting channel (off, auto off, on, auto on)
+ var/lighting = APC_CHANNEL_AUTO_ON
+ ///State of the equipment channel (off, auto off, on, auto on)
+ var/equipment = APC_CHANNEL_AUTO_ON
+ ///State of the environmental channel (off, auto off, on, auto on)
+ var/environ = APC_CHANNEL_AUTO_ON
+ ///Is the apc working?
+ var/operating = TRUE
+ ///State of the apc charging (not charging, charging, fully charged)
+ var/charging = APC_NOT_CHARGING
+ ///Can the APC recharge?
+ var/chargemode = TRUE
+ ///Number of ticks where the apc is trying to recharge
+ var/chargecount = 0
+ ///Is the apc interface locked?
+ var/locked = TRUE
+ ///Is the apc cover locked?
+ var/coverlocked = TRUE
+ ///Is the AI locked from using the APC
+ var/aidisabled = FALSE
+ ///Reference to our cable terminal
+ var/obj/machinery/power/terminal/terminal = null
+ ///Amount of power used by the lighting channel
+ var/lastused_light = 0
+ ///Amount of power used by the equipment channel
+ var/lastused_equip = 0
+ ///Amount of power used by the environmental channel
+ var/lastused_environ = 0
+ ///Total amount of power used by the three channels
+ var/lastused_total = 0
+ var/main_status = APC_EXTERNAL_POWER_NONE
+ ///State of the electronics inside (missing, installed, secured)
+ var/has_electronics = APC_ELECTRONICS_MISSING
+ ///Used for counting how many times it has been hit, used for Aliens at the moment
+ var/beenhit = 0
+ ///Buffer state that makes apcs not shut off channels immediately as long as theres some power left, effect visible in apcs only slowly losing power
+ var/longtermpower = 10
+ ///Stores the flags related to icon updating
+ var/update_state = NONE
+ ///Stores the flag for the overlays
+ var/update_overlay = NONE
+ ///Used to stop the icon from updating too much
+ var/icon_update_needed = FALSE
+ ///Probability of APC being broken by a shuttle crash on the same z-level
+ var/crash_break_probability = 85
+
+/obj/machinery/power/apc/connect_to_network()
+ //Override because the APC does not directly connect to the network; it goes through a terminal.
+ //The terminal is what the power computer looks for anyway.
+ if(terminal)
+ terminal.connect_to_network()
+
+/obj/machinery/power/apc/updateUsrDialog()
+ if(machine_stat & (BROKEN|MAINT))
+ return
+ return ..()
+
+/obj/machinery/power/apc/Initialize(mapload, ndir, building)
+ GLOB.apcs_list += src
+ wires = new /datum/wires/apc(src)
+
+ // offset 32 pixels in direction of dir
+ // this allows the APC to be embedded in a wall, yet still inside an area
+ if (ndir)
+ setDir(ndir)
+
+ switch(dir)
+ if(NORTH)
+ pixel_y = -32
+ if(SOUTH)
+ pixel_y = 32
+ if(EAST)
+ pixel_x = -32
+ if(WEST)
+ pixel_x = 32
+
+ if(building)
+ var/area/A = get_area(src)
+ area = A
+ opened = APC_COVER_OPENED
+ operating = FALSE
+ name = "\improper [area.name] APC"
+ machine_stat |= MAINT
+ update_icon()
+ addtimer(CALLBACK(src, PROC_REF(update)), 5)
+
+ start_processing()
+
+ . = ..()
+
+ var/area/A = get_area(src)
+ area = A
+ name = "\improper [area.name] APC"
+
+ update_icon()
+ update() //areas should be lit on startup
+
+ if(mapload)
+ has_electronics = APC_ELECTRONICS_SECURED
+
+ //Is starting with a power cell installed, create it and set its charge level
+ if(cell_type)
+ set_cell(new cell_type(src))
+ cell.charge = start_charge * cell.maxcharge / 100.0 //Convert percentage to actual value
+ cell.update_icon()
+
+
+ make_terminal()
+
+ update() //areas should be lit on startup
+
+ //Break few ACPs on the colony
+ if(!start_charge && is_ground_level(z) && prob(10))
+ addtimer(CALLBACK(src, PROC_REF(set_broken)), 5)
+
+/obj/machinery/power/apc/Destroy()
+ GLOB.apcs_list -= src
+
+ area.power_light = 0
+ area.power_equip = 0
+ area.power_environ = 0
+ area.power_change()
+
+ QDEL_NULL(cell)
+ QDEL_NULL(wires)
+ if(terminal)
+ disconnect_terminal()
+
+ return ..()
+
+///Wrapper to guarantee powercells are properly nulled and avoid hard deletes.
+/obj/machinery/power/apc/proc/set_cell(obj/item/cell/new_cell)
+ if(cell)
+ UnregisterSignal(cell, COMSIG_QDELETING)
+ cell = new_cell
+ if(cell)
+ RegisterSignal(cell, COMSIG_QDELETING, PROC_REF(on_cell_deletion))
+
+
+///Called by the deletion of the referenced powercell.
+/obj/machinery/power/apc/proc/on_cell_deletion(obj/item/cell/source, force)
+ SIGNAL_HANDLER
+ set_cell(null)
+
+
+/obj/machinery/power/apc/proc/make_terminal()
+ //Create a terminal object at the same position as original turf loc
+ //Wires will attach to this
+ terminal = new(loc)
+ terminal.setDir(REVERSE_DIR(dir))
+ terminal.master = src
+
+/obj/machinery/power/apc/examine(mob/user)
+ . = ..()
+
+ if(machine_stat & BROKEN)
+ . += span_info("It appears to be completely broken. It's hard to see what else is wrong with it.")
+ return
+
+ if(opened)
+ if(has_electronics && terminal)
+ . += span_info("The cover is [opened == APC_COVER_REMOVED ? "removed":"open"] and the power cell is [cell ? "installed":"missing"].")
+ else
+ . += span_info("It's [ !terminal ? "not" : "" ] wired up.")
+ . += span_info("The electronics are[!has_electronics?"n't":""] installed.")
+ else
+ if(machine_stat & MAINT)
+ . += span_info("The cover is closed. Something is wrong with it, it doesn't work.")
+ else
+ . += span_info("The cover is closed.")
+
+ if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
+ . += span_info("The wiring is exposed.")
+
+/obj/machinery/power/apc/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+
+ if(!ui)
+ ui = new(user, src, "Apc", name)
+ ui.open()
+
+/obj/machinery/power/apc/ui_data(mob/user)
+ var/list/data = list(
+ "locked" = locked,
+ "isOperating" = operating,
+ "externalPower" = main_status,
+ "powerCellStatus" = cell ? cell.percent() : null,
+ "chargeMode" = chargemode,
+ "chargingStatus" = charging,
+ "totalLoad" = DisplayPower(lastused_total),
+ "coverLocked" = coverlocked,
+ "siliconUser" = issilicon(user),
+
+ "powerChannels" = list(
+ list(
+ "title" = "Equipment",
+ "powerLoad" = DisplayPower(lastused_equip),
+ "status" = equipment,
+ "topicParams" = list(
+ "auto" = list("eqp" = 3),
+ "on" = list("eqp" = 2),
+ "off" = list("eqp" = 1)
+ )
+ ),
+ list(
+ "title" = "Lighting",
+ "powerLoad" = DisplayPower(lastused_light),
+ "status" = lighting,
+ "topicParams" = list(
+ "auto" = list("lgt" = 3),
+ "on" = list("lgt" = 2),
+ "off" = list("lgt" = 1)
+ )
+ ),
+ list(
+ "title" = "Environment",
+ "powerLoad" = DisplayPower(lastused_environ),
+ "status" = environ,
+ "topicParams" = list(
+ "auto" = list("env" = 3),
+ "on" = list("env" = 2),
+ "off" = list("env" = 1)
+ )
+ )
+ )
+ )
+ return data
+
+
+/obj/machinery/power/apc/proc/setsubsystem(val)
+ if(cell?.charge > 0)
+ return (val==1) ? 0 : val
+ else if(val == 3)
+ return 1
+ else
+ return 0
+
+/obj/machinery/power/apc/proc/can_use(mob/user, loud = FALSE) //used by attack_hand() and Topic()
+ if(IsAdminGhost(user))
+ return TRUE
+ if(isAI(user) && aidisabled)
+ if(!loud)
+ balloon_alert(user, "eee is disabled")
+ return FALSE
+ return TRUE
+
+/obj/machinery/power/apc/ui_act(action, list/params)
+ . = ..()
+ if(. || !can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege))
+ return
+ switch(action)
+ if("lock")
+ if(usr.has_unlimited_silicon_privilege)
+ if((machine_stat & (BROKEN|MAINT)))
+ balloon_alert(usr, "APC unresponsive")
+ else
+ locked = !locked
+ update_icon()
+ . = TRUE
+ if("cover")
+ coverlocked = !coverlocked
+ . = TRUE
+ if("breaker")
+ toggle_breaker(usr)
+ . = TRUE
+ if("charge")
+ chargemode = !chargemode
+ if(!chargemode)
+ charging = APC_NOT_CHARGING
+ update_icon()
+ . = TRUE
+ if("channel")
+ if(params["eqp"])
+ equipment = setsubsystem(text2num(params["eqp"]))
+ update_icon()
+ update()
+ else if(params["lgt"])
+ lighting = setsubsystem(text2num(params["lgt"]))
+ update_icon()
+ update()
+ else if(params["env"])
+ environ = setsubsystem(text2num(params["env"]))
+ update_icon()
+ update()
+ . = TRUE
+ if("overload")
+ if(usr.has_unlimited_silicon_privilege)
+ overload_lighting()
+ . = TRUE
+ return TRUE
+
+/obj/machinery/power/apc/proc/report()
+ return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
+
+
+/obj/machinery/power/apc/proc/update()
+ if(operating && !shorted)
+ area.power_light = (lighting > 1)
+ area.power_equip = (equipment > 1)
+ area.power_environ = (environ > 1)
+ else
+ area.power_light = 0
+ area.power_equip = 0
+ area.power_environ = 0
+ area.power_change()
+
+
+/obj/machinery/power/apc/proc/reset(wire)
+ switch(wire)
+ if(WIRE_IDSCAN)
+ locked = TRUE
+ if(WIRE_POWER1, WIRE_POWER2)
+ if(!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2))
+ shorted = FALSE
+ if(WIRE_AI)
+ if(!wires.is_cut(WIRE_AI))
+ aidisabled = FALSE
+ if(APC_RESET_EMP)
+ equipment = 3
+ environ = 3
+ update_icon()
+ update()
+
+/obj/machinery/power/apc/surplus()
+ if(terminal)
+ return terminal.surplus()
+ else
+ return 0
+
+
+/obj/machinery/power/apc/add_load(amount)
+ if(terminal?.powernet)
+ return terminal.add_load(amount)
+ return 0
+
+
+/obj/machinery/power/apc/avail()
+ if(terminal)
+ return terminal.avail()
+ else
+ return 0
+
+
+/obj/machinery/power/apc/process()
+ if(icon_update_needed)
+ update_icon()
+ if(machine_stat & (BROKEN|MAINT))
+ return
+ if(!area.requires_power)
+ return
+
+ lastused_light = area.usage(STATIC_LIGHTS)
+ lastused_light += area.usage(LIGHT)
+ lastused_equip = area.usage(EQUIP)
+ lastused_equip += area.usage(STATIC_EQUIP)
+ lastused_environ = area.usage(ENVIRON)
+ lastused_environ += area.usage(STATIC_ENVIRON)
+ area.clear_usage()
+
+ lastused_total = lastused_light + lastused_equip + lastused_environ
+
+ //store states to update icon if any change
+ var/last_lt = lighting
+ var/last_eq = equipment
+ var/last_en = environ
+ var/last_ch = charging
+
+ var/excess = surplus()
+
+ if(!avail())
+ main_status = APC_EXTERNAL_POWER_NONE
+ else if(excess < 0)
+ main_status = APC_EXTERNAL_POWER_LOW
+ else
+ main_status = APC_EXTERNAL_POWER_GOOD
+
+ if(cell && !shorted)
+ // draw power from cell as before to power the area
+ var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
+ cell.use(cellused)
+
+ if(excess > lastused_total) // if power excess recharge the cell
+ // by the same amount just used
+ cell.give(cellused)
+ add_load(cellused / GLOB.CELLRATE) // add the load used to recharge the cell
+
+
+ else // no excess, and not enough per-apc
+ if((cell.charge / GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
+ cell.charge = min(cell.maxcharge, cell.charge + GLOB.CELLRATE * excess) //recharge with what we can
+ add_load(excess) // so draw what we can from the grid
+ charging = APC_NOT_CHARGING
+
+ else // not enough power available to run the last tick!
+ charging = APC_NOT_CHARGING
+ chargecount = 0
+ // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+
+
+ // set channels depending on how much charge we have left
+
+ // Allow the APC to operate as normal if the cell can charge
+ if(charging && longtermpower < 10)
+ longtermpower += 1
+ else if(longtermpower > -10)
+ longtermpower -= 2
+
+ if(cell.charge <= 0) // zero charge, turn all off
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+ area.poweralert(0, src)
+ else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
+ equipment = autoset(equipment, 2)
+ lighting = autoset(lighting, 2)
+ environ = autoset(environ, 1)
+ area.poweralert(0, src)
+ else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
+ equipment = autoset(equipment, 2)
+ lighting = autoset(lighting, 1)
+ environ = autoset(environ, 1)
+ area.poweralert(0, src)
+ else // otherwise all can be on
+ equipment = autoset(equipment, 1)
+ lighting = autoset(lighting, 1)
+ environ = autoset(environ, 1)
+ area.poweralert(1, src)
+ if(cell.percent() > 75)
+ area.poweralert(1, src)
+
+ // now trickle-charge the cell
+ if(chargemode && charging == APC_CHARGING && operating)
+ if(excess > 0) // check to make sure we have enough to charge
+ // Max charge is capped to % per second constant
+ var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL)
+ add_load(ch/GLOB.CELLRATE) // Removes the power we're taking from the grid
+ cell.give(ch) // actually recharge the cell
+
+ else
+ charging = APC_NOT_CHARGING // stop charging
+ chargecount = 0
+
+ // show cell as fully charged if so
+ if(cell.charge >= cell.maxcharge)
+ cell.charge = cell.maxcharge
+ charging = APC_FULLY_CHARGED
+
+ if(chargemode)
+ if(!charging)
+ if(excess > cell.maxcharge * GLOB.CHARGELEVEL)
+ chargecount++
+ else
+ chargecount = 0
+
+ if(chargecount == 10)
+
+ chargecount = 0
+ charging = APC_CHARGING
+
+ else // chargemode off
+ charging = APC_NOT_CHARGING
+ chargecount = 0
+
+ else // no cell, switch everything off
+ charging = APC_NOT_CHARGING
+ chargecount = 0
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+ area.poweralert(0, src)
+
+ // update icon & area power if anything changed
+ if(last_lt != lighting || last_eq != equipment || last_en != environ)
+ queue_icon_update()
+ update()
+ else if(last_ch != charging)
+ queue_icon_update()
+
+//val 0 = off, 1 = off(auto) 2 = on, 3 = on(auto)
+//on 0 = off, 1 = auto-on, 2 = auto-off
+
+/proc/autoset(val, on)
+
+ switch(on)
+ if(0) //Turn things off
+ switch(val)
+ if(2) //If on, return off
+ return 0
+ if(3) //If auto-on, return auto-off
+ return 1
+
+ if(1) //Turn things auto-on
+ if(val == 1) //If auto-off, return auto-on
+ return 3
+
+ if(2) //Turn things auto-off
+ if(val == 3) //If auto-on, return auto-off
+ return 1
+ return val
+
+
+/obj/machinery/power/apc/emp_act(severity)
+ if(cell)
+ cell.emp_act(severity)
+ lighting = 0
+ equipment = 0
+ environ = 0
+ update_icon()
+ update()
+ addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 60 SECONDS)
+ return ..()
+
+
+/obj/machinery/power/apc/ex_act(severity)
+ switch(severity)
+ if(EXPLODE_DEVASTATE)
+ cell?.ex_act(1) //More lags woohoo
+ qdel(src)
+ return
+ if(EXPLODE_HEAVY)
+ if(prob(50))
+ return
+ set_broken()
+ if(!cell || prob(50))
+ return
+ if(EXPLODE_LIGHT)
+ if(prob(75))
+ return
+ set_broken()
+ if(!cell || prob(75))
+ return
+ if(EXPLODE_WEAK)
+ if(prob(80))
+ return
+ set_broken()
+ if(!cell || prob(85))
+ return
+
+ cell.ex_act(severity)
+
+
+/obj/machinery/power/apc/proc/set_broken()
+ //Aesthetically much better!
+ visible_message(span_warning("[src]'s screen flickers with warnings briefly!"))
+ addtimer(CALLBACK(src, PROC_REF(do_break)), rand(2, 5))
+
+
+/obj/machinery/power/apc/proc/do_break()
+ visible_message(span_danger("[src]'s screen suddenly explodes in rain of sparks and small debris!"))
+ machine_stat |= BROKEN
+ operating = FALSE
+ update_icon()
+ update()
+
+
+//Overload all the lights in this APC area
+/obj/machinery/power/apc/proc/overload_lighting()
+ if(!operating || shorted)
+ return
+ if(cell?.charge >= 20)
+ cell.use(20)
+ INVOKE_ASYNC(src, PROC_REF(break_lights))
+
+
+/obj/machinery/power/apc/proc/break_lights()
+ for(var/obj/machinery/light/L in get_area(src))
+ L.broken()
+ stoplag()
+
+
+/obj/machinery/power/apc/disconnect_terminal()
+ if(terminal)
+ terminal.master = null
+ terminal = null
+
+
+/obj/machinery/power/apc/proc/toggle_breaker(mob/user)
+ if(machine_stat & (NOPOWER|BROKEN|MAINT))
+ return
+
+ operating = !operating
+ log_combat(user, src, "turned [operating ? "on" : "off"]")
+ update()
+ update_icon()
+
+
+//------Various APCs ------//
+
+// mapping helpers
+/obj/machinery/power/apc/drained
+ start_charge = 0
+
+/obj/machinery/power/apc/lowcharge
+ start_charge = 25
+
+/obj/machinery/power/apc/potato
+ cell_type = /obj/item/cell/potato
+
+/obj/machinery/power/apc/weak
+ cell_type = /obj/item/cell
+
+/obj/machinery/power/apc/high
+ cell_type = /obj/item/cell/high
+
+/obj/machinery/power/apc/super
+ cell_type = /obj/item/cell/super
+
+/obj/machinery/power/apc/hyper
+ cell_type = /obj/item/cell/hyper
+
+//------Marine ship APCs ------//
+
+/obj/machinery/power/apc/mainship
+ req_access = list(ACCESS_MARINE_ENGINEERING)
+ cell_type = /obj/item/cell/high
+
+/obj/machinery/power/apc/mainship/hardened
+ name = "hardened area power controller"
+ desc = "A control terminal for the area electrical systems. This one is hardened against sudden power fluctuations caused by electrical grid damage."
+ crash_break_probability = 0
diff --git a/code/modules/power/apc/apc_appearance.dm b/code/modules/power/apc/apc_appearance.dm
new file mode 100644
index 0000000000000..fe95cfb680947
--- /dev/null
+++ b/code/modules/power/apc/apc_appearance.dm
@@ -0,0 +1,88 @@
+/obj/machinery/power/apc/update_appearance(updates=check_updates())
+ icon_update_needed = FALSE
+ if(!updates)
+ return
+ . = ..()
+ // And now, separately for cleanness, the lighting changing
+ if(!update_state)
+ switch(charging)
+ if(APC_NOT_CHARGING)
+ set_light_color(LIGHT_COLOR_RED)
+ if(APC_CHARGING)
+ set_light_color(LIGHT_COLOR_BLUE)
+ if(APC_FULLY_CHARGED)
+ set_light_color(LIGHT_COLOR_GREEN)
+ set_light(initial(light_range))
+ return
+ set_light(0)
+
+/obj/machinery/power/apc/update_icon_state()
+ . = ..()
+
+ var/broken = CHECK_BITFIELD(update_state, UPSTATE_BROKE) ? "-b" : ""
+ var/status = (CHECK_BITFIELD(update_state, UPSTATE_WIREEXP) && !CHECK_BITFIELD(update_state, UPSTATE_OPENED1)) ? "-wires" : broken
+ icon_state = "apc[opened][status]"
+
+/obj/machinery/power/apc/update_overlays()
+ . = ..()
+
+ if(opened && cell)
+ . += "apco-cell"
+
+ if((machine_stat & (BROKEN|MAINT)) || update_state)
+ return
+
+ . += emissive_appearance(icon, "apcox-[locked]")
+ . += mutable_appearance(icon, "apcox-[locked]")
+ . += emissive_appearance(icon, "apco3-[charging]")
+ . += mutable_appearance(icon, "apco3-[charging]")
+
+ . += emissive_appearance(icon, "apco0-[operating ? equipment : 0]")
+ . += mutable_appearance(icon, "apco0-[operating ? equipment : 0]")
+ . += emissive_appearance(icon, "apco1-[operating ? lighting : 0]")
+ . += mutable_appearance(icon, "apco1-[operating ? lighting : 0]")
+ . += emissive_appearance(icon, "apco2-[operating ? environ : 0]")
+ . += mutable_appearance(icon, "apco2-[operating ? environ : 0]")
+
+/// Checks for what icon updates we will need to handle
+/obj/machinery/power/apc/proc/check_updates()
+ SIGNAL_HANDLER
+ . = NONE
+
+ // Handle icon status:
+ var/new_update_state = NONE
+ if(machine_stat & BROKEN)
+ new_update_state |= UPSTATE_BROKE
+ if(machine_stat & MAINT)
+ new_update_state |= UPSTATE_MAINT
+
+ if(opened)
+ new_update_state |= (opened << UPSTATE_COVER_SHIFT)
+
+ else if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
+ new_update_state |= UPSTATE_WIREEXP
+
+ if(new_update_state != update_state)
+ update_state = new_update_state
+ . |= UPDATE_ICON_STATE
+
+ // Handle overlay status:
+ var/new_update_overlay = NONE
+ if(operating)
+ new_update_overlay |= UPOVERLAY_OPERATING
+
+ if(!update_state)
+ if(locked)
+ new_update_overlay |= UPOVERLAY_LOCKED
+
+ new_update_overlay |= (charging << UPOVERLAY_CHARGING_SHIFT)
+ new_update_overlay |= (equipment << UPOVERLAY_EQUIPMENT_SHIFT)
+ new_update_overlay |= (lighting << UPOVERLAY_LIGHTING_SHIFT)
+ new_update_overlay |= (environ << UPOVERLAY_ENVIRON_SHIFT)
+
+ if(new_update_overlay != update_overlay)
+ update_overlay = new_update_overlay
+ . |= UPDATE_OVERLAYS
+
+/obj/machinery/power/apc/proc/queue_icon_update()
+ icon_update_needed = TRUE
diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm
new file mode 100644
index 0000000000000..96edd263d5da4
--- /dev/null
+++ b/code/modules/power/apc/apc_attack.dm
@@ -0,0 +1,223 @@
+/obj/machinery/power/apc/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
+ return FALSE
+
+ if(effects)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.visible_message(span_danger("[xeno_attacker] slashes \the [src]!"), \
+ span_danger("We slash \the [src]!"), null, 5)
+ playsound(loc, "alien_claw_metal", 25, 1)
+
+ var/allcut = wires.is_all_cut()
+
+ if(beenhit >= pick(3, 4) && !CHECK_BITFIELD(machine_stat, PANEL_OPEN))
+ ENABLE_BITFIELD(machine_stat, PANEL_OPEN)
+ update_appearance()
+ visible_message(span_danger("\The [src]'s cover swings open, exposing the wires!"), null, null, 5)
+
+ else if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) && !allcut)
+ wires.cut_all()
+ update_appearance()
+ visible_message(span_danger("\The [src]'s wires snap apart in a rain of sparks!"), null, null, 5)
+ if(xeno_attacker.client)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[xeno_attacker.ckey]
+ personal_statistics.apcs_slashed++
+ else
+ beenhit += 1
+
+//Attack with an item - open/close cover, insert cell, or (un)lock interface //todo please clean this up
+/obj/machinery/power/apc/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if(.)
+ return
+
+ if(istype(I, /obj/item/cell) && opened) //Trying to put a cell inside
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ user.visible_message(span_notice("[user] fumbles around figuring out how to fit [I] into [src]."),
+ span_notice("You fumble around figuring out how to fit [I] into [src]."))
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ if(cell)
+ balloon_alert(user, "Already installed")
+ return
+
+ if(machine_stat & MAINT)
+ balloon_alert(user, "No connector")
+ return
+
+ if(!user.transferItemToLoc(I, src))
+ return
+
+ set_cell(I)
+ user.visible_message("[user] inserts [I] into [src]!",
+ "You insert [I] into [src]!")
+ chargecount = 0
+ update_appearance()
+
+ else if(istype(I, /obj/item/card/id)) //Trying to unlock the interface with an ID card
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ user.visible_message(span_notice("[user] fumbles around figuring out where to swipe [I] on [src]."),
+ span_notice("You fumble around figuring out where to swipe [I] on [src]."))
+ var/fumbling_time = 3 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ if(opened)
+ balloon_alert(user, "Close the cover first")
+ return
+
+ if(CHECK_BITFIELD(machine_stat, PANEL_OPEN))
+ balloon_alert(user, "Close the panel first")
+ return
+
+ if(machine_stat & (BROKEN|MAINT))
+ balloon_alert(user, "Nothing happens")
+ return
+
+ if(!allowed(user))
+ balloon_alert(user, "Access denied")
+ return
+
+ locked = !locked
+ balloon_alert_to_viewers("[locked ? "locked" : "unlocked"]")
+ update_appearance()
+
+ else if(iscablecoil(I) && !terminal && opened && has_electronics != APC_ELECTRONICS_SECURED)
+ var/obj/item/stack/cable_coil/C = I
+
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ var/turf/T = get_turf(src)
+ if(T.intact_tile)
+ balloon_alert(user, "Remove the floor plating")
+ return
+
+ if(C.get_amount() < 10)
+ balloon_alert(user, "Not enough wires")
+ return
+
+ balloon_alert_to_viewers("starts wiring [src]")
+ playsound(loc, 'sound/items/deconstruct.ogg', 25, 1)
+
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD) || terminal || !opened || has_electronics == APC_ELECTRONICS_SECURED)
+ return
+
+ var/obj/structure/cable/N = T.get_cable_node()
+ if(prob(50) && electrocute_mob(user, N, N))
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ return
+
+ if(!C.use(10))
+ return
+
+ balloon_alert_to_viewers("Wired]")
+ make_terminal()
+ terminal.connect_to_network()
+
+ else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && !(machine_stat & BROKEN))
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ balloon_alert_to_viewers("Tries to insert APC board into [src]")
+ playsound(loc, 'sound/items/deconstruct.ogg', 25, 1)
+
+ if(!do_after(user, 15, NONE, src, BUSY_ICON_BUILD))
+ return
+
+ has_electronics = APC_ELECTRONICS_INSTALLED
+ balloon_alert_to_viewers("Inserts APC board into [src]")
+ qdel(I)
+
+ else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && (machine_stat & BROKEN))
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ balloon_alert(user, "Cannot, frame damaged")
+
+ else if(istype(I, /obj/item/frame/apc) && opened && (machine_stat & BROKEN))
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ if(has_electronics)
+ balloon_alert(user, "Cannot, electronics still inside")
+ return
+
+ balloon_alert_to_viewers("Begins replacing front panel")
+
+ if(!do_after(user, 50, NONE, src, BUSY_ICON_BUILD))
+ return
+
+ balloon_alert_to_viewers("Replaces front panel")
+ qdel(I)
+ DISABLE_BITFIELD(machine_stat, BROKEN)
+ if(opened == APC_COVER_REMOVED)
+ opened = APC_COVER_OPENED
+ update_appearance()
+
+ else if(istype(I, /obj/item/frame/apc) && opened)
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ if(opened == APC_COVER_REMOVED)
+ opened = APC_COVER_OPENED
+ balloon_alert_to_viewers("Replaces [src]'s front panel")
+ qdel(I)
+ update_appearance()
+
+ else
+ if(((machine_stat & BROKEN)) && !opened && I.force >= 5)
+ opened = APC_COVER_REMOVED
+ balloon_alert_to_viewers("Knocks down [src]'s panel")
+ update_appearance()
+ else
+ if(issilicon(user))
+ return attack_hand(user)
+
+ if(!opened && CHECK_BITFIELD(machine_stat, PANEL_OPEN) && (ismultitool(I) || iswirecutter(I)))
+ return attack_hand(user)
+ balloon_alert_to_viewers("Hits [src] with [I]")
+
+//Attack with hand - remove cell (if cover open) or interact with the APC
+/obj/machinery/power/apc/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+
+ if(opened && cell && !issilicon(user))
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+ balloon_alert_to_viewers("Removes [src] from [src]")
+ user.put_in_hands(cell)
+ cell.update_appearance()
+ set_cell(null)
+ charging = APC_NOT_CHARGING
+ update_appearance()
+ return
+
+ if(machine_stat & (BROKEN|MAINT))
+ return
+
+ interact(user)
diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm
new file mode 100644
index 0000000000000..6fcf7c5677490
--- /dev/null
+++ b/code/modules/power/apc/apc_tool_act.dm
@@ -0,0 +1,116 @@
+/obj/machinery/power/apc/crowbar_act(mob/user, obj/item/I)
+ . = TRUE
+ if(opened)
+ if(has_electronics == APC_ELECTRONICS_INSTALLED)
+ if(terminal)
+ balloon_alert(user, "Disconnect the wires")
+ return
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("Fumbles around removing cell from [src]")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+ I.play_tool_sound(src)
+ balloon_alert(user, "Removing APC board")
+ if(I.use_tool(src, user, 50))
+ if(has_electronics == APC_ELECTRONICS_INSTALLED)
+ has_electronics = APC_ELECTRONICS_MISSING
+ if(machine_stat & BROKEN)
+ balloon_alert_to_viewers("Removes the charred control board")
+ return
+ else
+ balloon_alert_to_viewers("Removes the control board")
+ new /obj/item/circuitboard/apc(loc)
+ return
+ else if(opened != APC_COVER_REMOVED)
+ opened = APC_COVER_CLOSED
+ coverlocked = TRUE //closing cover relocks it
+ update_appearance()
+ return
+ else if(!(machine_stat & BROKEN))
+ if(coverlocked && !(machine_stat & MAINT)) // locked...
+ balloon_alert(user, "Locked")
+ return
+ else if(machine_stat & PANEL_OPEN)
+ balloon_alert(user, "Can't, wires in way")
+ return
+ else
+ opened = APC_COVER_OPENED
+ update_appearance()
+ return
+
+
+/obj/machinery/power/apc/screwdriver_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(.)
+ return TRUE
+ . = TRUE
+ if(opened)
+ if(cell)
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+ balloon_alert_to_viewers("Removes cell")
+ var/turf/T = get_turf(user)
+ cell.forceMove(T)
+ cell.update_appearance()
+ set_cell(null)
+ charging = APC_NOT_CHARGING
+ update_appearance()
+ return
+ else
+ switch(has_electronics)
+ if(APC_ELECTRONICS_INSTALLED)
+ has_electronics = APC_ELECTRONICS_SECURED
+ machine_stat &= ~MAINT
+ I.play_tool_sound(src)
+ balloon_alert(user, "Screws circuit board in")
+ if(APC_ELECTRONICS_SECURED)
+ has_electronics = APC_ELECTRONICS_INSTALLED
+ machine_stat |= MAINT
+ I.play_tool_sound(src)
+ balloon_alert(user, "Unfastens electronics")
+ else
+ balloon_alert(user, "Nothing securable")
+ return
+ update_appearance()
+ else
+ TOGGLE_BITFIELD(machine_stat, PANEL_OPEN)
+ balloon_alert(user, "wires [CHECK_BITFIELD(machine_stat, PANEL_OPEN) ? "exposed" : "unexposed"]")
+ update_appearance()
+
+
+/obj/machinery/power/apc/wirecutter_act(mob/living/user, obj/item/I)
+ if(terminal && opened)
+ terminal.deconstruct(user)
+ return TRUE
+
+
+/obj/machinery/power/apc/welder_act(mob/living/user, obj/item/I)
+ if(!opened || has_electronics || terminal)
+ return
+
+ if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
+ balloon_alert_to_viewers("fumbles")
+ var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) )
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
+ return
+
+ if(!I.tool_start_check(user, amount = 3))
+ return
+ balloon_alert_to_viewers("welds [src]")
+
+ if(!I.use_tool(src, user, 50, volume = 50, amount = 3))
+ return
+
+ if((machine_stat & BROKEN) || opened == APC_COVER_REMOVED)
+ new /obj/item/stack/sheet/metal(loc)
+ balloon_alert_to_viewers("cuts apart [src]")
+ else
+ new /obj/item/frame/apc(loc)
+ balloon_alert_to_viewers("cuts [src] from the wall")
+ qdel(src)
+ return TRUE
+
diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm
index 9e5b59adea496..0e2a60f11d6b7 100644
--- a/code/modules/power/batteryrack.dm
+++ b/code/modules/power/batteryrack.dm
@@ -68,19 +68,19 @@
capacity = C * 40 //Basic cells are such crap. Hyper cells needed to get on normal SMES levels.
-/obj/machinery/power/smes/batteryrack/update_icon()
- overlays.Cut()
+/obj/machinery/power/smes/batteryrack/update_overlays()
+ . = ..()
if(machine_stat & BROKEN)
return
- if (outputting)
- overlays += image('icons/obj/power.dmi', "gsmes_outputting")
+ if(outputting)
+ . += image('icons/obj/power.dmi', "gsmes_outputting")
if(inputting)
- overlays += image('icons/obj/power.dmi', "gsmes_charging")
+ . += image('icons/obj/power.dmi', "gsmes_charging")
var/clevel = chargedisplay()
if(clevel>0)
- overlays += image('icons/obj/power.dmi', "gsmes_og[clevel]")
+ . += image('icons/obj/power.dmi', "gsmes_og[clevel]")
@@ -90,6 +90,8 @@
/obj/machinery/power/smes/batteryrack/attackby(obj/item/I, mob/user, params) //these can only be moved by being reconstructed, solves having to remake the powernet.
. = ..() //SMES attackby for now handles screwdriver, cable coils and wirecutters, no need to repeat that here
+ if(.)
+ return
if(!CHECK_BITFIELD(machine_stat, PANEL_OPEN))
return
@@ -108,8 +110,6 @@
M.state = 2
M.icon_state = "box_1"
for(var/obj/O in component_parts)
- if(O.reliability != 100 && crit_fail)
- O.crit_fail = TRUE
O.forceMove(loc)
qdel(src)
@@ -147,20 +147,21 @@
/obj/machinery/power/smes/batteryrack/makeshift/update_icon()
- overlays.Cut()
- if(machine_stat & BROKEN) return
+ . = ..()
+ if(machine_stat & BROKEN)
+ return
- if (outputting)
- overlays += image('icons/obj/power.dmi', "gsmes_outputting")
+ if(outputting)
+ . += image('icons/obj/power.dmi', "gsmes_outputting")
if(inputting)
- overlays += image('icons/obj/power.dmi', "gsmes_charging")
- if (overcharge_percent > 100)
- overlays += image('icons/obj/power.dmi', "gsmes_overcharge")
+ . += image('icons/obj/power.dmi', "gsmes_charging")
+ if(overcharge_percent > 100)
+ . += image('icons/obj/power.dmi', "gsmes_overcharge")
else
var/clevel = chargedisplay()
if(clevel>0)
- overlays += image('icons/obj/power.dmi', "gsmes_og[clevel]")
- return
+ . += image('icons/obj/power.dmi', "gsmes_og[clevel]")
+
//This mess of if-elses and magic numbers handles what happens if the engies don't pay attention and let it eat too much charge
//What happens depends on how much capacity has the ghetto smes and how much it is overcharged.
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 4d06c11d197d2..de7b516c8130a 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -115,7 +115,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
return ..() // then go ahead and delete the cable
/obj/structure/cable/deconstruct(disassembled = TRUE)
- if(!(flags_atom & NODECONSTRUCT))
+ if(!(atom_flags & NODECONSTRUCT))
new /obj/item/stack/cable_coil(drop_location(), 1)
return ..()
@@ -124,6 +124,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
///////////////////////////////////
/obj/structure/cable/update_icon_state()
+ . = ..()
if(!linked_dirs)
icon_state = "l[cable_layer]-noconnection"
else
@@ -396,8 +397,8 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 5
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
singular_name = "cable piece"
usesound = 'sound/items/deconstruct.ogg'
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index f111de72c7aa6..35de3bf6b44ae 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -54,14 +54,9 @@
explode()
return 0
- if(maxcharge < amount) return 0
+ if(maxcharge < amount)
+ return 0
var/amount_used = min(maxcharge-charge,amount)
- if(crit_fail) return 0
- if(!prob(reliability))
- minor_fault++
- if(prob(minor_fault))
- crit_fail = 1
- return 0
charge += amount_used
return amount_used
@@ -72,8 +67,6 @@
. += "The manufacturer's label states this cell has a power rating of [maxcharge], and that you should not swallow it.\nThe charge meter reads [round(src.percent() )]%."
else
. += "This power cell has an exciting chrome finish, as it is an uber-capacity cell type! It has a power rating of [maxcharge]!\nThe charge meter reads [round(src.percent() )]%."
- if(crit_fail)
- . += span_warning("This power cell seems to be faulty.")
if(rigged)
if(get_dist(user,src) < 3) //Have to be close to make out the *DANGEROUS* details
. += span_danger("This power cell looks jury rigged to explode!")
@@ -104,6 +97,8 @@
/obj/item/cell/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
@@ -194,9 +189,7 @@
charge -= 1000 / severity
if (charge < 0)
charge = 0
- if(reliability != 100 && prob(50/severity))
- reliability -= 10 / severity
- ..()
+ return ..()
/obj/item/cell/ex_act(severity)
diff --git a/code/modules/power/fusion_engine.dm b/code/modules/power/fusion_engine.dm
index 75228d4c32f2b..4c5b38ec7d97f 100644
--- a/code/modules/power/fusion_engine.dm
+++ b/code/modules/power/fusion_engine.dm
@@ -178,12 +178,12 @@
if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI)
balloon_alert_to_viewers("Fumbles with [src]'s internals")
var/fumbling_time = 10 SECONDS - 2 SECONDS * user.skills.getRating(SKILL_ENGINEER)
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return FALSE
playsound(loc, 'sound/items/weldingtool_weld.ogg', 25)
balloon_alert_to_viewers("Starts welding some damage")
add_overlay(GLOB.welding_sparks)
- if(!do_after(user, 20 SECONDS - (user.skills.getRating(SKILL_ENGINEER) * 3 SECONDS) , NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20 SECONDS - (user.skills.getRating(SKILL_ENGINEER) * 3 SECONDS) , NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return FALSE
if(buildstate != FUSION_ENGINE_HEAVY_DAMAGE || is_on)
cut_overlay(GLOB.welding_sparks)
@@ -301,7 +301,7 @@
. += span_info("The power gauge reads: [power_gen_percent]%")
if(fusion_cell)
. += span_info("You can see a fuel cell in the receptacle.")
- if(user.skills.getRating(SKILL_ENGINEER) >= SKILL_ENGINEER_MASTER)
+ if(user.skills.getRating(SKILL_ENGINEER) >= SKILL_ENGINEER_EXPERT)
switch(fusion_cell.fuel_amount)
if(0 to 10)
. += span_danger("The fuel cell is critically low.")
@@ -318,7 +318,8 @@
else
. += span_info("There is no fuel cell in the receptacle.")
-/obj/machinery/power/fusion_engine/update_icon()
+/obj/machinery/power/fusion_engine/update_icon_state()
+ . = ..()
switch(buildstate)
if(FUSION_ENGINE_NO_DAMAGE)
if(fusion_cell?.fuel_amount > 0)
@@ -383,7 +384,8 @@
fuel_amount = rand(0,100)
update_icon()
-/obj/item/fuel_cell/update_icon()
+/obj/item/fuel_cell/update_icon_state()
+ . = ..()
switch(get_fuel_percent())
if(-INFINITY to 0)
icon_state = "cell-empty"
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index f4036e3c0a1cb..a3e3ee4ad3bfb 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -75,6 +75,8 @@
/obj/machinery/power/generator/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
anchored = !anchored
diff --git a/code/modules/power/groundmap_geothermal.dm b/code/modules/power/groundmap_geothermal.dm
index fcb7a3d77feb8..8370a53629726 100644
--- a/code/modules/power/groundmap_geothermal.dm
+++ b/code/modules/power/groundmap_geothermal.dm
@@ -32,6 +32,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
. = ..()
RegisterSignals(SSdcs, list(COMSIG_GLOB_OPEN_TIMED_SHUTTERS_LATE, COMSIG_GLOB_OPEN_TIMED_SHUTTERS_XENO_HIVEMIND, COMSIG_GLOB_OPEN_SHUTTERS_EARLY, COMSIG_GLOB_TADPOLE_LAUNCHED), PROC_REF(activate_corruption))
update_icon()
+ SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "generator", ABOVE_FLOAT_LAYER)) //RU TGMC edit - map blips
if(is_ground_level(z))
GLOB.generators_on_ground += 1
@@ -55,7 +56,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
return TRUE
//We don't want to cut/update the power overlays every single proc. Just when it actually changes. This should save on CPU cycles. Efficiency!
-/obj/machinery/power/geothermal/update_icon()
+/obj/machinery/power/geothermal/update_icon_state()
. = ..()
//RUTGMC ADDITION BEGIN
SSminimaps.remove_marker(src)
@@ -91,6 +92,19 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
icon_state = "wrench"
desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is lightly damaged. Use a wrench to repair it."
+/obj/machinery/power/geothermal/update_desc(updates)
+ . = ..()
+ switch(buildstate)
+ if(GEOTHERMAL_NO_DAMAGE)
+ if(!is_on)
+ desc = "A thermoelectric generator sitting atop a borehole dug deep in the planet's surface. It generates energy by boiling the plasma steam that rises from the well.\nIt is old technology and has a large failure rate, and must be repaired frequently.\nIt is currently turned off and silent."
+ if(GEOTHERMAL_HEAVY_DAMAGE)
+ desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is heavily damaged. Use a blowtorch, wirecutters, and then a wrench to repair it."
+ if(GEOTHERMAL_MEDIUM_DAMAGE)
+ desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is damaged. Use wirecutters and then a wrench to repair it."
+ if(GEOTHERMAL_LIGHT_DAMAGE)
+ desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is lightly damaged. Use a wrench to repair it."
+
/obj/machinery/power/geothermal/update_overlays()
. = ..()
if(corrupted)
@@ -112,7 +126,9 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
return PROCESS_KILL
if((length(GLOB.humans_by_zlevel["2"]) > 0.2 * length(GLOB.alive_human_list_faction[FACTION_TERRAGOV])))
//You get points proportional to the % of generators corrupted (for example, if 66% of generators are corrupted the hive gets 0.66 points per second)
- SSpoints.add_psy_points(corrupted, GENERATOR_PSYCH_POINT_OUTPUT / GLOB.generators_on_ground)
+ var/points_generated = GENERATOR_PSYCH_POINT_OUTPUT / GLOB.generators_on_ground
+ SSpoints.add_strategic_psy_points(corrupted, points_generated)
+ SSpoints.add_tactical_psy_points(corrupted, points_generated*0.25)
return
if(!is_on || buildstate || !anchored || !powernet) //Default logic checking
return PROCESS_KILL
@@ -158,26 +174,26 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
return TRUE
return FALSE //Nope, all fine
-/obj/machinery/power/geothermal/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/machinery/power/geothermal/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(corrupted) //you have no reason to interact with it if its already corrupted
return
- if(CHECK_BITFIELD(X.xeno_caste.can_flags, CASTE_CAN_CORRUPT_GENERATOR) && is_corruptible)
- to_chat(X, span_notice("You start to corrupt [src]"))
- if(!do_after(X, 10 SECONDS, NONE, src, BUSY_ICON_HOSTILE))
+ if(CHECK_BITFIELD(xeno_attacker.xeno_caste.can_flags, CASTE_CAN_CORRUPT_GENERATOR) && is_corruptible)
+ to_chat(xeno_attacker, span_notice("You start to corrupt [src]"))
+ if(!do_after(xeno_attacker, 10 SECONDS, NONE, src, BUSY_ICON_HOSTILE))
return
- corrupt(X.hivenumber)
- to_chat(X, span_notice("You have corrupted [src]"))
- record_generator_sabotages(X)
+ corrupt(xeno_attacker.hivenumber)
+ to_chat(xeno_attacker, span_notice("You have corrupted [src]"))
+ record_generator_sabotages(xeno_attacker)
return
if(buildstate)
return
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
play_attack_sound(1)
- X.visible_message(span_danger("\The [X] slashes at \the [src], tearing at it's components!"),
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] slashes at \the [src], tearing at it's components!"),
span_danger("We start slashing at \the [src], tearing at it's components!"))
fail_rate += 5 // 5% fail rate every attack
- record_generator_sabotages(X)
+ record_generator_sabotages(xeno_attacker)
/obj/machinery/power/geothermal/attack_hand(mob/living/carbon/user)
interact_hand(user)
@@ -231,7 +247,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
user.visible_message(span_notice("[user] fumbles around figuring out the resin tendrils on [src]."),
span_notice("You fumble around figuring out the resin tendrils on [src]."))
var/fumbling_time = 10 SECONDS - 2 SECONDS * user.skills.getRating(SKILL_ENGINEER)
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return
if(!WT.remove_fuel(1, user))
@@ -242,7 +258,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
span_notice("You carefully start burning [src]'s resin off."))
add_overlay(GLOB.welding_sparks)
- if(!do_after(user, 20 SECONDS, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20 SECONDS - clamp((user.skills.getRating(SKILL_ENGINEER) - SKILL_ENGINEER_ENGI) * 5, 0, 20) SECONDS, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
cut_overlay(GLOB.welding_sparks)
return FALSE
@@ -259,7 +275,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
user.visible_message(span_notice("[user] fumbles around figuring out [src]'s internals."),
span_notice("You fumble around figuring out [src]'s internals."))
var/fumbling_time = 10 SECONDS - 2 SECONDS * user.skills.getRating(SKILL_ENGINEER)
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)) || buildstate != GEOTHERMAL_HEAVY_DAMAGE || is_on)
+ if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))) || buildstate != GEOTHERMAL_HEAVY_DAMAGE || is_on)
return
if(!WT.remove_fuel(1, user))
@@ -270,7 +286,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
span_notice("You start welding [src]'s internal damage."))
add_overlay(GLOB.welding_sparks)
- if(!do_after(user, 20 SECONDS, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, /obj/item/tool/weldingtool/proc/isOn)) || buildstate != GEOTHERMAL_HEAVY_DAMAGE || is_on)
+ if(!do_after(user, 20 SECONDS - clamp((user.skills.getRating(SKILL_ENGINEER) - SKILL_ENGINEER_ENGI) * 5, 0, 20) SECONDS, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(WT, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))) || buildstate != GEOTHERMAL_HEAVY_DAMAGE || is_on)
cut_overlay(GLOB.welding_sparks)
return FALSE
@@ -296,7 +312,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
user.visible_message(span_notice("[user] starts securing [src]'s wiring."),
span_notice("You start securing [src]'s wiring."))
- if(!do_after(user, 12 SECONDS, NONE, src, BUSY_ICON_BUILD) || buildstate != GEOTHERMAL_MEDIUM_DAMAGE || is_on)
+ if(!do_after(user, 12 SECONDS - clamp((user.skills.getRating(SKILL_ENGINEER) - SKILL_ENGINEER_ENGI) * 4, 0, 12) SECONDS, NONE, src, BUSY_ICON_BUILD) || buildstate != GEOTHERMAL_MEDIUM_DAMAGE || is_on)
return FALSE
playsound(loc, 'sound/items/wirecutter.ogg', 25, 1)
@@ -321,7 +337,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0)
user.visible_message(span_notice("[user] starts repairing [src]'s tubing and plating."),
span_notice("You start repairing [src]'s tubing and plating."))
- if(!do_after(user, 15 SECONDS, NONE, src, BUSY_ICON_BUILD) || buildstate != GEOTHERMAL_LIGHT_DAMAGE || is_on)
+ if(!do_after(user, 15 SECONDS - clamp((user.skills.getRating(SKILL_ENGINEER) - SKILL_ENGINEER_ENGI) * 5, 0, 15) SECONDS, NONE, src, BUSY_ICON_BUILD) || buildstate != GEOTHERMAL_LIGHT_DAMAGE || is_on)
return FALSE
playsound(loc, 'sound/items/ratchet.ogg', 25, 1)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
old mode 100644
new mode 100755
index 1130171274dc7..0011fcbd390a9
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -34,6 +34,8 @@
/obj/machinery/light_construct/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iswrench(I))
if(stage == 1)
@@ -125,6 +127,7 @@
name = "light fixture"
icon = 'icons/obj/lighting.dmi'
var/base_state = "tube" // base description and icon_state
+ base_icon_state = "tube"
icon_state = "tube1"
desc = "A lighting fixture."
anchored = TRUE
@@ -139,13 +142,27 @@
var/bulb_power = 1 // basically the light_power of the emitted light source
var/bulb_colour = COLOR_WHITE
var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN
+ ///is our light flickering?
var/flickering = FALSE
- var/light_type = /obj/item/light_bulb/tube // the type of light item
+ ///what's the duration that the light switches between on and off while flickering
+ var/flicker_time = 2 SECONDS
+ ///the type of light item
+ var/light_type = /obj/item/light_bulb/tube
var/fitting = "tube"
///count of number of times switched on/off. this is used to calc the probability the light burns out
var/switchcount = 0
/// true if rigged to explode
var/rigged = FALSE
+ ///holds the state of our flickering
+ var/light_flicker_state = FALSE
+ ///if true randomize the time we turn on and off
+ var/random_flicker = FALSE
+ ///upper bounds of potential flicker time when randomized
+ var/flicker_time_upper_max = 10 SECONDS
+ ///lower bounds of potential flicker time when randomized
+ var/flicker_time_lower_min = 0.2 SECONDS
+ ///looping sound for flickering lights
+ var/datum/looping_sound/flickeringambient/lightambient
/obj/machinery/light/mainship
base_state = "tube"
@@ -165,6 +182,7 @@
brightness = 4
desc = "A small lighting fixture."
light_type = /obj/item/light_bulb/bulb
+ base_icon_state = "bulb"
/obj/machinery/light/red
base_state = "tubered"
@@ -183,6 +201,7 @@
brightness = 4
desc = "A small lighting fixture."
light_type = /obj/item/light_bulb/bulb
+ base_icon_state = "bulb"
/obj/machinery/light/spot
name = "spotlight"
@@ -242,6 +261,7 @@
turn_light(null, (A.lightswitch && A.power_light))
/obj/machinery/light/Destroy()
+ QDEL_NULL(lightambient)
GLOB.nightfall_toggleable_lights -= src
return ..()
@@ -250,7 +270,8 @@
return TRUE
return FALSE
-/obj/machinery/light/update_icon()
+/obj/machinery/light/update_icon_state()
+ . = ..()
switch(status) // set icon_states
if(LIGHT_OK)
icon_state = "[base_state][light_on]"
@@ -310,6 +331,8 @@
. += "The [fitting] is burnt out."
if(LIGHT_BROKEN)
. += "The [fitting] has been smashed."
+ if(flickering)
+ . += "The fixture seems to be damaged and the cabling is partially broken."
@@ -317,6 +340,8 @@
/obj/machinery/light/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/lightreplacer))
var/obj/item/lightreplacer/LR = I
@@ -357,7 +382,7 @@
return
visible_message("[user] smashed the light!", "You hit the light, and it smashes!")
- if(light_on && (I.flags_atom & CONDUCT) && prob(12))
+ if(light_on && (I.atom_flags & CONDUCT) && prob(12))
electrocute_mob(user, get_area(src), src, 0.3)
broken()
@@ -379,7 +404,7 @@
newlight.stage = 2
qdel(src)
- else if(has_power() && (I.flags_atom & CONDUCT))
+ else if(has_power() && (I.atom_flags & CONDUCT))
to_chat(user, "You stick \the [I] into the light socket!")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
@@ -394,34 +419,57 @@
var/area/A = get_area(src)
return A.lightswitch && A.power_light
-/obj/machinery/light/proc/flicker(amount = rand(10, 20))
- if(flickering)
+///flicker lights on and off
+/obj/machinery/light/proc/flicker(toggle_flicker = FALSE)
+ if(!has_power())
+ lightambient.stop(src)
return
- flickering = TRUE
- spawn(0)
- if(light_on && status == LIGHT_OK)
- for(var/i = 0; i < amount; i++)
- if(status != LIGHT_OK)
- break
- update(FALSE)
- sleep(rand(5, 15))
- update(FALSE)
+ if(toggle_flicker)
+ if(status != LIGHT_OK)
+ addtimer(CALLBACK(src, PROC_REF(flicker), TRUE), flicker_time)
+ return
+ flickering = !flickering
+ if(flickering)
+ lightambient.start(src)
+ else
+ lightambient.stop(src)
+ if(random_flicker)
+ flicker_time = rand(flicker_time_lower_min, flicker_time_upper_max)
+ if(status != LIGHT_OK)
+ lightambient.stop(src)
flickering = FALSE
+ addtimer(CALLBACK(src, PROC_REF(flicker), TRUE), flicker_time)
+ return
+ light_flicker_state = !light_flicker_state
+ if(!light_flicker_state)
+ flick("[base_icon_state]_flick_off", src)
+ //delay the power change long enough to get the flick() animation off
+ addtimer(CALLBACK(src, PROC_REF(flicker_power_state)), 0.3 SECONDS)
+ else
+ flick("[base_icon_state]_flick_on", src)
+ addtimer(CALLBACK(src, PROC_REF(flicker_power_state)), 0.3 SECONDS)
+ flicker_time = flicker_time * 2 //for effect it's best if the amount of time we spend off is more than the time we spend on
+ if(!flickering)
+ return
+ addtimer(CALLBACK(src, PROC_REF(flicker)), flicker_time)
-// ai attack - make lights flicker, because why not
-
-/obj/machinery/light/attack_ai(mob/user)
- flicker(1)
-
+///proc to toggle power on and off for light
+/obj/machinery/light/proc/flicker_power_state(turn_on = TRUE, turn_off = FALSE)
+ if(!light_flicker_state)
+ pick(playsound(loc, 'sound/effects/lightfizz.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz2.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz3.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz4.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz5.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz6.ogg', 10, TRUE))
+ update(FALSE)
+ else
+ pick(playsound(loc, 'sound/effects/lightfizz.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz2.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz3.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz4.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz5.ogg', 10, TRUE), playsound(loc, 'sound/effects/lightfizz6.ogg', 10, TRUE))
+ turn_light(null, FALSE)
//Xenos smashing lights
-/obj/machinery/light/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(X.status_flags & INCORPOREAL)
+/obj/machinery/light/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
if(status == 2) //Ignore if broken.
return FALSE
- X.do_attack_animation(src, ATTACK_EFFECT_SMASH)
- X.visible_message(span_danger("\The [X] smashes [src]!"), \
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_SMASH)
+ xeno_attacker.visible_message(span_danger("\The [xeno_attacker] smashes [src]!"), \
span_danger("We smash [src]!"), null, 5)
broken() //Smashola!
@@ -538,6 +586,9 @@
// called when area power state changes
/obj/machinery/light/power_change()
var/area/A = get_area(src)
+ if(flickering)
+ lightambient.start(src)
+ addtimer(CALLBACK(src, PROC_REF(flicker)), flicker_time)
turn_light(null, (A.lightswitch && A.power_light))
// called when on fire
@@ -656,6 +707,8 @@
// if a syringe, can inject phoron to make it explode
/obj/item/light_bulb/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm
index 15f2790b81782..2da0c72f9553e 100644
--- a/code/modules/power/pipecleaners.dm
+++ b/code/modules/power/pipecleaners.dm
@@ -107,7 +107,7 @@ By design, d1 is the smallest direction and d2 is the highest
return ..() // then go ahead and delete the pipe_cleaner
/obj/structure/pipe_cleaner/deconstruct(disassembled = TRUE)
- if(!(flags_atom & NODECONSTRUCT))
+ if(!(atom_flags & NODECONSTRUCT))
var/turf/T = get_turf(loc)
if(T)
stored.forceMove(T)
@@ -120,10 +120,14 @@ By design, d1 is the smallest direction and d2 is the highest
// General procedures
///////////////////////////////////
-/obj/structure/pipe_cleaner/update_icon()
+/obj/structure/pipe_cleaner/update_icon_state()
+ . = ..()
icon_state = "[d1]-[d2]"
+
+/obj/structure/pipe_cleaner/update_icon()
color = null
add_atom_colour(pipe_cleaner_color, FIXED_COLOUR_PRIORITY)
+ return ..()
// Items usable on a pipe_cleaner :
// - Wirecutters : cut it duh !
@@ -183,8 +187,8 @@ By design, d1 is the smallest direction and d2 is the highest
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 5
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
singular_name = "pipe cleaner piece"
usesound = 'sound/items/deconstruct.ogg'
@@ -206,11 +210,18 @@ By design, d1 is the smallest direction and d2 is the highest
///////////////////////////////////
-/obj/item/stack/pipe_cleaner_coil/update_icon()
+/obj/item/stack/pipe_cleaner_coil/update_icon_state()
+ . = ..()
icon_state = "[initial(item_state)][amount < 3 ? amount : ""]"
+
+/obj/item/stack/pipe_cleaner_coil/update_name(updates)
+ . = ..()
name = "pipe cleaner [amount < 3 ? "piece" : "coil"]"
+
+/obj/item/stack/pipe_cleaner_coil/update_icon()
color = null
add_atom_colour(pipe_cleaner_color, FIXED_COLOUR_PRIORITY)
+ return ..()
/obj/item/stack/pipe_cleaner_coil/attack_hand(mob/user)
. = ..()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 598cd7880ea1b..b8c8061d08e69 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -30,11 +30,11 @@
record_generator_sabotages(user)
return TRUE
-/obj/machinery/power/port_gen/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/power/port_gen/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(!.)
return FALSE
- record_generator_sabotages(X)
+ record_generator_sabotages(xeno_attacker)
return TRUE
/obj/machinery/power/port_gen/should_have_node()
@@ -70,6 +70,7 @@
soundloop.start()
/obj/machinery/power/port_gen/update_icon_state()
+ . = ..()
icon_state = "[base_icon]"
/obj/machinery/power/port_gen/process()
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index 3de0d90d94e6a..b68e6c03d0d45 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -132,6 +132,8 @@
//almost never called, overwritten by all power machines but terminal and generator
/obj/machinery/power/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(iscablecoil(I))
var/obj/item/stack/cable_coil/coil = I
diff --git a/code/modules/power/power_monitor.dm b/code/modules/power/power_monitor.dm
index 1c2875e9f34dc..a6c798f17f872 100644
--- a/code/modules/power/power_monitor.dm
+++ b/code/modules/power/power_monitor.dm
@@ -87,6 +87,7 @@
set_light(initial(light_range))
/obj/machinery/power/monitor/update_icon_state()
+ . = ..()
if(machine_stat & (BROKEN|DISABLED))
icon_state = "[initial(icon_state)]_broken"
else
@@ -105,6 +106,8 @@
//copied from computer.dm
/obj/machinery/power/monitor/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I) && circuit)
playsound(loc, 'sound/items/screwdriver.ogg', 25, 1)
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index db94f65d73827..767d3d16ed456 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -188,6 +188,8 @@
/obj/machinery/power/smes/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
TOGGLE_BITFIELD(machine_stat, PANEL_OPEN)
diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm
index c9bd9c432140b..19d68ec5a9bd7 100644
--- a/code/modules/power/smes_construction.dm
+++ b/code/modules/power/smes_construction.dm
@@ -168,12 +168,10 @@
A.set_broken()
// Failing SMES has special icon overlay.
-/obj/machinery/power/smes/buildable/update_icon()
- if (failing)
- overlays.Cut()
- overlays += image('icons/obj/power.dmi', "smes_crit")
- else
- ..()
+/obj/machinery/power/smes/buildable/update_overlays()
+ . = ..()
+ if(failing)
+ . += image('icons/obj/power.dmi', "smes_crit")
/obj/machinery/power/smes/buildable/attackby(obj/item/I, mob/user, params)
// No more disassembling of overloaded SMESs. You broke it, now enjoy the consequences.
@@ -225,8 +223,6 @@
M.state = 2
M.icon_state = "box_1"
for(var/obj/O in component_parts)
- if(O.reliability != 100 && crit_fail)
- O.crit_fail = TRUE
O.forceMove(loc)
qdel(src)
diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm
index 5cf59ed867aec..3b56bf133821e 100644
--- a/code/modules/projectiles/ammo_datums.dm
+++ b/code/modules/projectiles/ammo_datums.dm
@@ -1,5 +1,9 @@
#define DEBUG_STAGGER_SLOWDOWN 0
+/*!
+ * TODO SPLIT THIS FILE GODDAM
+ */
+
GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/facehugger, /obj/alien/egg, /obj/structure/mineral_door, /obj/alien/resin, /obj/structure/bed/nest))) //For sticky/acid spit
/datum/ammo
@@ -60,13 +64,13 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
///How far the bullet can travel before incurring a chance of hitting barricades; normally 1.
var/barricade_clear_distance = 1
///Does this have an override for the armor type the ammo should test? Bullet by default
- var/armor_type = "bullet"
+ var/armor_type = BULLET
///How many stacks of sundering to apply to a mob on hit
var/sundering = 0
///how much damage airbursts do to mobs around the target, multiplier of the bullet's damage
var/airburst_multiplier = 0.1
///What kind of behavior the ammo has
- var/flags_ammo_behavior = NONE
+ var/ammo_behavior_flags = NONE
///Determines what color our bullet will be when it flies
var/bullet_color = COLOR_WHITE
///If this ammo is hitscan, the icon of beam coming out from the gun
@@ -82,7 +86,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
///greyscale color for the projectile associated with the ammo
var/projectile_greyscale_colors = null
///Multiplier for deflagrate chance
- var/deflagrate_multiplier = 1
+ var/deflagrate_multiplier = 0.9
///Flat damage caused if fire_burst is triggered by deflagrate
var/fire_burst_damage = 10
///Base fire stacks added on hit if the projectile has AMMO_INCENDIARY
@@ -108,7 +112,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
return
///Special effects for leaving a turf. Only called if the projectile has AMMO_LEAVE_TURF enabled
-/datum/ammo/proc/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/proc/on_leave_turf(turf/T, obj/projectile/proj)
return
///Handles CC application on the victim
@@ -163,19 +167,19 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
if(iscarbon(victim))
var/mob/living/carbon/carbon_victim = victim
#if DEBUG_STAGGER_SLOWDOWN
- to_chat(world, span_debuginfo("Damage: Initial stagger is: [target.IsStaggered()]"))
+ to_chat(world, span_debuginfo("Damage: Initial stagger is: [carbon_victim.AmountStaggered()]"))
#endif
if(!HAS_TRAIT(carbon_victim, TRAIT_STAGGER_RESISTANT)) //Some mobs like the Queen are immune to projectile stagger
- carbon_victim.adjust_stagger(stagger)
+ carbon_victim.Stagger(stagger)
#if DEBUG_STAGGER_SLOWDOWN
- to_chat(world, span_debuginfo("Damage: Final stagger is: [target.IsStaggered()]"))
+ to_chat(world, span_debuginfo("Damage: Final stagger is: [carbon_victim.AmountStaggered()]"))
#endif
#if DEBUG_STAGGER_SLOWDOWN
- to_chat(world, span_debuginfo("Damage: Initial slowdown is: [target.slowdown]"))
+ to_chat(world, span_debuginfo("Damage: Initial slowdown is: [carbon_victim.slowdown]"))
#endif
carbon_victim.add_slowdown(slowdown)
#if DEBUG_STAGGER_SLOWDOWN
- to_chat(world, span_debuginfo("Damage: Final slowdown is: [target.slowdown]"))
+ to_chat(world, span_debuginfo("Damage: Final slowdown is: [carbon_victim.slowdown]"))
#endif
to_chat(victim, "[impact_message]") //Summarize all the bad shit that happened
@@ -188,7 +192,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
continue
victim.visible_message(span_danger("[victim] is hit by backlash from \a [proj.name]!"),
isxeno(victim) ? span_xenodanger("We are hit by backlash from \a [proj.name]!") : span_highdanger("You are hit by backlash from \a [proj.name]!"))
- victim.apply_damage(proj.damage * proj.airburst_multiplier, proj.ammo.damage_type, blocked = armor_type, updating_health = TRUE)
+ victim.apply_damage(proj.damage * airburst_multiplier, proj.ammo.damage_type, blocked = armor_type, updating_health = TRUE)
///handles the probability of a projectile hit to trigger fire_burst, based off actual damage done
/datum/ammo/proc/deflagrate(atom/target, obj/projectile/proj)
@@ -217,12 +221,16 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
//Damages the victims, inflicts brief stagger+slow, and ignites
victim.apply_damage(fire_burst_damage, BURN, blocked = FIRE, updating_health = TRUE)
- staggerstun(victim, proj, 30, stagger = 1 SECONDS, slowdown = 0.5)
+ staggerstun(victim, proj, 30, stagger = 0.5 SECONDS, slowdown = 0.5)
victim.adjust_fire_stacks(5)
victim.IgniteMob()
-
-/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/main_proj, atom/shooter, atom/source, range, speed, angle, target, origin_override)
+/**
+ * Fires additional projectiles, generally considered to still be originating from a gun
+ * Such a buckshot
+ * origin_override used to have the new projectile(s) originate from a different source than the main projectile
+*/
+/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/main_proj, mob/living/shooter, atom/source, range, speed, angle, target, origin_override) //todo: Combine these procs with extra args or something, as they are quite similar
var/effect_icon = ""
var/proj_type = /obj/projectile
if(istype(main_proj, /obj/projectile/hitscan))
@@ -249,7 +257,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
new_proj.fire_at(target, shooter, source, range, speed, new_angle, TRUE, loc_override = origin_override)
///A variant of Fire_bonus_projectiles without fixed scatter and no link between gun and bonus_projectile accuracy
-/datum/ammo/proc/fire_directionalburst(obj/projectile/main_proj, atom/shooter, atom/source, projectile_amount, range, speed, angle, target)
+/datum/ammo/proc/fire_directionalburst(obj/projectile/main_proj, mob/living/shooter, atom/source, projectile_amount, range, speed, angle, target)
var/effect_icon = ""
var/proj_type = /obj/projectile
if(istype(main_proj, /obj/projectile/hitscan))
@@ -265,7 +273,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
if(isgun(source))
var/obj/item/weapon/gun/gun = source
- gun.apply_gun_modifiers(new_proj, target, shooter)
+ gun.apply_gun_modifiers(new_proj, target)
//Scatter here is how many degrees extra stuff deviate from the main projectile's firing angle. Fully randomised with no 45 degree cap like normal bullets
var/f = (i-1)
@@ -274,7 +282,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
new_angle += 360
if(new_angle > 360)
new_angle -= 360
- new_proj.fire_at(target, main_proj.loc, source, range, speed, new_angle, TRUE)
+ new_proj.fire_at(target, shooter, main_proj.loc, range, speed, new_angle, TRUE)
/datum/ammo/proc/drop_flame(turf/T)
if(!istype(T))
@@ -295,9 +303,6 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
///bounces the projectile by creating a new projectile and calculating an angle of reflection
/datum/ammo/proc/reflect(turf/T, obj/projectile/proj, scatter_variance)
- if(!bonus_projectiles_type)
- return
-
var/new_range = proj.proj_max_range - proj.distance_travelled
if(new_range <= 0)
return
@@ -322,8 +327,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
new_angle -= 360
bonus_projectiles_amount = 1
- fire_bonus_projectiles(proj, T, proj.shot_from, new_range, proj.projectile_speed, new_angle, null, get_step(T, dir_to_proj))
- bonus_projectiles_amount = 0
+ fire_bonus_projectiles(proj, null, proj.shot_from, new_range, proj.projectile_speed, new_angle, null, get_step(T, dir_to_proj))
+ bonus_projectiles_amount = initial(bonus_projectiles_amount)
/*
//================================================
@@ -334,7 +339,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet
name = "default bullet"
icon_state = "bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
sound_hit = "ballistic_hit"
sound_armor = "ballistic_armor"
sound_miss = "ballistic_miss"
@@ -357,7 +362,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "pistol bullet"
hud_state = "pistol"
hud_state_empty = "pistol_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 20
penetration = 5
accurate_range = 5
@@ -452,7 +457,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "pistol_fire"
damage_type = BURN
shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
damage = 20
/datum/ammo/bullet/pistol/squash
@@ -471,7 +476,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state_empty = "monkey_empty"
ping = null //no bounce off.
damage_type = BURN
- flags_ammo_behavior = AMMO_INCENDIARY|AMMO_IGNORE_ARMOR
+ ammo_behavior_flags = AMMO_INCENDIARY
shell_speed = 2
damage = 15
@@ -492,7 +497,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "revolver"
hud_state_empty = "revolver_empty"
handful_amount = 7
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 45
penetration = 10
sundering = 3
@@ -597,7 +602,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "submachinegun bullet"
hud_state = "smg"
hud_state_empty = "smg_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accuracy_var_low = 7
accuracy_var_high = 7
damage = 20
@@ -620,16 +625,38 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/smg/hollow
name = "hollow-point submachinegun bullet"
hud_state = "pistol_squash"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 35
penetration = 0
damage_falloff = 3
shrapnel_chance = 45
+/datum/ammo/bullet/smg/squash
+ name = "squash-head submachinegun bullet"
+ hud_state = "pistol_squash"
+ ammo_behavior_flags = AMMO_BALLISTIC
+ damage = 15
+ penetration = 15
+ armor_type = BOMB
+ sundering = 1
+ damage_falloff = 2
+ shrapnel_chance = 0
+ ///shatter effection duration when hitting mobs
+ var/shatter_duration = 3 SECONDS
+
+/datum/ammo/bullet/smg/squash/on_hit_mob(mob/M, obj/projectile/proj)
+ if(!isliving(M))
+ return
+
+ var/mob/living/living_victim = M
+ living_victim.apply_status_effect(STATUS_EFFECT_SHATTER, shatter_duration)
+
+
+
/datum/ammo/bullet/smg/incendiary
name = "incendiary submachinegun bullet"
hud_state = "smg_fire"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
damage = 18
penetration = 0
@@ -648,6 +675,12 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
return
living_victim.apply_radiation(2, 2)
+/datum/ammo/bullet/smg/heavy
+ name = "heavy submachinegun bullet"
+ damage = 27.5
+ penetration = 10
+ sundering = 1
+
/datum/ammo/bullet/smg/mech
name = "super-heavy submachinegun bullet"
damage = 20
@@ -664,7 +697,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "rifle bullet"
hud_state = "rifle"
hud_state_empty = "rifle_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 12
damage = 25
penetration = 5
@@ -706,7 +739,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "rifle_fire"
damage_type = BURN
shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
accuracy = -10
/datum/ammo/bullet/rifle/machinegun
@@ -731,17 +764,17 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "hivelo"
hud_state_empty = "hivelo_empty"
damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 15
damage = 40
- penetration = 20
- sundering = 10
+ penetration = 30
+ sundering = 5
bullet_color = COLOR_SOFT_RED
/datum/ammo/bullet/rifle/tx8/incendiary
name = "high velocity incendiary bullet"
hud_state = "hivelo_fire"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_PASS_THROUGH_MOB
damage = 25
penetration = 20
sundering = 2.5
@@ -751,8 +784,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "high velocity impact bullet"
hud_state = "hivelo_impact"
damage = 30
- penetration = 10
- sundering = 12.5
+ penetration = 20
+ sundering = 6.5
/datum/ammo/bullet/rifle/tx8/impact/on_hit_mob(mob/M, obj/projectile/P)
staggerstun(M, P, max_range = 14, slowdown = 1, knockback = 1)
@@ -760,7 +793,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/rifle/mpi_km
name = "crude heavy rifle bullet"
hud_state = "rifle_crude"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 30
penetration = 15
sundering = 1.75
@@ -770,7 +803,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "hivelo"
hud_state_empty = "hivelo_empty"
damage_falloff = 0.5
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 25
accurate_range_min = 6
max_range = 40
@@ -789,7 +822,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "light marksman bullet"
hud_state = "hivelo"
hud_state_empty = "hivelo_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
penetration = 15
damage = 32.5
sundering = 1.25
@@ -833,7 +866,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "shotgun slug"
handful_icon_state = "shotgun slug"
hud_state = "shotgun_slug"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
shell_speed = 3
max_range = 15
damage = 100
@@ -849,7 +882,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "beanbag slug"
icon_state = "beanbag"
hud_state = "shotgun_beanbag"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 15
max_range = 15
shrapnel_chance = 0
@@ -863,7 +896,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "incendiary slug"
hud_state = "shotgun_fire"
damage_type = BRUTE
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
max_range = 15
damage = 70
penetration = 15
@@ -878,7 +911,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "shotgun flechette shell"
icon_state = "flechette"
hud_state = "shotgun_flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
bonus_projectiles_type = /datum/ammo/bullet/shotgun/flechette/flechette_spread
bonus_projectiles_amount = 2
bonus_projectiles_scatter = 3
@@ -913,6 +946,22 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/shotgun/buckshot/on_hit_mob(mob/M,obj/projectile/P)
staggerstun(M, P, weaken = 2 SECONDS, stagger = 2 SECONDS, knockback = 2, slowdown = 0.5, max_range = 3)
+/datum/ammo/bullet/hefa_buckshot
+ name = "hefa fragment"
+ handful_icon_state = "shotgun buckshot shell"
+ icon_state = "buckshot"
+ hud_state = "shotgun_buckshot"
+ accuracy_var_low = 9
+ accuracy_var_high = 9
+ accurate_range = 3
+ max_range = 10
+ shrapnel_chance = 15
+ damage = 30
+ damage_falloff = 3
+
+/datum/ammo/bullet/hefa_buckshot/on_hit_mob(mob/mob_hit, obj/projectile/projectile)
+ staggerstun(mob_hit, projectile, knockback = 2, max_range = 4)
+
/datum/ammo/bullet/shotgun/spread
name = "additional buckshot"
icon_state = "buckshot"
@@ -928,7 +977,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "shotgun explosive shell"
handful_icon_state = "shotgun tracker shell"
hud_state = "shotgun_tracker"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
bonus_projectiles_type = /datum/ammo/bullet/shotgun/frag/frag_spread
bonus_projectiles_amount = 2
bonus_projectiles_scatter = 6
@@ -1010,7 +1059,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "shotgun flechette shell"
icon_state = "flechette"
hud_state = "shotgun_flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
bonus_projectiles_type = /datum/ammo/bullet/shotgun/tx15_flechette/spread
bonus_projectiles_amount = 4
bonus_projectiles_scatter = 2
@@ -1027,7 +1076,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "shotgun slug"
handful_icon_state = "shotgun slug"
hud_state = "shotgun_slug"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
shell_speed = 3
max_range = 15
damage = 60
@@ -1060,7 +1109,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "light shotgun sabot shell"
icon_state = "shotgun_slug"
hud_state = "shotgun_sabot"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
shell_speed = 5
max_range = 30
damage = 50
@@ -1128,7 +1177,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "sniper"
hud_state_empty = "sniper_empty"
damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_SNIPER
accurate_range_min = 7
shell_speed = 4
accurate_range = 30
@@ -1142,7 +1191,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "sniper_fire"
accuracy = 0
damage_type = BURN
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SNIPER|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SNIPER
accuracy_var_high = 7
max_range = 20
damage = 70
@@ -1158,7 +1207,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
airburst_multiplier = 0.5
/datum/ammo/bullet/sniper/flak/on_hit_mob(mob/victim, obj/projectile/proj)
- staggerstun(victim, proj, max_range = 30, slowdown = 2)
+ staggerstun(victim, proj, max_range = 30)
airburst(victim, proj)
/datum/ammo/bullet/sniper/svd
@@ -1175,7 +1224,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_icon_state = "crude heavy sniper bullet"
hud_state = "sniper_crude"
handful_amount = 5
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 120
penetration = 20
accurate_range_min = 0
@@ -1192,7 +1241,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/elite
name = "supersonic sniper bullet"
hud_state = "sniper_supersonic"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accuracy = 20
damage = 100
penetration = 60
@@ -1201,7 +1250,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/pfc
name = "high caliber rifle bullet"
hud_state = "sniper_heavy"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_SNIPER
damage = 80
penetration = 30
sundering = 7.5
@@ -1210,7 +1259,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/pfc/flak
name = "high caliber flak rifle bullet"
hud_state = "sniper_heavy_flak"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_SNIPER
damage = 40
penetration = 10
sundering = 10
@@ -1221,9 +1270,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/auto
- name = "high caliber rifle bullet"
+ name = "low velocity high caliber rifle bullet"
hud_state = "sniper_auto"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_SNIPER
damage = 50
penetration = 30
sundering = 2
@@ -1232,7 +1281,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/clf_heavyrifle
name = "high velocity incendiary sniper bullet"
handful_icon_state = "ptrs"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SNIPER|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY|AMMO_SNIPER
hud_state = "sniper_fire"
accurate_range_min = 4
shell_speed = 5
@@ -1242,7 +1291,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/sniper/mech
name = "light anti-tank bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_SNIPER|AMMO_IFF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IFF
damage = 100
penetration = 35
sundering = 0
@@ -1259,7 +1308,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction
hud_state = "smartgun"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 12
damage = 20
penetration = 15
@@ -1270,7 +1319,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction
hud_state = "smartgun_minigun"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 12
damage = 10
penetration = 25
@@ -1282,7 +1331,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction
hud_state = "smartgun"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 40
max_range = 40
penetration = 30
@@ -1292,13 +1341,25 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
accurate_range = 25
accurate_range_min = 3
+/datum/ammo/bullet/cupola
+ name = "cupola bullet"
+ bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction
+ hud_state = "smartgun"
+ hud_state_empty = "smartgun_empty"
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_IFF
+ accurate_range = 12
+ damage = 30
+ penetration = 10
+ sundering = 1
+
/datum/ammo/bullet/spottingrifle
name = "smart spotting bullet"
bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction
hud_state = "spotrifle"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
damage = 50
+ max_range = 40
penetration = 25
sundering = 5
shell_speed = 4
@@ -1310,7 +1371,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sundering = 0.5
/datum/ammo/bullet/spottingrifle/highimpact/on_hit_mob(mob/M,obj/projectile/P)
- staggerstun(M, P, stagger = 1, slowdown = 1, max_range = 12)
+ staggerstun(M, P, stagger = 1 SECONDS, slowdown = 1, max_range = 12)
/datum/ammo/bullet/spottingrifle/heavyrubber
name = "smart heavy-rubber spotting bullet"
@@ -1319,7 +1380,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sundering = 0.5
/datum/ammo/bullet/spottingrifle/heavyrubber/on_hit_mob(mob/M,obj/projectile/P)
- staggerstun(M, P, weaken = 1, slowdown = 1, max_range = 12)
+ staggerstun(M, P, weaken = 1 SECONDS, slowdown = 1, max_range = 12)
/datum/ammo/bullet/spottingrifle/plasmaloss
name = "smart tanglefoot spotting bullet"
@@ -1354,7 +1415,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/spottingrifle/incendiary
name = "smart incendiary spotting bullet"
hud_state = "spotrifle_incend"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
damage_type = BURN
damage = 10
sundering = 0.5
@@ -1364,7 +1425,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
bullet_color = COLOR_SOFT_RED
hud_state = "rifle"
hud_state_empty = "rifle_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_SENTRY
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 10
damage = 25
penetration = 20
@@ -1382,13 +1443,72 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "small caliber autocannon bullet"
damage = 20
penetration = 20
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SENTRY
+ ammo_behavior_flags = AMMO_BALLISTIC
+/datum/ammo/bullet/turret/sniper
+ name = "antimaterial bullet"
+ bullet_color = COLOR_SOFT_RED
+ accurate_range = 21
+ damage = 80
+ penetration = 50
+ sundering = 5
+
+/datum/ammo/bullet/turret/buckshot
+ name = "turret buckshot shell"
+ icon_state = "buckshot"
+ hud_state = "shotgun_buckshot"
+ bonus_projectiles_type = /datum/ammo/bullet/turret/spread
+ bonus_projectiles_amount = 6
+ bonus_projectiles_scatter = 5
+ max_range = 10
+ damage = 20
+ penetration = 40
+ damage_falloff = 1
+
+/datum/ammo/bullet/turret/buckshot/on_hit_mob(mob/M,obj/projectile/P)
+ staggerstun(M, P, knockback = 1, max_range = 4)
+
+/datum/ammo/bullet/turret/spread
+ name = "additional buckshot"
+ max_range = 10
+ damage = 20
+ penetration = 40
+ damage_falloff = 1
+
+/datum/ammo/flamer
+ name = "flame turret glob"
+ icon_state = "pulse0"
+ hud_state = "flame"
+ hud_state_empty = "flame_empty"
+ damage_type = BURN
+ ammo_behavior_flags = AMMO_INCENDIARY|AMMO_FLAME
+ armor_type = FIRE
+ damage = 30
+ max_range = 7
+ bullet_color = LIGHT_COLOR_FIRE
+
+/datum/ammo/flamer/drop_nade(turf/T)
+ flame_radius(2, T)
+ playsound(T, 'sound/weapons/guns/fire/flamethrower2.ogg', 50, 1, 4)
+
+
+/datum/ammo/flamer/on_hit_mob(mob/M, obj/projectile/P)
+ drop_nade(get_turf(M))
+
+/datum/ammo/flamer/on_hit_obj(obj/O, obj/projectile/P)
+ drop_nade(O.density ? P.loc : O.loc)
+
+/datum/ammo/flamer/on_hit_turf(turf/T, obj/projectile/P)
+ drop_nade(T.density ? P.loc : T)
+
+/datum/ammo/flamer/do_at_max_range(turf/T, obj/projectile/P)
+ drop_nade(T.density ? P.loc : T)
+
/datum/ammo/bullet/machinegun //Adding this for the MG Nests (~Art)
name = "machinegun bullet"
icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed.
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
hud_state = "minigun"
hud_state_empty = "smartgun_empty"
accurate_range = 12
@@ -1402,7 +1522,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "minigun bullet"
hud_state = "minigun"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_BALLISTIC
accuracy_var_low = 3
accuracy_var_high = 3
accurate_range = 5
@@ -1417,11 +1537,20 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
penetration = 10
sundering = 0.5
+/datum/ammo/bullet/minigun/ltaap
+ name = "chaingun bullet"
+ damage = 30
+ penetration = 10
+ sundering = 0
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_IFF
+ damage_falloff = 2
+ accuracy = 80
+
/datum/ammo/bullet/auto_cannon
name = "autocannon high-velocity bullet"
hud_state = "minigun"
hud_state_empty = "smartgun_empty"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
accurate_range_min = 6
accuracy_var_low = 3
accuracy_var_high = 3
@@ -1430,7 +1559,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sundering = 1
max_range = 35
///Bonus flat damage to walls, balanced around resin walls.
- var/autocannon_wall_bonus = 20
+ var/autocannon_wall_bonus = 50
/datum/ammo/bullet/auto_cannon/on_hit_turf(turf/T, obj/projectile/P)
P.proj_max_range -= 20
@@ -1449,13 +1578,13 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/auto_cannon/flak
name = "autocannon smart-detonating bullet"
hud_state = "sniper_flak"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_EXPLOSIVE
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_TARGET_TURF
damage = 50
penetration = 30
sundering = 5
max_range = 30
airburst_multiplier = 1
- autocannon_wall_bonus = 5
+ autocannon_wall_bonus = 25
/datum/ammo/bullet/auto_cannon/flak/on_hit_mob(mob/victim, obj/projectile/proj)
airburst(victim, proj)
@@ -1467,7 +1596,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "armor piercing railgun slug"
hud_state = "railgun_ap"
icon_state = "blue_bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
shell_speed = 4
max_range = 14
damage = 150
@@ -1494,7 +1623,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/railgun/smart
name = "smart armor piercing railgun slug"
hud_state = "railgun_smart"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE|AMMO_IFF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE|AMMO_IFF
damage = 100
penetration = 20
sundering = 20
@@ -1506,7 +1635,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "\improper APFSDS round"
hud_state = "alloy_spike"
icon_state = "blue_bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOVABLE|AMMO_UNWIELDY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOVABLE|AMMO_UNWIELDY
shell_speed = 4
max_range = 14
damage = 150
@@ -1524,8 +1653,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_amount = 3
ping = null //no bounce off.
sound_bounce = "rocket_bounce"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
- armor_type = "bomb"
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
+ armor_type = BOMB
damage_falloff = 0.5
shell_speed = 2
accurate_range = 12
@@ -1593,6 +1722,13 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_greyscale_colors = COLOR_AMMO_TANGLEFOOT
projectile_greyscale_colors = COLOR_AMMO_TANGLEFOOT
+/datum/ammo/tx54/smoke/acid
+ name = "20mm acid grenade"
+ hud_state = "grenade_acid"
+ bonus_projectiles_type = /datum/ammo/bullet/tx54_spread/smoke/acid
+ handful_greyscale_colors = COLOR_AMMO_ACID
+ projectile_greyscale_colors = COLOR_AMMO_ACID
+
/datum/ammo/tx54/razor
name = "20mm razorburn grenade"
hud_state = "grenade_razor"
@@ -1629,7 +1765,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/tx54_spread
name = "Shrapnel"
icon_state = "flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB
accuracy_var_low = 5
accuracy_var_high = 5
max_range = 4
@@ -1643,7 +1779,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/tx54_spread/incendiary
name = "incendiary flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
damage = 15
penetration = 10
sundering = 1.5
@@ -1656,12 +1792,12 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
return
T.ignite(5, 10)
-/datum/ammo/bullet/tx54_spread/incendiary/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/bullet/tx54_spread/incendiary/on_leave_turf(turf/T, obj/projectile/proj)
drop_flame(T)
/datum/ammo/bullet/tx54_spread/smoke
name = "chemical bomblet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_LEAVE_TURF
max_range = 3
damage = 5
penetration = 0
@@ -1682,7 +1818,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/tx54_spread/smoke/on_hit_mob(mob/M, obj/projectile/proj)
return
-/datum/ammo/bullet/tx54_spread/smoke/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/bullet/tx54_spread/smoke/on_leave_turf(turf/T, obj/projectile/proj)
trail_spread_system.set_up(0, T)
trail_spread_system.start()
@@ -1692,9 +1828,12 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/tx54_spread/smoke/tangle
trail_spread_system = /datum/effect_system/smoke_spread/plasmaloss
+/datum/ammo/bullet/tx54_spread/smoke/acid
+ trail_spread_system = /datum/effect_system/smoke_spread/xeno/acid
+
/datum/ammo/bullet/tx54_spread/razor
name = "chemical bomblet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_LEAVE_TURF
max_range = 4
damage = 5
penetration = 0
@@ -1720,7 +1859,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/tx54_spread/razor/on_hit_mob(mob/M, obj/projectile/proj)
return
-/datum/ammo/bullet/tx54_spread/razor/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/bullet/tx54_spread/razor/on_leave_turf(turf/T, obj/projectile/proj)
chemical_payload.set_up(0, T, reagent_list, RAZOR_FOAM)
chemical_payload.start()
@@ -1743,7 +1882,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/micro_rail
hud_state_empty = "grenade_empty_flash"
handful_icon_state = "micro_grenade_airburst"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
shell_speed = 2
handful_amount = 3
max_range = 3 //failure to detonate if the target is too close
@@ -1802,7 +1941,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/micro_rail_spread
name = "Shrapnel"
icon_state = "flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB
accuracy_var_low = 5
accuracy_var_high = 5
max_range = 7
@@ -1816,7 +1955,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/micro_rail_spread/incendiary
name = "incendiary flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
damage = 15
penetration = 5
sundering = 1.5
@@ -1830,14 +1969,14 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
return
T.ignite(5, 10)
-/datum/ammo/bullet/micro_rail_spread/incendiary/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/bullet/micro_rail_spread/incendiary/on_leave_turf(turf/T, obj/projectile/proj)
if(prob(40))
drop_flame(T)
/datum/ammo/micro_rail_cluster
name = "bomblet"
icon_state = "bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_LEAVE_TURF
sound_hit = "ballistic_hit"
sound_armor = "ballistic_armor"
sound_miss = "ballistic_miss"
@@ -1879,7 +2018,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
var/obj/obj_victim = target
obj_victim.take_damage(explosion_damage, BRUTE, BOMB)
-/datum/ammo/micro_rail_cluster/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/micro_rail_cluster/on_leave_turf(turf/T, obj/projectile/proj)
///chance to detonate early, scales with distance and capped, to avoid lots of immediate detonations, and nothing reach max range respectively.
var/detonate_probability = min(proj.distance_travelled * 4, 16)
if(prob(detonate_probability))
@@ -1900,7 +2039,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/smoke_burst
name = "micro smoke canister"
icon_state = "bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
sound_hit = "ballistic_hit"
sound_armor = "ballistic_armor"
sound_miss = "ballistic_miss"
@@ -1943,8 +2082,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
handful_amount = 1
ping = null //no bounce off.
sound_bounce = "rocket_bounce"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_IFF
- armor_type = "bomb"
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER|AMMO_IFF
+ armor_type = BOMB
damage_falloff = 0.5
shell_speed = 2
accurate_range = 12
@@ -1979,7 +2118,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/ags_spread
name = "Shrapnel"
icon_state = "flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB
accuracy_var_low = 15
accuracy_var_high = 5
max_range = 6
@@ -1990,7 +2129,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/ags_spread/incendiary
name = "White phosphorous shrapnel"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_INCENDIARY
damage = 20
penetration = 10
sundering = 1.5
@@ -2018,7 +2157,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "high-velocity tungsten slug"
hud_state = "railgun_ap"
icon_state = "blue_bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOVABLE
shell_speed = 5
max_range = 31
damage = 70
@@ -2044,8 +2183,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state_empty = "rocket_empty"
ping = null //no bounce off.
sound_bounce = "rocket_bounce"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
- armor_type = "bomb"
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
+ armor_type = BOMB
damage_falloff = 0
shell_speed = 2
accuracy = 40
@@ -2084,7 +2223,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/he/unguided
damage = 100
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING // We want this one to specifically go over onscreen range.
+ ammo_behavior_flags = AMMO_SNIPER // We want this one to specifically go over onscreen range.
/datum/ammo/rocket/he/unguided/drop_nade(turf/T)
explosion(T, 0, 7, 0, 0, 2)
@@ -2104,14 +2243,15 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/ltb
name = "cannon round"
icon_state = "ltb"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
accurate_range = 15
max_range = 40
- penetration = 200
- damage = 300
+ penetration = 50
+ damage = 200
+ hud_state = "bigshell_he"
/datum/ammo/rocket/ltb/drop_nade(turf/T)
- explosion(T, 0, 4, 6, 0, 7)
+ explosion(T, 0, 2, 5, 0, 3)
/datum/ammo/rocket/mech
name = "large high-explosive rocket"
@@ -2123,16 +2263,15 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
explosion(T, 0, 0, 5, 0, 5)
/datum/ammo/rocket/heavy_isg
- name = "15cm round"
+ name = "8.8cm round"
icon_state = "heavyrr"
hud_state = "bigshell_he"
hud_state_empty = "shell_empty"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE
- damage = 50
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_TARGET_TURF
+ damage = 100
penetration = 200
max_range = 30
shell_speed = 0.75
- accuracy = 30
accurate_range = 21
handful_amount = 1
@@ -2141,18 +2280,17 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/heavy_isg/unguided
hud_state = "bigshell_he_unguided"
- flags_ammo_behavior = AMMO_ROCKET
+ ammo_behavior_flags = AMMO_SNIPER
/datum/ammo/bullet/heavy_isg_apfds
- name = "15cm APFDS round"
+ name = "8.8cm APFDS round"
icon_state = "apfds"
hud_state = "bigshell_apfds"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
- damage = 200
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ damage = 275
penetration = 75
shell_speed = 7
accurate_range = 24
- accurate_range_min = 6
max_range = 35
/datum/ammo/bullet/isg_apfds/on_hit_turf(turf/T, obj/projectile/P)
@@ -2169,8 +2307,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "white phosphorous rocket"
icon_state = "rocket_wp"
hud_state = "rocket_fire"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_INCENDIARY|AMMO_EXPLOSIVE|AMMO_SUNDERING
- armor_type = "fire"
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_INCENDIARY|AMMO_TARGET_TURF
+ armor_type = FIRE
damage_type = BURN
accuracy_var_low = 7
accurate_range = 15
@@ -2190,7 +2328,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/wp/quad
name = "thermobaric rocket"
hud_state = "rocket_thermobaric"
- flags_ammo_behavior = AMMO_ROCKET
+ ammo_behavior_flags = AMMO_SNIPER
damage = 40
penetration = 25
max_range = 30
@@ -2215,13 +2353,13 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "white phosphorous RPG"
hud_state = "rpg_fire"
icon_state = "rpg_incendiary"
- flags_ammo_behavior = AMMO_ROCKET
+ ammo_behavior_flags = AMMO_SNIPER
effect_radius = 5
/datum/ammo/rocket/wp/quad/ds
name = "super thermobaric rocket"
hud_state = "rocket_thermobaric"
- flags_ammo_behavior = AMMO_ROCKET
+ ammo_behavior_flags = AMMO_SNIPER
damage = 200
penetration = 75
max_range = 30
@@ -2229,7 +2367,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/wp/unguided
damage = 100
- flags_ammo_behavior = AMMO_ROCKET|AMMO_INCENDIARY|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_INCENDIARY
effect_radius = 5
/datum/ammo/rocket/recoilless
@@ -2237,8 +2375,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "recoilless_rifle_he"
hud_state = "shell_he"
hud_state_empty = "shell_empty"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
- armor_type = "bomb"
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
+ armor_type = BOMB
damage_falloff = 0
shell_speed = 2
accurate_range = 20
@@ -2254,7 +2392,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "HEAT shell"
icon_state = "recoilless_rifle_heat"
hud_state = "shell_heat"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_SNIPER
damage = 200
penetration = 100
sundering = 0
@@ -2265,7 +2403,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/recoilless/heat/mech //for anti mech use in HvH
name = "HEAM shell"
accuracy = -10 //Not designed for anti human use
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING|AMMO_UNWIELDY
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_UNWIELDY
/datum/ammo/rocket/recoilless/heat/mech/on_hit_obj(obj/O, obj/projectile/P)
drop_nade(get_turf(O))
@@ -2279,7 +2417,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "light explosive shell"
icon_state = "recoilless_rifle_le"
hud_state = "shell_le"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING //We want this to specifically go farther than onscreen range.
+ ammo_behavior_flags = AMMO_SNIPER //We want this to specifically go farther than onscreen range.
accurate_range = 15
max_range = 20
damage = 75
@@ -2293,7 +2431,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "low velocity chemical shell"
icon_state = "recoilless_rifle_smoke"
hud_state = "shell_le"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING|AMMO_IFF //We want this to specifically go farther than onscreen range and pass through friendlies.
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_IFF //We want this to specifically go farther than onscreen range and pass through friendlies.
accurate_range = 21
max_range = 21
damage = 10
@@ -2327,7 +2465,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "low impact explosive shell"
icon_state = "recoilless_rifle_le"
hud_state = "shell_le"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING //We want this to specifically go farther than onscreen range.
+ ammo_behavior_flags = AMMO_SNIPER //We want this to specifically go farther than onscreen range.
accurate_range = 15
max_range = 20
damage = 75
@@ -2348,7 +2486,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "high explosive RPG"
icon_state = "rpg_he"
hud_state = "rpg_he"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_SNIPER
accurate_range = 15
max_range = 20
damage = 80
@@ -2362,7 +2500,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "low impact RPG"
icon_state = "rpg_le"
hud_state = "rpg_le"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_SNIPER
accurate_range = 15
damage = 60
penetration = 10
@@ -2387,7 +2525,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
penetration = 100
sundering = 0
accuracy = -10 //Not designed for anti human use
- flags_ammo_behavior = AMMO_ROCKET|AMMO_SUNDERING|AMMO_UNWIELDY
+ ammo_behavior_flags = AMMO_SNIPER|AMMO_UNWIELDY
/datum/ammo/rocket/som/heat/on_hit_obj(obj/O, obj/projectile/P)
drop_nade(get_turf(O))
@@ -2404,7 +2542,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 50
penetration = 10
///Base strength of the rad effects
- var/rad_strength = 25
+ var/rad_strength = 20
///Range for the maximum rad effects
var/inner_range = 3
///Range for the moderate rad effects
@@ -2437,7 +2575,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "atgun"
hud_state = "shell_heat"
hud_state_empty = "shell_empty"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING|AMMO_PASS_THROUGH_TURF
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER|AMMO_PASS_THROUGH_TURF
shell_speed = 2
damage = 90
penetration = 30
@@ -2454,7 +2592,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/atgun_shell/apcr
name = "tungsten penetrator"
hud_state = "shell_apcr"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
shell_speed = 4
damage = 200
penetration = 70
@@ -2477,7 +2615,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/atgun_shell/he
name = "low velocity high explosive shell"
hud_state = "shell_he"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
damage = 50
penetration = 50
sundering = 35
@@ -2491,7 +2629,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/atgun_shell/beehive
name = "beehive shell"
hud_state = "shell_le"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
shell_speed = 3
damage = 30
penetration = 30
@@ -2524,14 +2662,14 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/rocket/atgun_shell/beehive/incend
name = "napalm shell"
hud_state = "shell_heat"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER
shell_speed = 3
bonus_projectiles_type = /datum/ammo/bullet/atgun_spread/incendiary
/datum/ammo/bullet/atgun_spread
name = "Shrapnel"
icon_state = "flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB
accuracy_var_low = 15
accuracy_var_high = 5
max_range = 6
@@ -2542,7 +2680,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/bullet/atgun_spread/incendiary
name = "incendiary flechette"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_BALLISTIC|AMMO_PASS_THROUGH_MOB|AMMO_INCENDIARY|AMMO_LEAVE_TURF
damage = 20
penetration = 10
sundering = 1.5
@@ -2555,13 +2693,13 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
return
T.ignite(5, 10)
-/datum/ammo/bullet/atgun_spread/incendiary/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
+/datum/ammo/bullet/atgun_spread/incendiary/on_leave_turf(turf/T, obj/projectile/proj)
drop_flame(T)
/datum/ammo/mortar
name = "80mm shell"
icon_state = "mortar"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
shell_speed = 0.75
damage = 0
penetration = 0
@@ -2626,7 +2764,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
smoke.set_up(6, T, 7)
smoke.start()
flame_radius(4, T)
- flame_radius(1, T, burn_intensity = 45, burn_duration = 75, burn_damage = 15, fire_stacks = 75)
+ flame_radius(1, T, burn_intensity = 75, burn_duration = 45, burn_damage = 15, fire_stacks = 75)
/datum/ammo/mortar/smoke/howi/plasmaloss
smoketype = /datum/effect_system/smoke_spread/plasmaloss
@@ -2672,6 +2810,11 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/mortar/rocket/mlrs/drop_nade(turf/T)
explosion(T, 0, 0, 4, 0, 2)
+/datum/ammo/mortar/rocket/mlrs/incendiary/drop_nade(turf/T)
+ explosion(T, 0, 0, 2, 0, 2)
+ flame_radius(3, T)
+ playsound(T, 'sound/weapons/guns/fire/flamethrower2.ogg', 35, 1, 4)
+
/datum/ammo/mortar/rocket/smoke/mlrs
shell_speed = 2.5
smoketype = /datum/effect_system/smoke_spread/mustard
@@ -2683,6 +2826,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
smoke.set_up(5, T, 6)
smoke.start()
+/datum/ammo/mortar/rocket/smoke/mlrs/cloak
+ smoketype = /datum/effect_system/smoke_spread/tactical
+
/*
//================================================
Energy Ammo
@@ -2697,8 +2843,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sound_bounce = "ballistic_bounce"
damage_type = BURN
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SOUND_PITCH
- armor_type = "energy"
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SOUND_PITCH
+ armor_type = ENERGY
accuracy = 15 //lasers fly fairly straight
bullet_color = COLOR_LASER_RED
barricade_clear_distance = 2
@@ -2706,7 +2852,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/emitter //Damage is determined in emitter.dm
name = "emitter bolt"
icon_state = "emitter"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_ARMOR
+ ammo_behavior_flags = AMMO_ENERGY
accurate_range = 10
max_range = 10
bullet_color = COLOR_VIBRANT_LIME
@@ -2719,10 +2865,11 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 10
penetration = 100
damage_type = STAMINA
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SKIPS_ALIENS
max_range = 15
accurate_range = 10
bullet_color = COLOR_VIVID_YELLOW
+
/datum/ammo/energy/taser/on_hit_mob(mob/M,obj/projectile/P)
staggerstun(M, P, stun = 20 SECONDS)
@@ -2731,7 +2878,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "tesla"
hud_state = "taser"
hud_state_empty = "battery_empty"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SPECIAL_PROCESS
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SPECIAL_PROCESS
shell_speed = 0.1
damage = 20
penetration = 20
@@ -2741,7 +2888,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
zap_beam(proj, 4, damage)
/datum/ammo/energy/tesla/focused
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SPECIAL_PROCESS|AMMO_IFF
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SPECIAL_PROCESS|AMMO_IFF
shell_speed = 0.1
damage = 10
penetration = 10
@@ -2756,12 +2903,22 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
var/mob/living/carbon/xenomorph/X = M
X.use_plasma(0.3 * X.xeno_caste.plasma_max * X.xeno_caste.plasma_regen_limit) //Drains 30% of max plasma on hit
+/datum/ammo/energy/lasburster
+ name = "lasburster bolt"
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN
+ hud_state = "laser_overcharge"
+ armor_type = LASER
+ damage = 40
+ penetration = 5
+ max_range = 7
+ hitscan_effect_icon = "beam_heavy"
+
/datum/ammo/energy/lasgun
name = "laser bolt"
icon_state = "laser"
hud_state = "laser"
- armor_type = "laser"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING
+ armor_type = LASER
+ ammo_behavior_flags = AMMO_ENERGY
shell_speed = 4
accurate_range = 15
damage = 20
@@ -2789,7 +2946,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "laser_heat"
damage = 12 //requires mod with -0.15 multiplier should math out to 10
penetration = 100 // It's a laser that burns the skin! The fire stacks go threw anyway.
- flags_ammo_behavior = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_SUNDERING
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY
sundering = 1
/datum/ammo/energy/lasgun/M43/blast
@@ -2849,7 +3006,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 45
penetration = 0
damage_type = STAMINA
- flags_ammo_behavior = AMMO_ENERGY
+ ammo_behavior_flags = AMMO_ENERGY
bullet_color = COLOR_DISABLER_BLUE
/datum/ammo/energy/lasgun/M43/practice/on_hit_mob(mob/living/carbon/C, obj/projectile/P)
@@ -2866,7 +3023,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
// TE Lasers //
/datum/ammo/energy/lasgun/marine
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN
damage = 20
penetration = 10
sundering = 1.5
@@ -2996,7 +3153,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
penetration = 30
sundering = 3
hitscan_effect_icon = "beam_heavy"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOB
/datum/ammo/energy/lasgun/marine/autolaser/charge/on_hit_turf(turf/T, obj/projectile/proj)
if(istype(T, /turf/closed/wall))
@@ -3032,7 +3189,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 60
penetration = 30
accurate_range_min = 5
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN|AMMO_SNIPER
sundering = 5
max_range = 40
damage_falloff = 0
@@ -3045,7 +3202,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 40
penetration = 10
accurate_range_min = 5
- flags_ammo_behavior = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_HITSCAN|AMMO_SNIPER
sundering = 1
hitscan_effect_icon = "u_laser_beam"
bullet_color = COLOR_DISABLER_BLUE
@@ -3080,7 +3237,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hud_state = "laser_heat"
damage = 100
penetration = 30
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_SNIPER
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN|AMMO_SNIPER
sundering = 1
hitscan_effect_icon = "u_laser_beam"
bonus_projectiles_scatter = 0
@@ -3133,7 +3290,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage = 20
shell_speed = 2.5
penetration = 10
- flags_ammo_behavior = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_SUNDERING|AMMO_HITSCAN
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_HITSCAN
sundering = 0.5
hitscan_effect_icon = "beam_incen"
bullet_color = COLOR_LASER_RED
@@ -3145,7 +3302,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "xray heat bolt"
hud_state = "laser_xray"
icon_state = "u_laser"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_SUNDERING|AMMO_HITSCAN
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_HITSCAN
damage = 25
penetration = 5
sundering = 1
@@ -3155,14 +3312,14 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/lasgun/marine/xray/piercing
name = "xray piercing bolt"
icon_state = "xray"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_HITSCAN|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_HITSCAN|AMMO_PASS_THROUGH_TURF|AMMO_PASS_THROUGH_MOVABLE
damage = 25
penetration = 100
max_range = 10
hitscan_effect_icon = "xray_beam"
/datum/ammo/energy/lasgun/marine/heavy_laser
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_INCENDIARY
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_SNIPER|AMMO_ENERGY|AMMO_HITSCAN|AMMO_INCENDIARY
hud_state = "laser_overcharge"
damage = 60
penetration = 10
@@ -3188,6 +3345,172 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/lasgun/marine/heavy_laser/do_at_max_range(turf/T, obj/projectile/P)
drop_nade(T.density ? get_step_towards(T, P) : T)
+/datum/ammo/energy/plasma
+ name = "superheated plasma"
+ icon_state = "plasma_small"
+ hud_state = "plasma"
+ hud_state_empty = "battery_empty"
+ armor_type = ENERGY
+ bullet_color = COLOR_DISABLER_BLUE
+ ammo_behavior_flags = AMMO_ENERGY
+ shell_speed = 3
+
+/datum/ammo/energy/plasma/rifle_standard
+ damage = 25
+ penetration = 20
+ sundering = 0.75
+
+/datum/ammo/energy/plasma/rifle_marksman
+ icon_state = "plasma_big"
+ hud_state = "plasma_blast"
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_PASS_THROUGH_MOB
+ damage = 40
+ penetration = 30
+ sundering = 2
+ damage_falloff = 0.5
+ accurate_range = 25
+
+/datum/ammo/energy/plasma/rifle_marksman/on_hit_mob(mob/M, obj/projectile/proj)
+ if(!isliving(M))
+ return
+ var/mob/living/living_victim = M
+ living_victim.apply_status_effect(STATUS_EFFECT_SHATTER, 2 SECONDS)
+
+/datum/ammo/energy/plasma/blast
+ name = "plasma blast"
+ icon_state = "plasma_ball_small"
+ hud_state = "plasma_blast"
+ damage = 30
+ penetration = 10
+ sundering = 2
+ damage_falloff = 0.5
+ accurate_range = 5
+ max_range = 12
+
+/datum/ammo/energy/plasma/blast/drop_nade(turf/T)
+ explosion(T, weak_impact_range = 3, color = COLOR_DISABLER_BLUE)
+
+/datum/ammo/energy/plasma/blast/on_hit_obj(obj/O, obj/projectile/P)
+ drop_nade(O.density ? P.loc : O.loc)
+
+/datum/ammo/energy/plasma/blast/on_hit_turf(turf/T, obj/projectile/P)
+ drop_nade(T.density ? P.loc : T)
+
+/datum/ammo/energy/plasma/blast/do_at_max_range(turf/T, obj/projectile/P)
+ drop_nade(T.density ? P.loc : T)
+
+/datum/ammo/energy/plasma/blast/on_hit_mob(mob/M, obj/projectile/proj)
+ drop_nade(M.loc)
+
+/datum/ammo/energy/plasma/blast/melting
+ damage = 40
+ sundering = 3
+ damage_falloff = 0.5
+ accurate_range = 7
+ ///Number of melting stacks to apply
+ var/melting_stacks = 2
+
+/datum/ammo/energy/plasma/blast/melting/drop_nade(turf/T)
+ explosion(T, weak_impact_range = 4, color = COLOR_DISABLER_BLUE)
+ for(var/mob/living/living_victim in viewers(3, T)) //normally using viewers wouldn't work due to darkness and smoke both blocking vision. However explosions clear both temporarily so we avoid this issue.
+ var/datum/status_effect/stacking/melting/debuff = living_victim.has_status_effect(STATUS_EFFECT_MELTING)
+ if(debuff)
+ debuff.add_stacks(melting_stacks)
+ else
+ living_victim.apply_status_effect(STATUS_EFFECT_MELTING, melting_stacks)
+
+/datum/ammo/energy/plasma/blast/shatter
+ damage = 40
+ sundering = 3
+ damage_falloff = 0.5
+ accurate_range = 9
+ ammo_behavior_flags = AMMO_ENERGY
+
+/datum/ammo/energy/plasma/blast/shatter/drop_nade(turf/T)
+ explosion(T, light_impact_range = 2, weak_impact_range = 5, throw_range = 0, color = COLOR_DISABLER_BLUE)
+ for(var/mob/living/living_victim in viewers(3, T))
+ living_victim.apply_status_effect(STATUS_EFFECT_SHATTER, 5 SECONDS)
+
+/datum/ammo/energy/plasma/blast/incendiary
+ name = "plasma glob"
+ damage = 30
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY
+ shell_speed = 2
+ icon_state = "plasma_big"
+ hud_state = "flame"
+
+/datum/ammo/energy/plasma/blast/incendiary/drop_nade(turf/T)
+ flame_radius(2, T, burn_duration = 9, colour = "blue")
+ playsound(T, 'sound/weapons/guns/fire/flamethrower2.ogg', 35, 1, 4)
+
+#define PLASMA_CANNON_INNER_STAGGERSTUN_RANGE 3
+#define PLASMA_CANNON_STAGGERSTUN_RANGE 9
+#define PLASMA_CANNON_STAGGER_DURATION 3 SECONDS
+#define PLASMA_CANNON_SHATTER_DURATION 5 SECONDS
+/datum/ammo/energy/plasma/cannon_heavy
+ name = "plasma heavy glob"
+ icon_state = "plasma_ball_big"
+ hud_state = "plasma_sphere"
+ damage = 60
+ penetration = 40
+ sundering = 10
+
+/datum/ammo/energy/plasma/cannon_heavy/on_hit_mob(mob/M, obj/projectile/proj)
+ var/damage_mult = 1
+ switch(M.mob_size)
+ if(MOB_SIZE_BIG)
+ damage_mult = 2
+ if(MOB_SIZE_XENO)
+ damage_mult = 1.5
+
+ proj.damage *= damage_mult
+ if(!isliving(M))
+ return
+ var/mob/living/living_victim = M
+ living_victim.apply_status_effect(STATUS_EFFECT_SHATTER, PLASMA_CANNON_SHATTER_DURATION)
+ staggerstun(living_victim, proj, PLASMA_CANNON_INNER_STAGGERSTUN_RANGE, weaken = 0.5 SECONDS, knockback = 1, hard_size_threshold = 1)
+ staggerstun(living_victim, proj, PLASMA_CANNON_STAGGERSTUN_RANGE, stagger = PLASMA_CANNON_STAGGER_DURATION, slowdown = 2, knockback = 1, hard_size_threshold = 2)
+
+/datum/ammo/energy/plasma/cannon_heavy/on_hit_obj(obj/O, obj/projectile/proj)
+ var/damage_mult = 3
+ if(isvehicle(O))
+ var/obj/vehicle/vehicle_target = O
+ if(ismecha(vehicle_target) || isarmoredvehicle(vehicle_target))
+ damage_mult = 4
+ if(get_dist_euclidean(proj.starting_turf, vehicle_target) <= PLASMA_CANNON_STAGGERSTUN_RANGE) //staggerstun will fail on tank occupants if we just use staggerstun
+ for(var/mob/living/living_victim AS in vehicle_target.occupants)
+ living_victim.Stagger(PLASMA_CANNON_STAGGER_DURATION)
+ to_chat(living_victim, "You are knocked about by the impact, staggering you!")
+ proj.damage *= damage_mult
+
+/datum/ammo/energy/plasma/cannon_heavy/on_hit_turf(turf/T, obj/projectile/proj)
+ proj.damage *= 5
+
+#undef PLASMA_CANNON_INNER_STAGGERSTUN_RANGE
+#undef PLASMA_CANNON_STAGGERSTUN_RANGE
+#undef PLASMA_CANNON_STAGGER_DURATION
+#undef PLASMA_CANNON_SHATTER_DURATION
+
+/datum/ammo/energy/plasma/smg_standard
+ icon_state = "plasma_ball_small"
+ damage = 22
+ penetration = 10
+ sundering = 0.5
+
+/datum/ammo/energy/plasma/smg_standard/one
+ bonus_projectiles_type = /datum/ammo/energy/plasma/smg_standard
+
+/datum/ammo/energy/plasma/smg_standard/two
+ bonus_projectiles_type = /datum/ammo/energy/plasma/smg_standard/one
+
+/datum/ammo/energy/plasma/smg_standard/three
+ bonus_projectiles_type = /datum/ammo/energy/plasma/smg_standard/two
+
+/datum/ammo/energy/plasma/smg_standard/four
+ bonus_projectiles_type = /datum/ammo/energy/plasma/smg_standard/three
+
+/datum/ammo/energy/plasma/smg_standard/on_hit_turf(turf/T, obj/projectile/proj)
+ reflect(T, proj, 5)
/datum/ammo/energy/xeno
barricade_clear_distance = 0
@@ -3200,7 +3523,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/xeno/psy_blast
name = "psychic blast"
- flags_ammo_behavior = AMMO_XENO|AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_TARGET_TURF|AMMO_SNIPER|AMMO_ENERGY|AMMO_HITSCAN|AMMO_SKIPS_ALIENS
damage = 35
penetration = 10
sundering = 1
@@ -3223,7 +3546,6 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
var/mob/living/carbon/xenomorph/xeno_firer = P.firer
aoe_damage = xeno_firer.xeno_caste.blast_strength
- var/list/throw_atoms = list()
var/list/turf/target_turfs = generate_true_cone(T, aoe_range, -1, 359, 0, air_pass = TRUE)
for(var/turf/target_turf AS in target_turfs)
for(var/atom/movable/target AS in target_turf)
@@ -3238,16 +3560,11 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
var/obj/obj_victim = target
if(!(obj_victim.resistance_flags & XENO_DAMAGEABLE))
continue
+ if(isbarricade(target))
+ continue
obj_victim.take_damage(aoe_damage, BURN, ENERGY, TRUE, armour_penetration = penetration)
if(target.anchored)
continue
- throw_atoms += target
-
- for(var/atom/movable/target AS in throw_atoms)
- var/throw_dir = get_dir(T, target)
- if(T == get_turf(target))
- throw_dir = get_dir(P.starting_turf, T)
- target.safe_throw_at(get_ranged_target_turf(T, throw_dir, 5), 3, 1, spin = TRUE)
new /obj/effect/temp_visual/shockwave(T, aoe_range + 2)
@@ -3265,7 +3582,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/xeno/psy_blast/psy_lance
name = "psychic lance"
- flags_ammo_behavior = AMMO_XENO|AMMO_ENERGY|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOVABLE
+ ammo_behavior_flags = AMMO_XENO|AMMO_ENERGY|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOVABLE
damage = 60
penetration = 50
accuracy = 100
@@ -3278,14 +3595,14 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
glow_color = "#CB0166"
/datum/ammo/energy/xeno/psy_blast/psy_lance/on_hit_obj(obj/O, obj/projectile/P)
- if(ismecha(O))
- var/obj/vehicle/sealed/mecha/mech_victim = O
- mech_victim.take_damage(200, BURN, ENERGY, TRUE, armour_penetration = penetration)
+ if(isvehicle(O))
+ var/obj/vehicle/veh_victim = O
+ veh_victim.take_damage(200, BURN, ENERGY, TRUE, armour_penetration = penetration)
/datum/ammo/energy/xeno/psy_blast/psy_lance/on_hit_mob(mob/M, obj/projectile/P)
if(isxeno(M))
return
- staggerstun(M, P, 9, stagger = 4 SECONDS, slowdown = 2, knockback = 1)
+ staggerstun(M, P, 9, stagger = 1 SECONDS, slowdown = 2, knockback = 1)
/datum/ammo/energy/xeno/psy_blast/psy_lance/on_hit_turf(turf/T, obj/projectile/P)
return
@@ -3314,7 +3631,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/energy/lasgun/marine/mech/lance_strike
name = "particle lance"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SNIPER|AMMO_SUNDERING|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOVABLE|AMMO_PASS_THROUGH_MOB
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SNIPER|AMMO_HITSCAN|AMMO_PASS_THROUGH_MOVABLE|AMMO_PASS_THROUGH_MOB
damage_type = BRUTE
damage = 100
armor_type = MELEE
@@ -3331,11 +3648,11 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
max_range = 5
// Plasma //
-/datum/ammo/energy/plasma
+/datum/ammo/energy/sectoid_plasma
name = "plasma bolt"
icon_state = "pulse2"
hud_state = "plasma"
- armor_type = "laser"
+ armor_type = LASER
shell_speed = 4
accurate_range = 15
damage = 40
@@ -3353,7 +3670,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
max_range = 14
penetration = 5
shell_speed = 1.5
- flags_ammo_behavior = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_EXPLOSIVE
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_INCENDIARY|AMMO_TARGET_TURF
bullet_color = LIGHT_COLOR_ELECTRIC_GREEN
///Fire burn time
@@ -3395,9 +3712,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "overchargedlaser"
hud_state = "laser_heat"
hud_state_empty = "battery_empty_flash"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_SUNDERING|AMMO_SOUND_PITCH
+ ammo_behavior_flags = AMMO_ENERGY|AMMO_SOUND_PITCH
bullet_color = COLOR_TAN_ORANGE
- armor_type = "energy"
+ armor_type = ENERGY
max_range = 14
accurate_range = 5 //for charger
shell_speed = 4
@@ -3409,6 +3726,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
penetration = 10
sundering = 2
fire_burst_damage = 15
+ deflagrate_multiplier = 1
//inherited, could use some changes
ping = "ping_s"
@@ -3427,15 +3745,17 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
accuracy_var_low = 3
accuracy_var_high = 3
fire_burst_damage = 20
+ deflagrate_multiplier = 0.9
/datum/ammo/energy/volkite/medium/custom
- deflagrate_multiplier = 2
+ deflagrate_multiplier = 1.8
/datum/ammo/energy/volkite/heavy
max_range = 35
accurate_range = 12
damage = 25
fire_burst_damage = 20
+ deflagrate_multiplier = 0.9
/datum/ammo/energy/volkite/light
max_range = 25
@@ -3443,6 +3763,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
accuracy_var_low = 3
accuracy_var_high = 3
penetration = 5
+ deflagrate_multiplier = 0.9
/*
//================================================
@@ -3453,10 +3774,10 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "neurotoxin"
ping = "ping_x"
damage_type = TOX
- flags_ammo_behavior = AMMO_XENO
+ ammo_behavior_flags = AMMO_XENO
var/added_spit_delay = 0 //used to make cooldown of the different spits vary.
var/spit_cost = 5
- armor_type = "bio"
+ armor_type = BIO
shell_speed = 1
accuracy = 40
accurate_range = 15
@@ -3481,7 +3802,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/xeno/toxin
name = "neurotoxic spit"
- flags_ammo_behavior = AMMO_XENO|AMMO_EXPLOSIVE|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_TARGET_TURF|AMMO_SKIPS_ALIENS
spit_cost = 55
added_spit_delay = 0
damage_type = STAMINA
@@ -3569,9 +3890,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
name = "sticky resin spit"
icon_state = "sticky"
ping = null
- flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_XENO
+ ammo_behavior_flags = AMMO_SKIPS_ALIENS|AMMO_TARGET_TURF|AMMO_XENO
damage_type = STAMINA
- armor_type = "bio"
+ armor_type = BIO
spit_cost = 50
sound_hit = "alien_resin_build2"
sound_bounce = "alien_resin_build3"
@@ -3593,6 +3914,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/xeno/sticky/on_hit_obj(obj/O, obj/projectile/P)
+ if(isarmoredvehicle(O))
+ var/obj/vehicle/sealed/armored/tank = O
+ COOLDOWN_START(tank, cooldown_vehicle_move, tank.move_delay)
var/turf/T = get_turf(O)
drop_resin(T.density ? P.loc : T)
@@ -3660,8 +3984,8 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage_type = BURN
added_spit_delay = 5
spit_cost = 50
- flags_ammo_behavior = AMMO_XENO|AMMO_EXPLOSIVE
- armor_type = "acid"
+ ammo_behavior_flags = AMMO_XENO|AMMO_TARGET_TURF
+ armor_type = ACID
damage = 18
max_range = 8
bullet_color = COLOR_PALE_GREEN_GRAY
@@ -3681,7 +4005,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/xeno/acid/medium
name = "acid spatter"
damage = 30
- flags_ammo_behavior = AMMO_XENO
+ ammo_behavior_flags = AMMO_XENO
/datum/ammo/xeno/acid/auto
name = "light acid spatter"
@@ -3706,7 +4030,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/xeno/acid/passthrough
name = "acid spittle"
damage = 20
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS
/datum/ammo/xeno/acid/heavy
name = "acid splash"
@@ -3736,7 +4060,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
///For the Spitter's Scatterspit ability
/datum/ammo/xeno/acid/heavy/scatter
damage = 20
- flags_ammo_behavior = AMMO_XENO|AMMO_EXPLOSIVE|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_TARGET_TURF|AMMO_SKIPS_ALIENS
bonus_projectiles_type = /datum/ammo/xeno/acid/heavy/scatter
bonus_projectiles_amount = 6
bonus_projectiles_scatter = 2
@@ -3751,15 +4075,15 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
var/icon_key = BOILER_GLOB_NEURO
///This text will show up when a boiler selects this ammo. Span proc should be applied when this var is used.
var/select_text = "We will now fire neurotoxic gas. This is nonlethal."
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_TARGET_TURF
var/danger_message = span_danger("A glob of acid lands with a splat and explodes into noxious fumes!")
- armor_type = "bio"
+ armor_type = BIO
accuracy_var_high = 10
max_range = 30
damage = 50
damage_type = STAMINA
damage_falloff = 0
- penetration = 40
+ penetration = 50
bullet_color = BOILER_LUMINOSITY_AMMO_NEUROTOXIN_COLOR
reagent_transfer_amount = 30
///On a direct hit, how long is the target paralyzed?
@@ -3775,9 +4099,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
///We're going to reuse one smoke spread system repeatedly to cut down on processing.
var/datum/effect_system/smoke_spread/xeno/trail_spread_system
-/datum/ammo/xeno/boiler_gas/on_leave_turf(turf/T, atom/firer, obj/projectile/proj)
- if(isxeno(firer))
- var/mob/living/carbon/xenomorph/X = firer
+/datum/ammo/xeno/boiler_gas/on_leave_turf(turf/T, obj/projectile/proj)
+ if(isxeno(proj.firer))
+ var/mob/living/carbon/xenomorph/X = proj.firer
trail_spread_system.strength = X.xeno_caste.bomb_strength
trail_spread_system.set_up(0, T)
trail_spread_system.start()
@@ -3800,7 +4124,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
/datum/ammo/xeno/boiler_gas/New()
. = ..()
- if((flags_ammo_behavior & AMMO_LEAVE_TURF) && passed_turf_smoke_type)
+ if((ammo_behavior_flags & AMMO_LEAVE_TURF) && passed_turf_smoke_type)
trail_spread_system = new passed_turf_smoke_type(only_once = FALSE)
/datum/ammo/xeno/boiler_gas/Destroy()
@@ -3866,12 +4190,12 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sound_bounce = "acid_bounce"
icon_key = BOILER_GLOB_ACID
select_text = "We will now fire corrosive acid. This is lethal!"
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE
- armor_type = "acid"
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_TARGET_TURF
+ armor_type = ACID
danger_message = span_danger("A glob of acid lands with a splat and explodes into corrosive bile!")
damage = 50
damage_type = BURN
- penetration = 40
+ penetration = 50
bullet_color = BOILER_LUMINOSITY_AMMO_CORROSIVE_COLOR
hit_paralyze_time = 1 SECONDS
hit_eye_blur = 1
@@ -3897,11 +4221,11 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_key = BOILER_GLOB_NEURO_LANCE
select_text = "We will now fire a pressurized neurotoxic lance. This is barely nonlethal."
///As opposed to normal globs, this will pass by the target tile if they hit nothing.
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_LEAVE_TURF
danger_message = span_danger("A pressurized glob of acid lands with a nasty splat and explodes into noxious fumes!")
- max_range = 40
+ max_range = 25
damage = 75
- penetration = 60
+ penetration = 70
reagent_transfer_amount = 55
passed_turf_smoke_type = /datum/effect_system/smoke_spread/xeno/neuro/light
hit_paralyze_time = 2 SECONDS
@@ -3917,24 +4241,23 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_key = BOILER_GLOB_ACID_LANCE
select_text = "We will now fire a pressurized corrosive lance. This lethal!"
///As opposed to normal globs, this will pass by the target tile if they hit nothing.
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_LEAVE_TURF
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_LEAVE_TURF
danger_message = span_danger("A pressurized glob of acid lands with a concerning hissing sound and explodes into corrosive bile!")
- max_range = 40
+ max_range = 25
damage = 75
- penetration = 60
+ penetration = 70
passed_turf_smoke_type = /datum/effect_system/smoke_spread/xeno/acid/light
hit_paralyze_time = 1.5 SECONDS
hit_eye_blur = 4
hit_drowsyness = 2
fixed_spread_range = 2
accuracy = 100
- accurate_range = 30
shell_speed = 1.5
/datum/ammo/xeno/hugger
name = "hugger ammo"
ping = ""
- flags_ammo_behavior = AMMO_XENO
+ ammo_behavior_flags = AMMO_XENO
damage = 0
max_range = 6
shell_speed = 1
@@ -3963,7 +4286,10 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
hugger_type = /obj/item/clothing/mask/facehugger/combat/slash
/datum/ammo/xeno/hugger/neuro
- hugger_type = /obj/item/clothing/mask/facehugger/combat/neuro
+ hugger_type = /obj/item/clothing/mask/facehugger/combat/chem_injector/neuro
+
+/datum/ammo/xeno/hugger/ozelomelyn
+ hugger_type = /obj/item/clothing/mask/facehugger/combat/chem_injector/ozelomelyn
/datum/ammo/xeno/hugger/resin
hugger_type = /obj/item/clothing/mask/facehugger/combat/resin
@@ -3979,7 +4305,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
sound_bounce = "alien_resin_build3"
damage_type = STAMINA
bullet_color = COLOR_PURPLE
- flags_ammo_behavior = AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_SKIPS_ALIENS
ping = null
armor_type = BIO
accurate_range = 15
@@ -4015,7 +4341,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
icon_state = "widow_snareball"
ping = "ping_x"
damage_type = STAMINA
- flags_ammo_behavior = AMMO_SKIPS_ALIENS | AMMO_EXPLOSIVE
+ ammo_behavior_flags = AMMO_SKIPS_ALIENS | AMMO_TARGET_TURF
bullet_color = COLOR_PURPLE
ping = null
damage = 0
@@ -4053,7 +4379,7 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh
damage_type = BRUTE
bullet_color = COLOR_WHITE
sound_hit = 'sound/bullets/spear_armor1.ogg'
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS
+ ammo_behavior_flags = AMMO_XENO|AMMO_SKIPS_ALIENS
RU TGMC EDIT*/
/*
//================================================
@@ -4065,10 +4391,10 @@ RU TGMC EDIT*/
name = "pepperball"
hud_state = "pepperball"
hud_state_empty = "pepperball_empty"
- flags_ammo_behavior = AMMO_BALLISTIC
+ ammo_behavior_flags = AMMO_BALLISTIC
accurate_range = 15
damage_type = STAMINA
- armor_type = "bio"
+ armor_type = BIO
damage = 70
penetration = 0
shrapnel_chance = 0
@@ -4080,8 +4406,9 @@ RU TGMC EDIT*/
/datum/ammo/bullet/pepperball/on_hit_mob(mob/living/victim, obj/projectile/proj)
if(isxeno(victim))
var/mob/living/carbon/xenomorph/X = victim
- X.use_plasma(drain_multiplier * X.xeno_caste.plasma_max * X.xeno_caste.plasma_regen_limit)
- X.use_plasma(plasma_drain)
+ if(!(X.xeno_caste.caste_flags & CASTE_PLASMADRAIN_IMMUNE))
+ X.use_plasma(drain_multiplier * X.xeno_caste.plasma_max * X.xeno_caste.plasma_regen_limit)
+ X.use_plasma(plasma_drain)
/datum/ammo/bullet/pepperball/pepperball_mini
damage = 40
@@ -4109,8 +4436,8 @@ RU TGMC EDIT*/
hud_state = "flame"
hud_state_empty = "flame_empty"
damage_type = BURN
- flags_ammo_behavior = AMMO_INCENDIARY|AMMO_FLAME|AMMO_EXPLOSIVE
- armor_type = "fire"
+ ammo_behavior_flags = AMMO_INCENDIARY|AMMO_FLAME|AMMO_TARGET_TURF
+ armor_type = FIRE
max_range = 7
damage = 31
damage_falloff = 0
@@ -4164,7 +4491,7 @@ RU TGMC EDIT*/
damage = 0
shell_speed = 1
damage_type = BURN
- flags_ammo_behavior = AMMO_EXPLOSIVE
+ ammo_behavior_flags = AMMO_TARGET_TURF
bullet_color = null
/datum/ammo/water/proc/splash(turf/extinguished_turf, splash_direction)
@@ -4209,7 +4536,7 @@ RU TGMC EDIT*/
damage_type = BRUTE
var/nade_type = /obj/item/explosive/grenade
icon_state = "grenade"
- armor_type = "bomb"
+ armor_type = BOMB
damage = 15
accuracy = 15
max_range = 10
@@ -4239,7 +4566,7 @@ RU TGMC EDIT*/
/datum/ammo/grenade_container/ags_grenade
name = "grenade shell"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_IFF
+ ammo_behavior_flags = AMMO_TARGET_TURF|AMMO_IFF
icon_state = "grenade_projectile"
hud_state = "grenade_he"
hud_state_empty = "grenade_empty"
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index d396b81d1d863..402276f43088d 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -8,8 +8,8 @@
slot_l_hand_str = 'icons/mob/inhands/weapons/ammo_left.dmi',
slot_r_hand_str = 'icons/mob/inhands/weapons/ammo_right.dmi',
)
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
throwforce = 2
w_class = WEIGHT_CLASS_TINY
throw_speed = 2
@@ -33,7 +33,7 @@
///Just an easier way to track how many shells to eject later.
var/used_casings = 0
///flags specifically for magazines.
- var/flags_magazine = MAGAZINE_REFILLABLE
+ var/magazine_flags = MAGAZINE_REFILLABLE
///the default mag icon state.
var/base_mag_icon
@@ -53,7 +53,8 @@
update_icon()
/obj/item/ammo_magazine/update_icon_state()
- if(CHECK_BITFIELD(flags_magazine, MAGAZINE_HANDFUL))
+ . = ..()
+ if(CHECK_BITFIELD(magazine_flags, MAGAZINE_HANDFUL))
setDir(current_rounds + round(current_rounds/3))
return
if(current_rounds <= 0)
@@ -67,7 +68,7 @@
/obj/item/ammo_magazine/attack_hand(mob/living/user)
- if(user.get_inactive_held_item() != src || !CHECK_BITFIELD(flags_magazine, MAGAZINE_REFILLABLE))
+ if(user.get_inactive_held_item() != src || !CHECK_BITFIELD(magazine_flags, MAGAZINE_REFILLABLE))
return ..()
if(current_rounds <= 0)
to_chat(user, span_notice("[src] is empty. There is nothing to grab."))
@@ -76,8 +77,10 @@
/obj/item/ammo_magazine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/ammo_magazine))
- if(!CHECK_BITFIELD(flags_magazine, MAGAZINE_WORN) || !istype(I, /obj/item/weapon/gun) || loc != user)
+ if(!CHECK_BITFIELD(magazine_flags, MAGAZINE_WORN) || !istype(I, /obj/item/weapon/gun) || loc != user)
return ..()
var/obj/item/weapon/gun/gun = I
if(!CHECK_BITFIELD(gun.reciever_flags, AMMO_RECIEVER_MAGAZINES))
@@ -85,10 +88,10 @@
gun.reload(src, user)
return
- if(!CHECK_BITFIELD(flags_magazine, MAGAZINE_REFILLABLE)) //and a refillable magazine
+ if(!CHECK_BITFIELD(magazine_flags, MAGAZINE_REFILLABLE)) //and a refillable magazine
return
- if(src != user.get_inactive_held_item() && !CHECK_BITFIELD(flags_magazine, MAGAZINE_HANDFUL)) //It has to be held.
+ if(src != user.get_inactive_held_item() && !CHECK_BITFIELD(magazine_flags, MAGAZINE_HANDFUL)) //It has to be held.
to_chat(user, span_notice("Try holding [src] before you attempt to restock it."))
return
@@ -149,7 +152,7 @@
source.current_rounds -= amount_difference
current_rounds += amount_difference
- if(source.current_rounds <= 0 && CHECK_BITFIELD(source.flags_magazine, MAGAZINE_HANDFUL)) //We want to delete it if it's a handful.
+ if(source.current_rounds <= 0 && CHECK_BITFIELD(source.magazine_flags, MAGAZINE_HANDFUL)) //We want to delete it if it's a handful.
user?.temporarilyRemoveItemFromInventory(source)
QDEL_NULL(source) //Dangerous. Can mean future procs break if they reference the source. Have to account for this.
else
@@ -170,13 +173,13 @@
user.put_in_hands(new_handful)
to_chat(user, span_notice("You grab [rounds] round\s from [src]."))
update_icon() //Update the other one.
- if(current_rounds <= 0 && CHECK_BITFIELD(flags_magazine, MAGAZINE_HANDFUL))
+ if(current_rounds <= 0 && CHECK_BITFIELD(magazine_flags, MAGAZINE_HANDFUL))
user.temporarilyRemoveItemFromInventory(src)
qdel(src)
return rounds //Give the number created.
else
update_icon()
- if(current_rounds <= 0 && CHECK_BITFIELD(flags_magazine, MAGAZINE_HANDFUL))
+ if(current_rounds <= 0 && CHECK_BITFIELD(magazine_flags, MAGAZINE_HANDFUL))
qdel(src)
return new_handful
@@ -221,15 +224,30 @@
/obj/item/ammo_magazine/handful
name = "generic handful of bullets or shells"
desc = "A handful of rounds to reload on the go."
- flags_equip_slot = null // It only fits into pockets and such.
+ equip_slot_flags = null // It only fits into pockets and such.
w_class = WEIGHT_CLASS_SMALL
current_rounds = 1 // So it doesn't get autofilled for no reason.
max_rounds = 5 // For shotguns, though this will be determined by the handful type when generated.
- flags_atom = CONDUCT|DIRLOCK
- flags_magazine = MAGAZINE_HANDFUL|MAGAZINE_REFILLABLE
+ atom_flags = CONDUCT|DIRLOCK
+ magazine_flags = MAGAZINE_HANDFUL|MAGAZINE_REFILLABLE
attack_speed = 3 // should make reloading less painful
icon_state_mini = "bullets"
+/obj/item/ammo_magazine/handful/repeater
+ name = "handful of heavy impact rifle bullet (.45-70 Government)"
+ icon_state = "bullet"
+ current_rounds = 8
+ max_rounds = 8
+ default_ammo = /datum/ammo/bullet/rifle/repeater
+ caliber = CALIBER_4570
+
+/obj/item/ammo_magazine/handful/slug
+ name = "handful of shotgun slug (12 gauge)"
+ icon_state = "shotgun slug"
+ current_rounds = 5
+ default_ammo = /datum/ammo/bullet/shotgun/slug
+ caliber = CALIBER_12G
+
/obj/item/ammo_magazine/handful/buckshot
name = "handful of shotgun buckshot shells (12g)"
icon_state = "shotgun buckshot shell"
@@ -300,7 +318,7 @@ Turn() or Shift() as there is virtually no overhead. ~N
w_class = WEIGHT_CLASS_TINY
layer = LOWER_ITEM_LAYER //Below other objects
dir = 1 //Always north when it spawns.
- flags_atom = CONDUCT|DIRLOCK
+ atom_flags = CONDUCT|DIRLOCK
var/current_casings = 1 //This is manipulated in the procs that use these.
var/max_casings = 16
var/current_icon = 0
@@ -313,10 +331,16 @@ Turn() or Shift() as there is virtually no overhead. ~N
pixel_y = rand(-2, 2)
icon_state = initial_icon_state += "[rand(1, number_of_states)]" //Set the icon to it.
-//This does most of the heavy lifting. It updates the icon and name if needed, then changes .dir to simulate new casings.
-/obj/item/ammo_casing/update_icon()
+//This does most of the heavy lifting. It updates the icon and name if needed
+
+/obj/item/ammo_casing/update_name(updates)
+ . = ..()
+ if(max_casings >= current_casings && current_casings == 2)
+ name += "s" //In case there is more than one.
+
+/obj/item/ammo_casing/update_icon_state()
+ . = ..()
if(max_casings >= current_casings)
- if(current_casings == 2) name += "s" //In case there is more than one.
if(round((current_casings-1)/8) > current_icon)
current_icon++
icon_state += "_[current_icon]"
@@ -324,9 +348,24 @@ Turn() or Shift() as there is virtually no overhead. ~N
var/base_direction = current_casings - (current_icon * 8)
setDir(base_direction + round(base_direction)/3)
switch(current_casings)
- if(3 to 5) w_class = WEIGHT_CLASS_SMALL //Slightly heavier.
- if(9 to 10) w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff.
+ if(3 to 5)
+ w_class = WEIGHT_CLASS_SMALL //Slightly heavier.
+ if(9 to 10)
+ w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff.
+
+///changes .dir to simulate new casings, also sets the new w_class
+/obj/item/ammo_casing/proc/update_dir()
+ var/base_direction = current_casings - (current_icon * 8)
+ setDir(base_direction + round(base_direction)/3)
+ switch(current_casings)
+ if(3 to 5)
+ w_class = WEIGHT_CLASS_SMALL //Slightly heavier.
+ if(9 to 10)
+ w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff.
+/obj/item/ammo_casing/update_icon()
+ update_dir()
+ return ..()
//Making child objects so that locate() and istype() doesn't screw up.
/obj/item/ammo_casing/bullet
@@ -352,7 +391,7 @@ Turn() or Shift() as there is virtually no overhead. ~N
icon = 'icons/obj/items/ammo.dmi'
icon_state = "big_ammo_box"
item_state = "big_ammo_box"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
base_icon_state = "big_ammo_box"
var/default_ammo = /datum/ammo/bullet/rifle
var/bullet_amount = 2400
@@ -360,6 +399,7 @@ Turn() or Shift() as there is virtually no overhead. ~N
var/caliber = CALIBER_10X24_CASELESS
/obj/item/big_ammo_box/update_icon_state()
+ . = ..()
if(bullet_amount)
icon_state = base_icon_state
return
@@ -374,13 +414,15 @@ Turn() or Shift() as there is virtually no overhead. ~N
/obj/item/big_ammo_box/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/AM = I
if(!isturf(loc))
to_chat(user, span_warning("[src] must be on the ground to be used."))
return
- if(AM.flags_magazine & MAGAZINE_REFILLABLE)
+ if(AM.magazine_flags & MAGAZINE_REFILLABLE)
if(default_ammo != AM.default_ammo)
to_chat(user, span_warning("Those aren't the same rounds. Better not mix them up."))
return
@@ -398,13 +440,13 @@ Turn() or Shift() as there is virtually no overhead. ~N
var/S = min(bullet_amount, AM.max_rounds - AM.current_rounds)
AM.current_rounds += S
bullet_amount -= S
- AM.update_icon(S)
+ AM.update_icon()
update_icon()
if(AM.current_rounds == AM.max_rounds)
to_chat(user, span_notice("You refill [AM]."))
else
to_chat(user, span_notice("You put [S] rounds in [AM]."))
- else if(AM.flags_magazine & MAGAZINE_HANDFUL)
+ else if(AM.magazine_flags & MAGAZINE_HANDFUL)
if(caliber != AM.caliber)
to_chat(user, span_warning("The rounds don't match up. Better not mix them up."))
return
@@ -437,7 +479,7 @@ Turn() or Shift() as there is virtually no overhead. ~N
item_state = "ammoboxslug"
base_icon_state = "ammoboxslug"
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
///Current stored rounds
var/current_rounds = 200
///Maximum stored rounds
@@ -450,7 +492,8 @@ Turn() or Shift() as there is virtually no overhead. ~N
var/caliber = CALIBER_12G
-/obj/item/shotgunbox/update_icon()
+/obj/item/shotgunbox/update_icon_state()
+ . = ..()
if(!deployed)
icon_state = "[initial(icon_state)]"
else if(current_rounds > 0)
@@ -508,6 +551,8 @@ Turn() or Shift() as there is virtually no overhead. ~N
/obj/item/shotgunbox/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(!istype(I, /obj/item/ammo_magazine/handful))
return
diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm
index 1c69ae4681cf4..afec546fc066d 100644
--- a/code/modules/projectiles/gun_attachables.dm
+++ b/code/modules/projectiles/gun_attachables.dm
@@ -26,16 +26,12 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = null
item_state = null
- greyscale_config = null
- greyscale_colors = GUN_PALETTE_BLACK
- colorable_colors = GUN_PALETTE_LIST
-
///Determines the amount of pixels to move the icon state for the overlay. in the x direction
var/pixel_shift_x = 16
///Determines the amount of pixels to move the icon state for the overlay. in the y direction
var/pixel_shift_y = 16
- flags_atom = CONDUCT
+ atom_flags = CONDUCT
w_class = WEIGHT_CLASS_SMALL
force = 1
///ATTACHMENT_SLOT_MUZZLE, ATTACHMENT_SLOT_RAIL, ATTACHMENT_SLOT_UNDER, ATTACHMENT_SLOT_STOCK the particular 'slot' the attachment can attach to. must always be a singular slot.
@@ -120,7 +116,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
var/activation_sound = 'sound/machines/click.ogg'
///various yes no flags associated with attachments. See defines for these: [ATTACH_REMOVABLE]
- var/flags_attach_features = ATTACH_REMOVABLE
+ var/attach_features_flags = ATTACH_REMOVABLE
///only used by lace, denotes whether the lace is currently deployed
var/lace_deployed = FALSE
@@ -158,7 +154,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/Initialize(mapload)
. = ..()
- AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound)
+ AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, attach_features_flags, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound)
///Called when the attachment is attached to something. If it is a gun it will update the guns stats.
/obj/item/attachable/proc/on_attach(attaching_item, mob/user)
@@ -184,14 +180,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = variants_by_parent_type[selection]
update_icon()
- if(!greyscale_colors || !greyscale_config)
- return
- RegisterSignal(master_gun, COMSIG_ITEM_SECONDARY_COLOR, PROC_REF(handle_color))
-
-///Sends a list of available colored attachments to be colored when the parent is right clicked with paint.
-/obj/item/attachable/proc/handle_color(datum/source, mob/user, list/obj/item/secondaries)
- SIGNAL_HANDLER
- secondaries += src
///Called when the attachment is detached from something. If the thing is a gun, it returns its stats to what they were before being attached.
/obj/item/attachable/proc/on_detach(detaching_item, mob/user)
@@ -211,9 +199,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
master_gun = null
icon_state = initial(icon_state)
update_icon()
- if(!greyscale_config || !greyscale_colors)
- return
- UnregisterSignal(master_gun, COMSIG_ITEM_SECONDARY_COLOR)
///Handles the modifiers to the parent gun
/obj/item/attachable/proc/apply_modifiers(attaching_item, mob/user, attaching)
@@ -325,9 +310,10 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
master_gun.fire_sound = initial(master_gun.fire_sound)
/obj/item/attachable/ui_action_click(mob/living/user, datum/action/item_action/action, obj/item/weapon/gun/G)
- if(G == user.get_active_held_item() || G == user.get_inactive_held_item() || CHECK_BITFIELD(G.flags_item, IS_DEPLOYED))
- if(activate(user)) //success
+ if(G == user.get_active_held_item() || G == user.get_inactive_held_item() || CHECK_BITFIELD(G.item_flags, IS_DEPLOYED))
+ if(activate(user))
playsound(user, activation_sound, 15, 1)
+ return TRUE
else
to_chat(user, span_warning("[G] must be in our hands to do this."))
@@ -358,7 +344,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
damage_falloff_mod = 0.1
/obj/item/attachable/suppressor/unremovable
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/attachable/suppressor/unremovable/invisible
@@ -486,7 +472,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = "sniperbarrel"
desc = "A heavy barrel. CANNOT BE REMOVED."
slot = ATTACHMENT_SLOT_MUZZLE
- flags_attach_features = NONE
+ attach_features_flags = NONE
accuracy_mod = 0.15
scatter_mod = -3
@@ -495,7 +481,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = "t81barrel"
desc = "A heavy barrel. CANNOT BE REMOVED."
slot = ATTACHMENT_SLOT_UNDER
- flags_attach_features = NONE
+ attach_features_flags = NONE
pixel_shift_x = 7
pixel_shift_y = 14
accuracy_mod = 0
@@ -506,7 +492,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = "smartbarrel"
desc = "A heavy rotating barrel. CANNOT BE REMOVED."
slot = ATTACHMENT_SLOT_MUZZLE
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/attachable/focuslens
name = "M43 focused lens"
@@ -552,7 +538,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "The standard barrel on the SX-16. CANNOT BE REMOVED."
slot = ATTACHMENT_SLOT_MUZZLE
icon_state = "sx16barrel"
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/attachable/pulselens
name = "M43 pulse lens"
@@ -569,7 +555,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = "sg29barrel"
desc = "A heavy barrel. CANNOT BE REMOVED."
slot = ATTACHMENT_SLOT_MUZZLE
- flags_attach_features = NONE
+ attach_features_flags = NONE
///////////// Rail attachments ////////////////////////
@@ -580,7 +566,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
slot = ATTACHMENT_SLOT_RAIL
accuracy_mod = 0.15
accuracy_unwielded_mod = 0.1
- aim_mode_delay_mod = -0.5
+ aim_mode_movement_mult = -0.35
variants_by_parent_type = list(/obj/item/weapon/gun/rifle/som = "", /obj/item/weapon/gun/shotgun/som = "")
/obj/item/attachable/m16sight
@@ -600,7 +586,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
light_mod = 6
light_system = MOVABLE_LIGHT
slot = ATTACHMENT_SLOT_RAIL
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION
attachment_action_type = /datum/action/item_action/toggle
activation_sound = 'sound/items/flashlight.ogg'
@@ -643,6 +629,8 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/flashlight/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I,/obj/item/tool/screwdriver))
to_chat(user, span_notice("You modify the rail flashlight back into a normal flashlight."))
@@ -657,7 +645,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A simple flashlight used for mounting on a firearm. \nHas no drawbacks, but isn't particuraly useful outside of providing a light source."
icon_state = "uflashlight"
slot = ATTACHMENT_SLOT_UNDER
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION
@@ -684,7 +672,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
. = ..()
if(!master_gun)
return
- reequip_component = master_gun.AddComponent(/datum/component/reequip, list(SLOT_S_STORE, SLOT_BACK))
+ reequip_component = master_gun.AddComponent(/datum/component/reequip, list(SLOT_S_STORE, SLOT_BELT, SLOT_BACK))
/obj/item/attachable/magnetic_harness/on_detach(attaching_item, mob/user)
. = ..()
@@ -700,7 +688,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
aim_speed_mod = 0.5 //Extra slowdown when aiming
wield_delay_mod = 0.4 SECONDS
scoped_accuracy_mod = SCOPE_RAIL //accuracy mod of 0.4 when scoped
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION
attachment_action_type = /datum/action/item_action/toggle
scope_zoom_mod = TRUE // codex
accuracy_unwielded_mod = -0.05
@@ -753,7 +741,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = "t76scope"
/obj/item/attachable/scope/unremovable
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
/obj/item/attachable/scope/unremovable/flaregun
name = "long range ironsights"
@@ -797,16 +785,16 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
scope_delay = 2 SECONDS
zoom_tile_offset = 7
-/obj/item/attachable/scope/unremovable/tl102
+/obj/item/attachable/scope/unremovable/hsg_102
name = "HSG-102 smart sight"
- desc = "An unremovable smart sight built for use with the tl102, it does nearly all the aiming work for the gun's integrated IFF systems."
+ desc = "An unremovable smart sight built for use with the HSG-102, it does nearly all the aiming work for the gun's integrated IFF systems."
icon_state = "sniperscope_invisible"
zoom_viewsize = 0
zoom_tile_offset = 5
deployed_scope_rezoom = TRUE
//all mounted guns with a nest use this
-/obj/item/attachable/scope/unremovable/tl102/nest
+/obj/item/attachable/scope/unremovable/hsg_102/nest
scope_delay = 2 SECONDS
zoom_tile_offset = 7
zoom_viewsize = 5 //RU TGMC EDIT
@@ -818,11 +806,11 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
zoom(user)
return TRUE
- if(!(master_gun.flags_item & WIELDED) && !CHECK_BITFIELD(master_gun.flags_item, IS_DEPLOYED))
+ if(!(master_gun.item_flags & WIELDED) && !CHECK_BITFIELD(master_gun.item_flags, IS_DEPLOYED))
if(user)
to_chat(user, span_warning("You must hold [master_gun] with two hands to use [src]."))
return FALSE
- if(CHECK_BITFIELD(master_gun.flags_item, IS_DEPLOYED) && user.dir != master_gun.loc.dir)
+ if(CHECK_BITFIELD(master_gun.item_flags, IS_DEPLOYED) && user.dir != master_gun.loc.dir)
user.setDir(master_gun.loc.dir)
if(!do_after(user, scope_delay, NONE, src, BUSY_ICON_BAR))
return FALSE
@@ -842,7 +830,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
RegisterSignal(user, COMSIG_CARBON_SWAPPED_HANDS, PROC_REF(zoom_item_turnoff))
else
RegisterSignals(user, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_SWAPPED_HANDS), PROC_REF(zoom_item_turnoff))
- if(!CHECK_BITFIELD(master_gun.flags_item, IS_DEPLOYED))
+ if(!CHECK_BITFIELD(master_gun.item_flags, IS_DEPLOYED))
RegisterSignal(user, COMSIG_MOB_FACE_DIR, PROC_REF(change_zoom_offset))
RegisterSignals(master_gun, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_UNWIELD, COMSIG_ITEM_DROPPED), PROC_REF(zoom_item_turnoff))
master_gun.accuracy_mult += scoped_accuracy_mod
@@ -889,6 +877,11 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A marine standard mounted zoom sight scope made for the Terra Experimental laser sniper rifle otherwise known as TE-S abbreviated, allows zoom by activating the attachment."
icon_state = "tes"
+/obj/item/attachable/scope/unremovable/plasma_sniper_scope
+ name = "PL-02 sniper rifle rail scope"
+ desc = "A marine standard mounted zoom sight scope made for the PL-02 plasma sniper rifle, allows zoom by activating the attachment. Use F12 if your HUD doesn't come back."
+ icon_state = "plasma_scope"
+
/obj/item/attachable/scope/mini
name = "mini rail scope"
icon_state = "miniscope"
@@ -917,7 +910,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
scoped_accuracy_mod = SCOPE_RAIL_SNIPER
has_nightvision = TRUE
zoom_allow_movement = FALSE
- flags_attach_features = ATTACH_ACTIVATION|ATTACH_REMOVABLE
+ attach_features_flags = ATTACH_ACTIVATION|ATTACH_REMOVABLE
pixel_shift_x = 0
pixel_shift_y = 17
@@ -927,7 +920,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/scope/pmc
icon_state = "pmcscope"
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
/obj/item/attachable/scope/mini/dmr
name = "DMR-37 mini rail scope"
@@ -941,7 +934,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "default stock"
desc = "Default parent object, not meant for use."
slot = ATTACHMENT_SLOT_STOCK
- flags_attach_features = NONE //most stocks are not removable
+ attach_features_flags = NONE //most stocks are not removable
size_mod = 2
pixel_shift_x = 30
pixel_shift_y = 14
@@ -1003,8 +996,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "SG-29 stock"
desc = "A standard machinegun stock."
icon_state = "sg29stock"
- greyscale_config = /datum/greyscale_config/gun_attachment
- colorable_allowed = PRESET_COLORS_ALLOWED
pixel_shift_x = 32
pixel_shift_y = 13
@@ -1033,8 +1024,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "\improper SR-127 stock"
desc = "A irremovable SR-127 sniper rifle stock."
icon_state = "tl127stock"
- greyscale_config = /datum/greyscale_config/gun_attachment
- colorable_allowed = PRESET_COLORS_ALLOWED
pixel_shift_x = 32
pixel_shift_y = 13
@@ -1088,7 +1077,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
pixel_shift_x = 32
pixel_shift_y = 13
size_mod = 1
- flags_attach_features = ATTACH_REMOVABLE
+ attach_features_flags = ATTACH_REMOVABLE
wield_delay_mod = 0.2 SECONDS
accuracy_mod = 0.15
recoil_mod = -2
@@ -1098,8 +1087,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "MG-60 stock"
desc = "A irremovable MG-60 general purpose machinegun stock."
icon_state = "t60stock"
- greyscale_config = /datum/greyscale_config/gun_attachment
- colorable_allowed = PRESET_COLORS_ALLOWED
pixel_shift_x = 32
pixel_shift_y = 13
@@ -1164,7 +1151,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "T-76 magnum stock"
desc = "A R-76 magnum stock. Makes about all your handling better outside of making it harder to wield. Recommended to be kept on the R-76 at all times if you value your shoulder."
icon_state = "t76stock"
- flags_attach_features = ATTACH_REMOVABLE
+ attach_features_flags = ATTACH_REMOVABLE
melee_mod = 5
scatter_mod = -1
size_mod = 2
@@ -1179,8 +1166,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "vertical grip"
desc = "A custom-built improved foregrip for better accuracy, moderately faster aimed movement speed, less recoil, and less scatter when wielded especially during burst fire. \nHowever, it also increases weapon size, slightly increases wield delay and makes unwielded fire more cumbersome."
icon_state = "verticalgrip"
- greyscale_config = /datum/greyscale_config/gun_attachment
- colorable_allowed = PRESET_COLORS_ALLOWED
wield_delay_mod = 0.2 SECONDS
size_mod = 1
slot = ATTACHMENT_SLOT_UNDER
@@ -1199,8 +1184,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
name = "angled grip"
desc = "A custom-built improved foregrip for less recoil, and faster wielding time. \nHowever, it also increases weapon size, and slightly hinders unwielded firing."
icon_state = "angledgrip"
- greyscale_config = /datum/greyscale_config/gun_attachment
- colorable_allowed = PRESET_COLORS_ALLOWED
wield_delay_mod = -0.3 SECONDS
size_mod = 1
slot = ATTACHMENT_SLOT_UNDER
@@ -1240,7 +1223,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A simple lace to wrap around your wrist."
icon_state = "lace"
slot = ATTACHMENT_SLOT_MUZZLE //so you cannot have this and RC at once aka balance
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION
attachment_action_type = /datum/action/item_action/toggle
/obj/item/attachable/lace/activate(mob/living/user, turn_off)
@@ -1289,7 +1272,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A foldable stock. You shouldn't see this."
icon_state = ""
slot = ATTACHMENT_SLOT_STOCK
- flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_REMOVABLE|ATTACH_ACTIVATION
attachment_action_type = /datum/action/item_action/toggle
///How long it takes to fold or unfold
var/deploy_time
@@ -1316,9 +1299,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
icon_state = variants_by_parent_type[selection]
update_icon()
- if(!greyscale_config || !greyscale_colors)
- return
- RegisterSignal(master_gun, COMSIG_ITEM_SECONDARY_COLOR, PROC_REF(handle_color))
/obj/item/attachable/foldable/on_detach(detaching_item, mob/user)
if(!isgun(detaching_item))
@@ -1336,9 +1316,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
master_gun = null
icon_state = initial(icon_state)
update_icon()
- if(!greyscale_config || !greyscale_colors)
- return
- UnregisterSignal(master_gun, COMSIG_ITEM_SECONDARY_COLOR)
/obj/item/attachable/foldable/activate(mob/living/user, turn_off)
if(user && deploy_time && !do_after(user, deploy_time, NONE, src, BUSY_ICON_BAR))
@@ -1368,7 +1345,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A foldable wire stock for a Skorpion submachinegun"
icon = 'icons/Marine/attachments_64.dmi'
icon_state = "skorpion"
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
pixel_shift_x = 0
pixel_shift_y = 0
size_mod = 2
@@ -1382,7 +1359,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/foldable/t19stock
name = "\improper MP-19 machinepistol stock"
desc = "A submachinegun stock distributed in small numbers to TGMC forces. Compatible with the MP-19, this stock reduces recoil and improves accuracy, but at a reduction to handling and agility. Seemingly a bit more effective in a brawl."
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
wield_delay_mod = 0.1 SECONDS
melee_mod = 5
size_mod = 1
@@ -1396,7 +1373,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/foldable/som_carbine
name = "\improper V-34 carbine stock"
desc = "A side folding stock built into the V-34 carbine. The gun is designed to be fired with the stock deployed, but can be done without, with some difficulty."
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
wield_delay_mod = 0.1 SECONDS
melee_mod = 5
size_mod = 1
@@ -1409,7 +1386,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/foldable/icc_machinepistol
name = "\improper PL-38 machinepistol stock"
desc = "A submachinegun stock found on ICC subguns, this stock reduces recoil and improves accuracy, but at a reduction to handling and agility. Seemingly a bit more effective in a brawl."
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
icon = 'icons/Marine/attachments_64.dmi'
wield_delay_mod = 0.1 SECONDS
melee_mod = 5
@@ -1426,9 +1403,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
desc = "A non-standard heavy stock for the SH-35 shotgun. Less quick and more cumbersome than the standard issue stakeout, but reduces recoil and improves accuracy. Allegedly makes a pretty good club in a fight too."
icon = 'icons/Marine/attachments_64.dmi'
icon_state = "t35stock"
- greyscale_config = /datum/greyscale_config/gun_attachment_64
- colorable_allowed = PRESET_COLORS_ALLOWED
- flags_attach_features = ATTACH_ACTIVATION
+ attach_features_flags = ATTACH_ACTIVATION
wield_delay_mod = 0.2 SECONDS
accuracy_mod = 0.15
recoil_mod = -3
@@ -1448,7 +1423,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
aim_mode_delay_mod = -0.5
/obj/item/attachable/foldable/bipod/activate(mob/living/user, turn_off)
- if(folded && !(master_gun.flags_item & WIELDED)) //no one handed bipod use
+ if(folded && !(master_gun.item_flags & WIELDED)) //no one handed bipod use
if(user)
balloon_alert(user, "Unwielded")
return
@@ -1499,13 +1474,13 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/buildasentry/on_attach(attaching_item, mob/user)
. = ..()
- ENABLE_BITFIELD(master_gun.flags_item, IS_DEPLOYABLE)
+ ENABLE_BITFIELD(master_gun.item_flags, IS_DEPLOYABLE)
master_gun.deployable_item = /obj/machinery/deployable/mounted/sentry/buildasentry
master_gun.ignored_terrains = list(
/obj/machinery/deployable/mounted,
/obj/machinery/miner,
)
- if(master_gun.ammo_datum_type && CHECK_BITFIELD(initial(master_gun.ammo_datum_type.flags_ammo_behavior), AMMO_ENERGY) || istype(master_gun, /obj/item/weapon/gun/energy)) //If the guns ammo is energy, the sentry will shoot at things past windows.
+ if(master_gun.ammo_datum_type && CHECK_BITFIELD(initial(master_gun.ammo_datum_type.ammo_behavior_flags), AMMO_ENERGY) || istype(master_gun, /obj/item/weapon/gun/energy)) //If the guns ammo is energy, the sentry will shoot at things past windows.
master_gun.ignored_terrains += list(
/obj/structure/window,
/obj/structure/window/reinforced,
@@ -1522,171 +1497,12 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
/obj/item/attachable/buildasentry/on_detach(detaching_item, mob/user)
. = ..()
var/obj/item/weapon/gun/detaching_gun = detaching_item
- DISABLE_BITFIELD(detaching_gun.flags_item, IS_DEPLOYABLE)
+ DISABLE_BITFIELD(detaching_gun.item_flags, IS_DEPLOYABLE)
qdel(detaching_gun.GetComponent(/datum/component/deployable_item))
detaching_gun.ignored_terrains = null
detaching_gun.deployable_item = null
detaching_gun.turret_flags &= ~(TURRET_HAS_CAMERA|TURRET_SAFETY|TURRET_ALERTS)
-
-/obj/item/attachable/shoulder_mount
- name = "experimental shoulder attachment point"
- desc = "A brand new advance in combat technology. This device, once attached to a firearm, will allow the firearm to be mounted onto any piece of modular armor. Once attached to the armor and activated, the gun will fire when the user chooses.\nOnce attached to the armor, right clicking the armor with an empty hand will select what click will fire the armor (middle, right, left). Right clicking with ammunition will reload the gun. Using the Unique Action keybind will perform the weapon's unique action only when the gun is active."
- icon = 'icons/mob/modular/shoulder_gun.dmi'
- icon_state = "shoulder_gun"
- slot = ATTACHMENT_SLOT_RAIL
- pixel_shift_x = 13
- ///What click the gun will fire on.
- var/fire_mode = "right"
- ///Blacklist of item types not allowed to be in the users hand to fire the gun.
- var/list/in_hand_items_blacklist = list(
- /obj/item/weapon/gun,
- /obj/item/weapon/shield,
- )
-
-/obj/item/attachable/shoulder_mount/on_attach(attaching_item, mob/user)
- . = ..()
- var/obj/item/weapon/gun/attaching_gun = attaching_item
- ENABLE_BITFIELD(flags_attach_features, ATTACH_BYPASS_ALLOWED_LIST|ATTACH_APPLY_ON_MOB)
- attaching_gun.AddElement(/datum/element/attachment, ATTACHMENT_SLOT_MODULE, icon, null, null, null, null, 0, 0, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound, attachment_layer = COLLAR_LAYER)
- RegisterSignal(attaching_gun, COMSIG_ATTACHMENT_ATTACHED, PROC_REF(handle_armor_attach))
- RegisterSignal(attaching_gun, COMSIG_ATTACHMENT_DETACHED, PROC_REF(handle_armor_detach))
-
-/obj/item/attachable/shoulder_mount/on_detach(detaching_item, mob/user)
- var/obj/item/weapon/gun/detaching_gun = detaching_item
- detaching_gun.RemoveElement(/datum/element/attachment, ATTACHMENT_SLOT_MODULE, icon, null, null, null, null, 0, 0, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound, attachment_layer = COLLAR_LAYER)
- DISABLE_BITFIELD(flags_attach_features, ATTACH_BYPASS_ALLOWED_LIST|ATTACH_APPLY_ON_MOB)
- UnregisterSignal(detaching_gun, list(COMSIG_ATTACHMENT_ATTACHED, COMSIG_ATTACHMENT_DETACHED))
- return ..()
-
-/obj/item/attachable/shoulder_mount/ui_action_click(mob/living/user, datum/action/item_action/action, obj/item/weapon/gun/G)
- if(!istype(master_gun.loc, /obj/item/clothing/suit/modular) || master_gun.loc.loc != user)
- return
- activate(user)
-
-/obj/item/attachable/shoulder_mount/activate(mob/user, turn_off)
- . = ..()
- if(CHECK_BITFIELD(master_gun.flags_item, IS_DEPLOYED))
- DISABLE_BITFIELD(master_gun.flags_item, IS_DEPLOYED)
- UnregisterSignal(user, COMSIG_MOB_MOUSEDOWN)
- master_gun.set_gun_user(null)
- . = FALSE
- else if(!turn_off)
- ENABLE_BITFIELD(master_gun.flags_item, IS_DEPLOYED)
- update_icon()
- master_gun.set_gun_user(user)
- RegisterSignal(user, COMSIG_MOB_MOUSEDOWN, PROC_REF(handle_firing))
- master_gun.RegisterSignal(user, COMSIG_MOB_MOUSEDRAG, TYPE_PROC_REF(/obj/item/weapon/gun, change_target))
- . = TRUE
- for(var/datum/action/item_action/toggle/action_to_update AS in actions)
- action_to_update.set_toggle(.)
- action_to_update.update_button_icon()
-
-///Handles the gun attaching to the armor.
-/obj/item/attachable/shoulder_mount/proc/handle_armor_attach(datum/source, attaching_item, mob/user)
- SIGNAL_HANDLER
- if(!istype(attaching_item, /obj/item/clothing/suit/modular))
- return
- master_gun.set_gun_user(null)
- RegisterSignal(attaching_item, COMSIG_ITEM_EQUIPPED, PROC_REF(handle_activations))
- RegisterSignal(attaching_item, COMSIG_ATOM_ATTACK_HAND_ALTERNATE, PROC_REF(switch_mode))
- RegisterSignal(attaching_item, COMSIG_ATOM_ATTACKBY_ALTERNATE, PROC_REF(reload_gun))
- RegisterSignal(master_gun, COMSIG_MOB_GUN_FIRED, PROC_REF(after_fire))
- master_gun.base_gun_icon = master_gun.placed_overlay_iconstate
- master_gun.update_icon()
-
-///Handles the gun detaching from the armor.
-/obj/item/attachable/shoulder_mount/proc/handle_armor_detach(datum/source, detaching_item, mob/user)
- SIGNAL_HANDLER
- if(!istype(detaching_item, /obj/item/clothing/suit/modular))
- return
- for(var/datum/action/action_to_delete AS in actions)
- if(action_to_delete.target != src)
- continue
- QDEL_NULL(action_to_delete)
- break
- update_icon(user)
- master_gun.base_gun_icon = initial(master_gun.icon_state)
- master_gun.update_icon()
- UnregisterSignal(detaching_item, list(COMSIG_ITEM_EQUIPPED, COMSIG_ATOM_ATTACK_HAND_ALTERNATE, COMSIG_ATOM_ATTACKBY_ALTERNATE))
- UnregisterSignal(master_gun, COMSIG_MOB_GUN_FIRED)
- UnregisterSignal(user, COMSIG_MOB_MOUSEDOWN)
-
-///Sets up the action.
-/obj/item/attachable/shoulder_mount/proc/handle_activations(datum/source, mob/equipper, slot)
- if(!isliving(equipper))
- return
- if(slot != SLOT_WEAR_SUIT)
- LAZYREMOVE(actions_types, /datum/action/item_action/toggle)
- var/datum/action/item_action/toggle/old_action = locate(/datum/action/item_action/toggle) in actions
- if(!old_action)
- return
- old_action.remove_action(equipper)
- actions = null
- else
- LAZYADD(actions_types, /datum/action/item_action/toggle)
- var/datum/action/item_action/toggle/new_action = new(src)
- new_action.give_action(equipper)
-
-///Performs the firing.
-/obj/item/attachable/shoulder_mount/proc/handle_firing(datum/source, atom/object, turf/location, control, params)
- SIGNAL_HANDLER
- var/list/modifiers = params2list(params)
- if(!modifiers[fire_mode])
- return
- if(!istype(master_gun.loc, /obj/item/clothing/suit/modular) || master_gun.loc.loc != source)
- return
- if(source.Adjacent(object))
- return
- var/mob/living/user = master_gun.gun_user
- if(user.incapacitated() || user.lying_angle || LAZYACCESS(user.do_actions, src) || !user.dextrous || (!CHECK_BITFIELD(master_gun.flags_gun_features, GUN_ALLOW_SYNTHETIC) && !CONFIG_GET(flag/allow_synthetic_gun_use) && issynth(user)))
- return
- var/active_hand = user.get_active_held_item()
- var/inactive_hand = user.get_inactive_held_item()
- for(var/item_blacklisted in in_hand_items_blacklist)
- if(!istype(active_hand, item_blacklisted) && !istype(inactive_hand, item_blacklisted))
- continue
- to_chat(user, span_warning("[src] beeps. Guns or shields in your hands are interfering with its targetting. Aborting."))
- return
- master_gun.start_fire(source, object, location, control, null, TRUE)
-
-///Switches click fire modes.
-/obj/item/attachable/shoulder_mount/proc/switch_mode(datum/source, mob/living/user)
- SIGNAL_HANDLER
- switch(fire_mode)
- if("right")
- fire_mode = "middle"
- to_chat(user, span_notice("[master_gun] will now fire on a 'middle click'."))
- if("middle")
- fire_mode = "left"
- to_chat(user, span_notice("[master_gun] will now fire on a 'left click'."))
- if("left")
- fire_mode = "right"
- to_chat(user, span_notice("[master_gun] will now fire on a 'right click'."))
-
-///Reloads the gun
-/obj/item/attachable/shoulder_mount/proc/reload_gun(datum/source, obj/item/attacking_item, mob/living/user)
- SIGNAL_HANDLER
- INVOKE_ASYNC(master_gun, TYPE_PROC_REF(/obj/item/weapon/gun, reload), attacking_item, user)
-
-///Performs the unique action after firing and checks to see if the user is still able to fire.
-/obj/item/attachable/shoulder_mount/proc/after_fire(datum/source, atom/target, obj/item/weapon/gun/fired_gun)
- SIGNAL_HANDLER
- if(CHECK_BITFIELD(master_gun.reciever_flags, AMMO_RECIEVER_REQUIRES_UNIQUE_ACTION))
- INVOKE_ASYNC(master_gun, TYPE_PROC_REF(/obj/item/weapon/gun, do_unique_action), master_gun.gun_user)
- var/mob/living/user = master_gun.gun_user
- var/active_hand = user.get_active_held_item()
- var/inactive_hand = user.get_inactive_held_item()
- for(var/item_blacklisted in in_hand_items_blacklist)
- if(!istype(active_hand, item_blacklisted) && !istype(inactive_hand, item_blacklisted))
- continue
- to_chat(user, span_warning("[src] beeps. Guns or shields in your hands are interfering with its targetting. Stopping fire."))
- master_gun.stop_fire()
- return
- if(!user.incapacitated() && !user.lying_angle && !LAZYACCESS(user.do_actions, src) && user.dextrous && (CHECK_BITFIELD(master_gun.flags_gun_features, GUN_ALLOW_SYNTHETIC) || CONFIG_GET(flag/allow_synthetic_gun_use) || !issynth(user)))
- return
- master_gun.stop_fire()
-
/obj/item/attachable/flamer_nozzle
name = "standard flamer nozzle"
desc = "The standard flamer nozzle. This one fires a stream of fire for direct and accurate flames. Though not as area filling as its counterpart, this one excels at directed frontline combat."
@@ -1695,7 +1511,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
attach_delay = 2 SECONDS
detach_delay = 2 SECONDS
- ///This is pulled when the parent flamer fires, it determins how the parent flamers fire stream acts.
+ ///This is pulled when the parent flamer fires, it determines how the parent flamers fire stream acts.
var/stream_type = FLAMER_STREAM_STRAIGHT
///Modifier for burn level of attached flamer. Percentage based.
@@ -1728,7 +1544,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
flamer.mob_flame_damage_mod /= mob_flame_damage_mod
/obj/item/attachable/flamer_nozzle/unremovable
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/attachable/flamer_nozzle/unremovable/invisible
icon_state = null
@@ -1789,8 +1605,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
attached_to:gunattachment = src
activate(user)
new_action.set_toggle(TRUE)
- new_action.update_button_icon()
- update_icon(user)
+ update_icon()
RegisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY, TYPE_PROC_REF(/obj/item/weapon/gun, drop_connected_mag))
///This is called when an attachment gun (src) detaches from a gun.
@@ -1809,7 +1624,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
UnregisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY)
master_gun = null
attached_to:gunattachment = null
- update_icon(user)
+ update_icon()
///This activates the weapon for use.
/obj/item/weapon/gun/proc/activate(mob/user)
@@ -1825,11 +1640,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime.
set_gun_user(null)
set_gun_user(master_gun.gun_user)
to_chat(user, span_notice("You start using [src]."))
- for(var/datum/action/item_action/toggle/action AS in master_gun.actions)
- if(action.target != src )
- continue
- action.set_toggle(master_gun.active_attachable == src)
- action.update_button_icon()
return TRUE
///Called when the attachment is trying to be attached. If the attachment is allowed to go through, return TRUE.
diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm
index 55ed0b9ce8854..32d4500c0d15b 100644
--- a/code/modules/projectiles/gun_helpers.dm
+++ b/code/modules/projectiles/gun_helpers.dm
@@ -26,6 +26,8 @@
/obj/item/weapon/gun/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(user.get_inactive_held_item() != src || istype(I, /obj/item/attachable) || isgun(I))
return
reload(I, user)
@@ -74,16 +76,16 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
/obj/item/weapon/gun/proc/do_wield(mob/user, wdelay) //*shrugs*
if(wield_time > 0 && !do_after(user, wdelay, IGNORE_LOC_CHANGE, user, BUSY_ICON_HOSTILE, null, PROGRESS_CLOCK, CALLBACK(src, PROC_REF(is_wielded))))
return FALSE
- flags_item |= FULLY_WIELDED
+ item_flags |= FULLY_WIELDED
setup_bullet_accuracy()
return TRUE
/obj/item/weapon/gun/attack_self(mob/user)
. = ..()
//There are only two ways to interact here.
- if(!CHECK_BITFIELD(flags_item, TWOHANDED))
+ if(!(item_flags & TWOHANDED))
return
- if(flags_item & WIELDED)
+ if(item_flags & WIELDED)
unwield(user)//Trying to unwield it
return
wield(user)//Trying to wield it
@@ -125,7 +127,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
if(istype(new_magazine.loc, /obj/item/storage))
var/obj/item/storage/S = new_magazine.loc
S.remove_from_storage(new_magazine, get_turf(user), user)
- if(!CHECK_BITFIELD(get_flags_magazine_features(new_magazine), MAGAZINE_WORN))
+ if(!CHECK_BITFIELD(get_magazine_features_flags(new_magazine), MAGAZINE_WORN))
user.put_in_any_hand_if_possible(new_magazine)
reload(new_magazine, user)
@@ -154,7 +156,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
return 1
/obj/item/weapon/gun/proc/is_wielded() //temporary proc until we get traits going
- return CHECK_BITFIELD(flags_item, WIELDED)
+ return CHECK_BITFIELD(item_flags, WIELDED)
///Checks the gun to see if it has an attachment of type attachment_type
/obj/item/weapon/gun/proc/has_attachment(attachment_type)
@@ -220,12 +222,9 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
var/datum/action/item_action/firemode/firemode_action = action
if(!istype(firemode_action))
if(master_gun)
- activate(user)
- return
+ return activate(user)
return ..()
- do_toggle_firemode()
- user.update_action_buttons()
-
+ return do_toggle_firemode()
/mob/living/carbon/human/verb/toggle_autofire()
set category = "Weapons"
@@ -334,11 +333,10 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
if(ishuman(source))
to_chat(source, span_notice("[icon2html(src, source)] You switch to [gun_firemode]."))
- if(source == gun_user)
- gun_user.update_action_buttons()
playsound(src, 'sound/weapons/guns/interact/selector.ogg', 15, 1)
SEND_SIGNAL(src, COMSIG_GUN_FIRE_MODE_TOGGLE, gun_firemode)
setup_bullet_accuracy()
+ return TRUE
/obj/item/weapon/gun/proc/add_firemode(added_firemode, mob/user)
@@ -354,7 +352,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
var/datum/action/new_action = new /datum/action/item_action/firemode(src)
if(user)
var/mob/living/living_user = user
- if((src == living_user.l_hand || src == living_user.r_hand) && !CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if((src == living_user.l_hand || src == living_user.r_hand) && !CHECK_BITFIELD(item_flags, IS_DEPLOYED))
new_action.give_action(living_user)
else //The action should already be there by now.
return
@@ -369,7 +367,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
var/datum/action/old_action = locate(/datum/action/item_action/firemode) in actions
if(user)
var/mob/living/living_user = user
- if((src == living_user.l_hand || src == living_user.r_hand) && !CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if((src == living_user.l_hand || src == living_user.r_hand) && !CHECK_BITFIELD(item_flags, IS_DEPLOYED))
old_action.remove_action(living_user)
qdel(old_action)
@@ -507,7 +505,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
var/list/usable_attachments = list()
// rail attachment use the button to toggle flashlight instead.
- // if(rail && (rail.flags_attach_features & ATTACH_ACTIVATION) )
+ // if(rail && (rail.attach_features_flags & ATTACH_ACTIVATION) )
// usable_attachments += rail
if(!length(attachments_by_slot))
balloon_alert(usr, "No usable attachments")
@@ -518,7 +516,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
if(!attachment)
continue
var/obj/item/attachable/attachable = attachment
- if(attachable.flags_attach_features & ATTACH_ACTIVATION)
+ if(attachable.attach_features_flags & ATTACH_ACTIVATION)
usable_attachments += attachment
if(!length(usable_attachments)) //No usable attachments.
@@ -577,7 +575,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
balloon_alert(usr, "Automatic unloading [CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_AUTO_EJECT) ? "enabled" : "disabled"].")
/obj/item/weapon/gun/item_action_slot_check(mob/user, slot)
- if(slot != SLOT_L_HAND && slot != SLOT_R_HAND && !CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(slot != SLOT_L_HAND && slot != SLOT_R_HAND && !CHECK_BITFIELD(item_flags, IS_DEPLOYED))
return FALSE
return TRUE
@@ -634,7 +632,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
/obj/item/weapon/gun/proc/toggle_auto_aim_mode(mob/living/carbon/human/user) //determines whether toggle_aim_mode activates at the end of gun/wield proc
- if((flags_item & FULLY_WIELDED) || (flags_item & IS_DEPLOYED)) //if gun is wielded it toggles aim mode directly instead
+ if((item_flags & FULLY_WIELDED) || (item_flags & IS_DEPLOYED)) //if gun is wielded it toggles aim mode directly instead
toggle_aim_mode(user)
return
@@ -661,7 +659,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
gunattachment.modify_auto_burst_delay(-aim_fire_delay)
to_chat(user, span_notice("You cease aiming."))
return
- if(!(flags_item & WIELDED) && !(flags_item & IS_DEPLOYED))
+ if(!(item_flags & WIELDED) && !(item_flags & IS_DEPLOYED))
to_chat(user, span_notice("You need to wield your gun before aiming."))
return
if(!user.wear_id)
@@ -672,10 +670,10 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
if(user.do_actions)
return
if(!user.marksman_aura)
- if(!do_after(user, aim_time, (flags_item & IS_DEPLOYED) ? NONE : IGNORE_USER_LOC_CHANGE, (flags_item & IS_DEPLOYED) ? loc : src, BUSY_ICON_BAR))
+ if(!do_after(user, aim_time, (item_flags & IS_DEPLOYED) ? NONE : IGNORE_USER_LOC_CHANGE, (item_flags & IS_DEPLOYED) ? loc : src, BUSY_ICON_BAR))
to_chat(user, span_warning("Your concentration is interrupted!"))
return
- if(!(flags_item & WIELDED) && !(flags_item & IS_DEPLOYED))
+ if(!(item_flags & WIELDED) && !(item_flags & IS_DEPLOYED))
to_chat(user, span_notice("You need to wield your gun before aiming."))
return
user.overlays += aim_mode_visual
@@ -693,7 +691,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
/// Signal handler to activate the rail attachement of that gun if it's in our active hand
/obj/item/weapon/gun/proc/activate_rail_attachment()
SIGNAL_HANDLER
- if(gun_user?.get_active_held_item() != src && !(flags_item & IS_DEPLOYED))
+ if(gun_user?.get_active_held_item() != src && !(item_flags & IS_DEPLOYED))
return
activate_attachment(ATTACHMENT_SLOT_RAIL, gun_user)
return COMSIG_KB_ACTIVATED
@@ -701,7 +699,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
/// Signal handler to activate the underrail attachement of that gun if it's in our active hand
/obj/item/weapon/gun/proc/activate_underrail_attachment()
SIGNAL_HANDLER
- if(gun_user?.get_active_held_item() != src && !(flags_item & IS_DEPLOYED))
+ if(gun_user?.get_active_held_item() != src && !(item_flags & IS_DEPLOYED))
return
activate_attachment(ATTACHMENT_SLOT_UNDER, gun_user)
return COMSIG_KB_ACTIVATED
diff --git a/code/modules/projectiles/gun_system.dm b/code/modules/projectiles/gun_system.dm
index d7268d4bb8c52..393b33f9081a3 100644
--- a/code/modules/projectiles/gun_system.dm
+++ b/code/modules/projectiles/gun_system.dm
@@ -17,30 +17,26 @@
/obj/item/weapon/gun
name = "Guns"
desc = "Its a gun. It's pretty terrible, though."
- icon = 'icons/obj/items/gun.dmi'
icon_state = ""
item_state = "gun"
item_state_worn = TRUE
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_1.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_1.dmi',
- )
+ slot_l_hand_str = 'icons/mob/inhands/guns/rifles_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/rifles_right_1.dmi',
+ )
max_integrity = 250
w_class = WEIGHT_CLASS_NORMAL
throwforce = 5
throw_speed = 4
throw_range = 5
force = 5
- flags_atom = CONDUCT
- flags_item = TWOHANDED
+ atom_flags = CONDUCT
+ item_flags = TWOHANDED
light_system = MOVABLE_LIGHT
light_range = 0
light_color = COLOR_WHITE
appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE
- greyscale_colors = GUN_PALETTE_BLACK
- colorable_colors = GUN_PALETTE_LIST
-
/*
* Muzzle Vars
*/
@@ -155,7 +151,7 @@
*/
///Innate carateristics of that gun
- var/flags_gun_features = GUN_CAN_POINTBLANK
+ var/gun_features_flags = GUN_CAN_POINTBLANK
///Current selected firemode of the gun.
var/gun_firemode = GUN_FIREMODE_SEMIAUTO
///List of allowed firemodes.
@@ -178,10 +174,8 @@
var/shots_fired = 0
///If this gun is in inactive hands and shooting in akimbo
var/dual_wield = FALSE
- ///determines upper accuracy modifier in akimbo
- var/upper_akimbo_accuracy = 2
- ///determines lower accuracy modifier in akimbo
- var/lower_akimbo_accuracy = 1
+ ///mult to scatter when firing akimbo
+ var/akimbo_scatter_mod = 3
///If fire delay is 1 second, and akimbo_additional_delay is 0.5, then you'll have to wait 1 second * 0.5 to fire the second gun
var/akimbo_additional_delay = 0.5
///Delay for the gun winding up before firing.
@@ -238,7 +232,7 @@
///Multiplier. Increased and decreased through attachments. Multiplies the accuracy/scatter penalty of the projectile when firing while moving.
var/movement_acc_penalty_mult = 5
///For regular shots, how long to wait before firing again.
- var/fire_delay = 6
+ var/fire_delay = 0.6 SECONDS
///Modifies the speed of projectiles fired.
var/shell_speed_mod = 0
///Modifies projectile damage by a % when a marine gets passed, but not hit
@@ -264,7 +258,7 @@
///Slowdown for wielding
var/aim_slowdown = 0
///How long between wielding and firing in tenths of seconds
- var/wield_delay = 0.4 SECONDS
+ var/wield_delay = 0.6 SECONDS
///Extra wield delay for untrained operators
var/wield_penalty = 0.2 SECONDS
///Storing value for above
@@ -288,10 +282,27 @@
var/gun_accuracy_mod = 0
///The actual scatter value of the fired projectile
var/gun_scatter = 0
+
/*
- * extra icon and item states or overlays
+ * HEAT MECHANIC VARS
+ *
*/
+ /// heat on this gun. at over 100 heat stops you from firing and goes on cooldown
+ var/heat_amount = 0
+ ///heat that we add every successful fire()
+ var/heat_per_fire = 0
+ ///heat reduction per second
+ var/cool_amount = 5
+ ///tracks overheat timer ref
+ var/overheat_timer
+ ///multiplier on cool amount to determine overheat time
+ var/overheat_multiplier = 1.1
+ ///image we create to keep track of heat
+ var/image/heat_bar/heat_meter
+/*
+ * extra icon and item states or overlays
+*/
///Whether the gun has ammo level overlays for its icon, mainly for eguns
var/ammo_level_icon
///Whether the icon_state overlay is offset in the x axis
@@ -299,13 +310,12 @@
///Whether the icon_state overlay is offset in the Y axis
var/icon_overlay_y_offset = 0
+
/*
*
* ATTACHMENT VARS
*
*/
-
-
///List of offsets to make attachment overlays not look wonky.
var/list/attachable_offset = null
///List of allowed attachments, IT MUST INCLUDE THE STARTING ATTACHMENT TYPES OR THEY WILL NOT ATTACH.
@@ -339,7 +349,7 @@
///Pixel shift on the Y Axis for the attached overlay.
var/pixel_shift_y = 16
///Flags for attachment functions.
- var/flags_attach_features = ATTACH_REMOVABLE
+ var/attach_features_flags = ATTACH_REMOVABLE
///Time it takes to attach src to a master gun.
var/attach_delay = 0 SECONDS
///Time it takes to detach src to a master gun.
@@ -391,8 +401,8 @@
setup_firemodes()
AddComponent(/datum/component/automatedfire/autofire, fire_delay, autoburst_delay, burst_delay, burst_amount, gun_firemode, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(Fire))) //This should go after handle_starting_attachment() and setup_firemodes() to get the proper values set.
AddComponent(/datum/component/attachment_handler, attachments_by_slot, attachable_allowed, attachable_offset, starting_attachment_types, null, CALLBACK(src, PROC_REF(on_attachment_attach)), CALLBACK(src, PROC_REF(on_attachment_detach)), attachment_overlays)
- if(CHECK_BITFIELD(flags_gun_features, GUN_IS_ATTACHMENT))
- AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, SKILL_FIREARMS, SKILL_FIREARMS_DEFAULT, 'sound/machines/click.ogg')
+ if(CHECK_BITFIELD(gun_features_flags, GUN_IS_ATTACHMENT))
+ AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, attach_features_flags, attach_delay, detach_delay, SKILL_FIREARMS, SKILL_FIREARMS_DEFAULT, 'sound/machines/click.ogg')
muzzle_flash = new(src, muzzleflash_iconstate)
@@ -472,8 +482,11 @@
COMSIG_MOB_SHOCK_STAGE_CHANGED,
COMSIG_HUMAN_MARKSMAN_AURA_CHANGED))
gun_user.client?.mouse_pointer_icon = initial(gun_user.client.mouse_pointer_icon)
- SEND_SIGNAL(gun_user, COMSIG_GUN_USER_UNSET)
- gun_user.hud_used.remove_ammo_hud(src)
+ SEND_SIGNAL(gun_user, COMSIG_GUN_USER_UNSET, src)
+ gun_user.hud_used?.remove_ammo_hud(src)
+ if(heat_meter && gun_user.client)
+ gun_user.client.images -= heat_meter
+ heat_meter = null
gun_user = null
if(!user)
@@ -483,8 +496,12 @@
return
gun_user = user
SEND_SIGNAL(gun_user, COMSIG_GUN_USER_SET, src)
- if(flags_gun_features & GUN_AMMO_COUNTER)
- gun_user.hud_used.add_ammo_hud(src, get_ammo_list(), get_display_ammo_count())
+ if(gun_features_flags & GUN_AMMO_COUNTER)
+ gun_user.hud_used?.add_ammo_hud(src, get_ammo_list(), get_display_ammo_count())
+ if(heat_per_fire)
+ heat_meter = new(loc=gun_user)
+ heat_meter.animate_change(heat_amount/100, 5)
+ gun_user.client.images += heat_meter
if(master_gun)
return
setup_bullet_accuracy()
@@ -493,13 +510,14 @@
COMSIG_MOB_SKILLS_CHANGED,
COMSIG_MOB_SHOCK_STAGE_CHANGED,
COMSIG_HUMAN_MARKSMAN_AURA_CHANGED), PROC_REF(setup_bullet_accuracy))
- if(!CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(!CHECK_BITFIELD(item_flags, IS_DEPLOYED))
RegisterSignal(gun_user, COMSIG_MOB_MOUSEDOWN, PROC_REF(start_fire))
RegisterSignal(gun_user, COMSIG_MOB_MOUSEDRAG, PROC_REF(change_target))
else
RegisterSignal(gun_user, COMSIG_KB_UNIQUEACTION, PROC_REF(unique_action))
RegisterSignal(gun_user, COMSIG_QDELETING, PROC_REF(clean_gun_user))
- RegisterSignals(gun_user, list(COMSIG_MOB_MOUSEUP, COMSIG_ITEM_ZOOM, COMSIG_ITEM_UNZOOM), PROC_REF(stop_fire))
+ RegisterSignals(gun_user, list(COMSIG_MOB_MOUSEUP, COMSIG_ITEM_ZOOM), PROC_REF(stop_fire))
+ RegisterSignal(gun_user, COMSIG_ITEM_UNZOOM, PROC_REF(on_unzoom))
RegisterSignal(gun_user, COMSIG_KB_RAILATTACHMENT, PROC_REF(activate_rail_attachment))
RegisterSignal(gun_user, COMSIG_KB_UNDERRAILATTACHMENT, PROC_REF(activate_underrail_attachment))
RegisterSignal(gun_user, COMSIG_KB_UNLOADGUN, PROC_REF(unload_gun))
@@ -513,7 +531,7 @@
SIGNAL_HANDLER
set_gun_user(null)
-/obj/item/weapon/gun/update_icon(mob/user)
+/obj/item/weapon/gun/update_icon()
. = ..()
for(var/datum/action/action AS in actions)
@@ -528,23 +546,15 @@
/obj/item/weapon/gun/update_icon_state()
. = ..()
if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_TOGGLES_OPEN) && !CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_CLOSED))
- icon_state = !greyscale_config ? base_gun_icon + "_o" : GUN_ICONSTATE_OPEN
+ icon_state = base_gun_icon + "_o"
else if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_REQUIRES_UNIQUE_ACTION) && !in_chamber && length(chamber_items))
- icon_state = !greyscale_config ? base_gun_icon + "_u" : GUN_ICONSTATE_UNRACKED
+ icon_state = base_gun_icon + "_u"
else if((!length(chamber_items) && max_chamber_items) || (!rounds && !max_chamber_items))
- icon_state = !greyscale_config ? base_gun_icon + "_e" : GUN_ICONSTATE_UNLOADED
+ icon_state = base_gun_icon + "_e"
else if(current_chamber_position <= length(chamber_items) && chamber_items[current_chamber_position] && chamber_items[current_chamber_position].loc != src)
icon_state = base_gun_icon + "_l"
else
- icon_state = !greyscale_config ? base_gun_icon : GUN_ICONSTATE_LOADED
-
-/obj/item/weapon/gun/color_item(obj/item/facepaint/paint, mob/user)
- . = ..()
- if(!ishuman(user))
- return
- var/mob/living/carbon/human/human = user
- human.regenerate_icons()
-
+ icon_state = base_gun_icon
//manages the overlays for the gun - separate from attachment overlays
/obj/item/weapon/gun/update_overlays()
@@ -569,13 +579,13 @@
/obj/item/weapon/gun/update_item_state()
var/current_state = item_state
- if(flags_gun_features & GUN_SHOWS_AMMO_REMAINING) //shows different ammo levels
+ if(gun_features_flags & GUN_SHOWS_AMMO_REMAINING) //shows different ammo levels
var/remaining_rounds = (rounds <= 0) ? 0 : CEILING((rounds / max((length(chamber_items) ? max_rounds : max_shells), 1)) * 100, 25)
- item_state = "[initial(icon_state)]_[remaining_rounds][flags_item & WIELDED ? "_w" : ""]"
- else if(flags_gun_features & GUN_SHOWS_LOADED) //shows loaded or unloaded
- item_state = "[initial(icon_state)]_[rounds ? 100 : 0][flags_item & WIELDED ? "_w" : ""]"
+ item_state = "[initial(icon_state)]_[remaining_rounds][item_flags & WIELDED ? "_w" : ""]"
+ else if(gun_features_flags & GUN_SHOWS_LOADED) //shows loaded or unloaded
+ item_state = "[initial(icon_state)]_[rounds ? 100 : 0][item_flags & WIELDED ? "_w" : ""]"
else
- item_state = "[base_gun_icon][flags_item & WIELDED ? "_w" : ""]"
+ item_state = "[base_gun_icon][item_flags & WIELDED ? "_w" : ""]"
return
if(current_state != item_state && ishuman(gun_user))
@@ -607,11 +617,11 @@
. += "[dat.Join(" ")]"
examine_ammo_count(user)
- if(!CHECK_BITFIELD(flags_item, IS_DEPLOYED))
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYABLE))
+ if(!CHECK_BITFIELD(item_flags, IS_DEPLOYED))
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYABLE))
. += span_notice("Use Ctrl-Click on a tile to deploy.")
return
- if(!CHECK_BITFIELD(flags_item, DEPLOYED_NO_ROTATE))
+ if(!CHECK_BITFIELD(item_flags, DEPLOYED_NO_ROTATE))
. += span_notice("Left or Right Click on a nearby tile to aim towards it.")
return
. += span_notice("Click-Drag to yourself to undeploy.")
@@ -620,16 +630,16 @@
///Gives the user a description of the ammunition remaining, as well as other information pertaining to reloading/ammo.
/obj/item/weapon/gun/proc/examine_ammo_count(mob/user)
- if(CHECK_BITFIELD(flags_gun_features, GUN_UNUSUAL_DESIGN) && CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES)) //Internal mags and unusual guns have their own stuff set.
+ if(CHECK_BITFIELD(gun_features_flags, GUN_UNUSUAL_DESIGN) && CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES)) //Internal mags and unusual guns have their own stuff set.
return
var/list/dat = list()
if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_TOGGLES_OPEN))
dat += "[CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_CLOSED) ? "It is closed. \n" : "It is open. \n"]"
if(rounds > 0)
- if(flags_gun_features & GUN_AMMO_COUNTER)
- if(max_rounds && CHECK_BITFIELD(flags_gun_features, GUN_AMMO_COUNT_BY_PERCENTAGE))
+ if(gun_features_flags & GUN_AMMO_COUNTER)
+ if(max_rounds && CHECK_BITFIELD(gun_features_flags, GUN_AMMO_COUNT_BY_PERCENTAGE))
dat += "Ammo counter shows [round((rounds / max_rounds) * 100)] percent remaining. "
- else if(max_rounds && CHECK_BITFIELD(flags_gun_features, GUN_AMMO_COUNT_BY_SHOTS_REMAINING))
+ else if(max_rounds && CHECK_BITFIELD(gun_features_flags, GUN_AMMO_COUNT_BY_SHOTS_REMAINING))
dat += "Ammo counter shows [round(rounds / rounds_per_shot)] shots remaining."
else
dat += "Ammo counter shows [rounds] round\s remaining. "
@@ -645,7 +655,7 @@
/* MOVED TO MODULE
/obj/item/weapon/gun/wield(mob/user)
- if(CHECK_BITFIELD(flags_gun_features, GUN_DEPLOYED_FIRE_ONLY))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_DEPLOYED_FIRE_ONLY))
to_chat(user, span_notice("[src] cannot be fired by hand and must be deployed."))
return
@@ -659,13 +669,13 @@
var/wdelay = wield_delay
//slower or faster wield delay depending on skill.
if(user.skills.getRating(SKILL_FIREARMS) < SKILL_FIREARMS_DEFAULT)
- wdelay += 0.3 SECONDS //no training in any firearms
+ wdelay += wield_penalty
else
var/skill_value = user.skills.getRating(gun_skill_category)
+ if(skill_value < 0)
+ wdelay += wield_penalty
if(skill_value > 0)
wdelay -= skill_value * 2
- else
- wdelay += wield_penalty
wield_time = world.time + wdelay
do_wield(user, wdelay)
if(HAS_TRAIT(src, TRAIT_GUN_AUTO_AIM_MODE))
@@ -687,9 +697,9 @@
/obj/item/weapon/gun/toggle_wielded(user, wielded)
if(wielded)
- flags_item |= WIELDED
+ item_flags |= WIELDED
else
- flags_item &= ~(WIELDED|FULLY_WIELDED)
+ item_flags &= ~(WIELDED|FULLY_WIELDED)
//----------------------------------------------------------
// \\
@@ -763,6 +773,11 @@
active_attachable?.clean_target()
target = get_turf(target)
+///Handles unzoom behavior
+/obj/item/weapon/gun/proc/on_unzoom(mob/user)
+ SIGNAL_HANDLER
+ stop_fire()
+
///Reset variables used in firing and remove the gun from the autofire system
/obj/item/weapon/gun/proc/stop_fire()
SIGNAL_HANDLER
@@ -812,7 +827,7 @@
///Wrapper proc to complete the whole firing process.
/obj/item/weapon/gun/proc/Fire()
- if(!target || !(gun_user || istype(loc, /obj/machinery/deployable/mounted/sentry)) || !(CHECK_BITFIELD(flags_item, IS_DEPLOYED) || able_to_fire(gun_user)) || windup_checked == WEAPON_WINDUP_CHECKING)
+ if(!target || !(gun_user || istype(loc, /obj/machinery/deployable/mounted/sentry)) || !(CHECK_BITFIELD(item_flags, IS_DEPLOYED) || able_to_fire(gun_user)) || windup_checked == WEAPON_WINDUP_CHECKING)
return NONE
if(windup_delay && windup_checked == WEAPON_WINDUP_NOT_CHECKED)
windup_checked = WEAPON_WINDUP_CHECKING
@@ -867,9 +882,24 @@
update_icon()
if(dual_wield && (gun_firemode == GUN_FIREMODE_SEMIAUTO || gun_firemode == GUN_FIREMODE_BURSTFIRE))
var/obj/item/weapon/gun/inactive_gun = gun_user.get_inactive_held_item()
- if(inactive_gun.rounds && !(inactive_gun.flags_gun_features & GUN_WIELDED_FIRING_ONLY))
+ if(inactive_gun.rounds && !(inactive_gun.gun_features_flags & GUN_WIELDED_FIRING_ONLY))
inactive_gun.last_fired = max(world.time - fire_delay * (1 - akimbo_additional_delay), inactive_gun.last_fired)
gun_user.swap_hand()
+ heat_amount += heat_per_fire
+ if(!(datum_flags & DF_ISPROCESSING))
+ START_PROCESSING(SSprocessing, src)
+ if(!heat_per_fire)
+ return AUTOFIRE_CONTINUE
+ if(heat_amount >= 100)
+ STOP_PROCESSING(SSprocessing, src)
+ var/obj/effect/abstract/particle_holder/overheat_smoke = new(src, /particles/overheat_smoke)
+ playsound(src, 'sound/weapons/guns/interact/gun_overheat.ogg', 25, 1, 5)
+ //overheat gives either you a bonus or penalty depending on gun, by default it is +10% time.
+ var/overheat_time = (heat_amount/cool_amount*overheat_multiplier) SECONDS
+ overheat_timer = addtimer(CALLBACK(src, PROC_REF(complete_overheat), overheat_smoke), overheat_time, TIMER_STOPPABLE)
+ heat_meter.animate_change(0, overheat_time)
+ return NONE
+ heat_meter.animate_change(heat_amount/100, fire_delay)
return AUTOFIRE_CONTINUE
///Actually fires the gun, sets up the projectile and fires it.
@@ -881,13 +911,14 @@
apply_gun_modifiers(projectile_to_fire, target, firer)
projectile_to_fire.accuracy = round((projectile_to_fire.accuracy * max( 0.1, gun_accuracy_mult)))
+ var/proj_scatter = 0
- if((flags_item & FULLY_WIELDED) || CHECK_BITFIELD(flags_item, IS_DEPLOYED) || (master_gun && (master_gun.flags_item & FULLY_WIELDED)))
+ if((item_flags & FULLY_WIELDED) || CHECK_BITFIELD(item_flags, IS_DEPLOYED) || (master_gun && (master_gun.item_flags & FULLY_WIELDED)))
scatter = clamp((scatter + scatter_increase) - ((world.time - last_fired - 1) * scatter_decay), min_scatter, max_scatter)
- projectile_to_fire.scatter += gun_scatter + scatter
+ proj_scatter += gun_scatter + scatter
else
scatter_unwielded = clamp((scatter_unwielded + scatter_increase_unwielded) - ((world.time - last_fired - 1) * scatter_decay_unwielded), min_scatter_unwielded, max_scatter_unwielded)
- projectile_to_fire.scatter += gun_scatter + scatter_unwielded
+ proj_scatter += gun_scatter + scatter_unwielded
if(gun_user)
projectile_to_fire.firer = gun_user
@@ -899,17 +930,17 @@
projectile_to_fire.damage *= 1 + skill_level * FIREARM_SKILL_DAM_MOD
if((world.time - gun_user.last_move_time) < 5) //if you moved during the last half second, you have some penalties to accuracy and scatter
- if(flags_item & FULLY_WIELDED)
+ if(item_flags & FULLY_WIELDED)
projectile_to_fire.accuracy -= projectile_to_fire.accuracy * max(0,movement_acc_penalty_mult * 0.03)
- projectile_to_fire.scatter = max(0, projectile_to_fire.scatter + max(0, movement_acc_penalty_mult * 0.5))
+ proj_scatter = max(0, proj_scatter + max(0, movement_acc_penalty_mult * 0.5))
else
projectile_to_fire.accuracy -= projectile_to_fire.accuracy * max(0,movement_acc_penalty_mult * 0.06)
- projectile_to_fire.scatter = max(0, projectile_to_fire.scatter + max(0, movement_acc_penalty_mult))
+ proj_scatter = max(0, proj_scatter + max(0, movement_acc_penalty_mult))
projectile_to_fire.accuracy += gun_accuracy_mod //additive added after move delay mult
- projectile_to_fire.scatter = max(projectile_to_fire.scatter, 0)
+ proj_scatter = max(proj_scatter, 0)
- var/firing_angle = get_angle_with_scatter((gun_user || get_turf(src)), target, projectile_to_fire.scatter, projectile_to_fire.p_x, projectile_to_fire.p_y)
+ var/firing_angle = get_angle_with_scatter((gun_user || get_turf(src)), target, proj_scatter, projectile_to_fire.p_x, projectile_to_fire.p_y)
//Finally, make with the pew pew!
if(!isobj(projectile_to_fire))
@@ -1001,8 +1032,8 @@
simulate_recoil(dual_wield, firing_angle)
- projectile_to_fire.fire_at(target, master_gun ? gun_user : loc, src, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED))
- if(CHECK_BITFIELD(flags_gun_features, GUN_SMOKE_PARTICLES))
+ projectile_to_fire.fire_at(target, master_gun ? gun_user : null, src, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_SMOKE_PARTICLES))
var/x_component = sin(firing_angle) * 40
var/y_component = cos(firing_angle) * 40
var/obj/effect/abstract/particle_holder/gun_smoke = new(get_turf(src), /particles/firing_smoke)
@@ -1022,8 +1053,21 @@
windup_checked = WEAPON_WINDUP_CHECKED
Fire()
+///called by a timer after overheat finishes
+/obj/item/weapon/gun/proc/complete_overheat(overheat_smoke)
+ QDEL_NULL(overheat_smoke)
+ overheat_timer = null
+ heat_amount = 0
+
+/obj/item/weapon/gun/process(delta_time)
+ if(heat_meter)
+ heat_amount = max(0, heat_amount - cool_amount*delta_time)
+ heat_meter.animate_change(heat_amount/100, 5)
+ if(!heat_amount)
+ return PROCESS_KILL
+
/obj/item/weapon/gun/attack(mob/living/M, mob/living/user, def_zone)
- if(!CHECK_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK) || !able_to_fire(user) || gun_on_cooldown(user) || CHECK_BITFIELD(M.status_flags, INCORPOREAL)) // If it can't point blank, you can't suicide and such.
+ if(!CHECK_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK) || !able_to_fire(user) || gun_on_cooldown(user) || CHECK_BITFIELD(M.status_flags, INCORPOREAL)) // If it can't point blank, you can't suicide and such.
if(master_gun)
return
return ..()
@@ -1045,21 +1089,21 @@
if(M != user || user.zone_selected != "mouth")
return ..()
- DISABLE_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK) //If they try to click again, they're going to hit themselves.
+ DISABLE_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK) //If they try to click again, they're going to hit themselves.
user.visible_message(span_warning("[user] sticks their gun in their mouth, ready to pull the trigger."))
log_combat(user, null, "is trying to commit suicide")
if(!do_after(user, 40, NONE, src, BUSY_ICON_DANGER))
M.visible_message(span_notice("[user] decided life was worth living."))
- ENABLE_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK)
+ ENABLE_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK)
return
var/obj/projectile/projectile_to_fire = in_chamber
if(!projectile_to_fire) //We actually have a projectile, let's move on.
playsound(src, dry_fire_sound, 25, 1, 5)
- ENABLE_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK)
+ ENABLE_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK)
return
projectile_to_fire = get_ammo_object()
@@ -1078,7 +1122,7 @@
user.death()
to_chat(user, span_highdanger("Your life flashes before you as your spirit is torn from your body!"))
user.ghostize(FALSE) //No return.
- ENABLE_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK)
+ ENABLE_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK)
return
switch(projectile_to_fire.ammo.damage_type)
@@ -1100,7 +1144,7 @@
QDEL_NULL(projectile_to_fire)
- ENABLE_BITFIELD(flags_gun_features, GUN_CAN_POINTBLANK)
+ ENABLE_BITFIELD(gun_features_flags, GUN_CAN_POINTBLANK)
/obj/item/weapon/gun/attack_alternate(mob/living/M, mob/living/user)
if(active_attachable)
@@ -1228,7 +1272,7 @@
if(!(new_mag.type in allowed_ammo_types))
if(isammomagazine(new_mag) && CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_HANDFULS))
var/obj/item/ammo_magazine/mag = new_mag
- if(!CHECK_BITFIELD(mag.flags_magazine, MAGAZINE_HANDFUL)) //If the gun uses handfuls, it accepts all handfuls since it uses caliber to check if its allowed.
+ if(!CHECK_BITFIELD(mag.magazine_flags, MAGAZINE_HANDFUL)) //If the gun uses handfuls, it accepts all handfuls since it uses caliber to check if its allowed.
to_chat(user, span_warning("[new_mag] cannot fit into [src]!"))
return FALSE
if(mag.caliber != caliber)
@@ -1261,8 +1305,8 @@
if(!get_current_rounds(new_mag) && !force)
to_chat(user, span_notice("[new_mag] is empty!"))
return FALSE
- var/flags_magazine_features = get_flags_magazine_features(new_mag)
- if(flags_magazine_features && CHECK_BITFIELD(flags_magazine_features, MAGAZINE_WORN) && \
+ var/magazine_features_flags = get_magazine_features_flags(new_mag)
+ if(magazine_features_flags && CHECK_BITFIELD(magazine_features_flags, MAGAZINE_WORN) && \
(!((loc == user) || (master_gun?.loc == user)) || (new_mag.loc != user)))
to_chat(user, span_warning("You need to be carrying both [src] and [new_mag] to connect them!"))
return FALSE
@@ -1282,7 +1326,7 @@
get_ammo()
if(user)
playsound(src, reload_sound, 25, 1)
- if(!flags_magazine_features || (flags_magazine_features && !CHECK_BITFIELD(flags_magazine_features, MAGAZINE_WORN)))
+ if(!magazine_features_flags || (magazine_features_flags && !CHECK_BITFIELD(magazine_features_flags, MAGAZINE_WORN)))
new_mag.forceMove(src)
user?.temporarilyRemoveItemFromInventory(new_mag)
if(istype(new_mag, /obj/item/ammo_magazine))
@@ -1301,7 +1345,7 @@
if(max_chamber_items)
if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_HANDFULS))
var/obj/item/ammo_magazine/mag = new_mag
- if(CHECK_BITFIELD(mag.flags_magazine, MAGAZINE_HANDFUL))
+ if(CHECK_BITFIELD(mag.magazine_flags, MAGAZINE_HANDFUL))
if(mag.current_rounds > 1)
items_to_insert += mag.create_handful(null, 1)
else
@@ -1414,7 +1458,7 @@
playsound(src, unload_sound, 25, 1, 5)
user?.visible_message(span_notice("[user] unloads [mag] from [src]."),
span_notice("You unload [mag] from [src]."), null, 4)
- if(drop && !(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES) && CHECK_BITFIELD(get_flags_magazine_features(mag), MAGAZINE_WORN)))
+ if(drop && !(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES) && CHECK_BITFIELD(get_magazine_features_flags(mag), MAGAZINE_WORN)))
if(user)
user.put_in_hands(mag)
else
@@ -1426,7 +1470,7 @@
if(istype(mag, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/magazine = mag
magazine.on_removed(src)
- if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES) && CHECK_BITFIELD(get_flags_magazine_features(mag), MAGAZINE_REFUND_IN_CHAMBER) && !after_fire && !CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE))
+ if(CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_MAGAZINES) && CHECK_BITFIELD(get_magazine_features_flags(mag), MAGAZINE_REFUND_IN_CHAMBER) && !after_fire && !CHECK_BITFIELD(reciever_flags, AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE))
QDEL_NULL(in_chamber)
adjust_current_rounds(mag, rounds_per_shot)
UnregisterSignal(mag, COMSIG_ITEM_REMOVED_INVENTORY)
@@ -1498,7 +1542,7 @@
num_of_casings--
if(num_of_casings)
casing.current_casings += num_of_casings
- casing.update_icon()
+ casing.update_appearance()
playsound(current_turf, sound_to_play, 25, 1, 5)
@@ -1507,7 +1551,7 @@
var/datum/ammo/new_ammo = get_ammo()
if(!new_ammo)
return
- var/projectile_type = CHECK_BITFIELD(initial(new_ammo.flags_ammo_behavior), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile
+ var/projectile_type = CHECK_BITFIELD(initial(new_ammo.ammo_behavior_flags), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile
var/obj/projectile/projectile = new projectile_type(null, initial(new_ammo.hitscan_effect_icon))
projectile.generate_bullet(new_ammo)
return projectile
@@ -1544,9 +1588,9 @@
///returns ammo count to display in the ammo counter of the HUD
/obj/item/weapon/gun/proc/get_display_ammo_count()
- if(rounds && (flags_gun_features & GUN_AMMO_COUNT_BY_SHOTS_REMAINING))
+ if(rounds && (gun_features_flags & GUN_AMMO_COUNT_BY_SHOTS_REMAINING))
return round(rounds / rounds_per_shot)
- if(max_rounds && rounds && (flags_gun_features & GUN_AMMO_COUNT_BY_PERCENTAGE))
+ if(max_rounds && rounds && (gun_features_flags & GUN_AMMO_COUNT_BY_PERCENTAGE))
return round((rounds / max_rounds) * 100)
return rounds
@@ -1582,7 +1626,7 @@
SIGNAL_HANDLER
if(!length(chamber_items) || !chamber_items[current_chamber_position])
return
- if(!(get_flags_magazine_features(chamber_items[current_chamber_position]) & MAGAZINE_WORN))
+ if(!(get_magazine_features_flags(chamber_items[current_chamber_position]) & MAGAZINE_WORN))
return
unload(user, FALSE)
@@ -1601,12 +1645,12 @@
var/obj/item/ammo_magazine/magazine = mag
return magazine?.max_rounds
-///Getter to draw flags_magazine features. If the mag has none, overwrite and return null.
-/obj/item/weapon/gun/proc/get_flags_magazine_features(obj/item/mag)
+///Getter to draw magazine_flags features. If the mag has none, overwrite and return null.
+/obj/item/weapon/gun/proc/get_magazine_features_flags(obj/item/mag)
var/obj/item/ammo_magazine/magazine = mag
if(!istype(magazine))
return NONE
- return magazine ? magazine.flags_magazine : NONE
+ return magazine ? magazine.magazine_flags : NONE
///Getter to draw default ammo type. If the mag has none, overwrite and return null.
/obj/item/weapon/gun/proc/get_magazine_default_ammo(obj/item/mag)
@@ -1656,35 +1700,38 @@
if(!user.dextrous)
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return FALSE
- if(!(flags_gun_features & GUN_ALLOW_SYNTHETIC) && !CONFIG_GET(flag/allow_synthetic_gun_use) && issynth(user))
+ if(!(gun_features_flags & GUN_ALLOW_SYNTHETIC) && !CONFIG_GET(flag/allow_synthetic_gun_use) && issynth(user))
to_chat(user, span_warning("Your program does not allow you to use this firearm."))
return FALSE
if(HAS_TRAIT(src, TRAIT_GUN_SAFETY))
to_chat(user, span_warning("The safety is on!"))
return FALSE
- if(CHECK_BITFIELD(flags_gun_features, GUN_WIELDED_FIRING_ONLY)) //If we're not holding the weapon with both hands when we should.
- if(!master_gun && !CHECK_BITFIELD(flags_item, WIELDED))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_WIELDED_FIRING_ONLY)) //If we're not holding the weapon with both hands when we should.
+ if(!master_gun && !CHECK_BITFIELD(item_flags, WIELDED))
to_chat(user, "You need a more secure grip to fire this weapon!")
return FALSE
- if(master_gun && !CHECK_BITFIELD(master_gun.flags_item, WIELDED))
+ if(master_gun && !CHECK_BITFIELD(master_gun.item_flags, WIELDED))
to_chat(user, span_warning("You need a more secure grip to fire [src]!"))
return FALSE
if(LAZYACCESS(user.do_actions, src))
to_chat(user, "You are doing something else currently.")
return FALSE
- if(CHECK_BITFIELD(flags_gun_features, GUN_WIELDED_STABLE_FIRING_ONLY))//If we must wait to finish wielding before shooting.
- if(!master_gun && !(flags_item & FULLY_WIELDED))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_WIELDED_STABLE_FIRING_ONLY))//If we must wait to finish wielding before shooting.
+ if(!master_gun && !(item_flags & FULLY_WIELDED))
to_chat(user, "You need a more secure grip to fire this weapon!")
return FALSE
- if(master_gun && !(master_gun.flags_item & FULLY_WIELDED))
+ if(master_gun && !(master_gun.item_flags & FULLY_WIELDED))
to_chat(user, "You need a more secure grip to fire [src]!")
return FALSE
- if(CHECK_BITFIELD(flags_gun_features, GUN_DEPLOYED_FIRE_ONLY) && !CHECK_BITFIELD(flags_item, IS_DEPLOYED))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_DEPLOYED_FIRE_ONLY) && !CHECK_BITFIELD(item_flags, IS_DEPLOYED))
to_chat(user, span_notice("You cannot fire [src] while it is not deployed."))
return FALSE
- if(CHECK_BITFIELD(flags_gun_features, GUN_IS_ATTACHMENT) && !master_gun && CHECK_BITFIELD(flags_gun_features, GUN_ATTACHMENT_FIRE_ONLY))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_IS_ATTACHMENT) && !master_gun && CHECK_BITFIELD(gun_features_flags, GUN_ATTACHMENT_FIRE_ONLY))
to_chat(user, span_notice("You cannot fire [src] without it attached to a gun!"))
return FALSE
+ if(overheat_timer)
+ balloon_alert(user, "overheat")
+ return FALSE
return TRUE
/obj/item/weapon/gun/proc/gun_on_cooldown(mob/user)
@@ -1713,7 +1760,7 @@
/obj/item/weapon/gun/proc/play_fire_sound(mob/user)
//Guns with low ammo have their firing sound
- var/firing_sndfreq = CHECK_BITFIELD(flags_gun_features, GUN_NO_PITCH_SHIFT_NEAR_EMPTY) ? FALSE : ((rounds / (max_rounds ? max_rounds : max_shells)) > 0.25) ? FALSE : 55000
+ var/firing_sndfreq = CHECK_BITFIELD(gun_features_flags, GUN_NO_PITCH_SHIFT_NEAR_EMPTY) ? FALSE : ((max(rounds, 1) / (max_rounds ? max_rounds : max_shells)) > 0.25) ? FALSE : 55000
if(HAS_TRAIT(src, TRAIT_GUN_SILENCED))
playsound(user, fire_sound, 25, firing_sndfreq ? TRUE : FALSE, frequency = firing_sndfreq)
return
@@ -1730,7 +1777,7 @@
projectile_to_fire.damage_falloff *= max(0, damage_falloff_mult)
projectile_to_fire.projectile_speed = projectile_to_fire.ammo.shell_speed
projectile_to_fire.projectile_speed += shell_speed_mod
- if(flags_gun_features & GUN_IFF || HAS_TRAIT(src, TRAIT_GUN_IS_AIMING) || projectile_to_fire.ammo.flags_ammo_behavior & AMMO_IFF)
+ if(gun_features_flags & GUN_IFF || HAS_TRAIT(src, TRAIT_GUN_IS_AIMING) || projectile_to_fire.ammo.ammo_behavior_flags & AMMO_IFF)
var/iff_signal
if(ishuman(firer))
var/mob/living/carbon/human/_firer = firer
@@ -1755,13 +1802,13 @@
gun_accuracy_mod = 0
gun_scatter = 0
- if((flags_item & FULLY_WIELDED) || CHECK_BITFIELD(flags_item, IS_DEPLOYED) || (master_gun && (master_gun.flags_item & FULLY_WIELDED) ))
+ if((item_flags & FULLY_WIELDED) || CHECK_BITFIELD(item_flags, IS_DEPLOYED) || (master_gun && (master_gun.item_flags & FULLY_WIELDED) ))
wielded_fire = TRUE
gun_accuracy_mult = accuracy_mult
else
gun_accuracy_mult = accuracy_mult_unwielded
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYED)) //if our gun is deployed, change the scatter by this number, usually a negative
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYED)) //if our gun is deployed, change the scatter by this number, usually a negative
gun_scatter += deployed_scatter_change
if(gun_firemode == GUN_FIREMODE_BURSTFIRE || gun_firemode == GUN_FIREMODE_AUTOBURST)
@@ -1773,7 +1820,7 @@
gun_scatter += burst_amount * burst_scatter_mult * 2
if(dual_wield) //akimbo firing gives terrible scatter
- gun_scatter += 2 * rand(upper_akimbo_accuracy, lower_akimbo_accuracy) //TODO: remove the rng increase
+ gun_scatter += akimbo_scatter_mod
if(gun_user)
//firearm skills modifiers
@@ -1795,21 +1842,18 @@
gun_accuracy_mod -= round(min(20, (shooter_human.shock_stage * 0.2))) //Accuracy declines with pain, being reduced by 0.2% per point of pain.
if(shooter_human.marksman_aura)
gun_accuracy_mod += 10 + max(5, shooter_human.marksman_aura * 5) //Accuracy bonus from active focus order
- add_aim_mode_fire_delay(AURA_HUMAN_FOCUS, initial(aim_fire_delay) * -0.5)
- else
- remove_aim_mode_fire_delay(AURA_HUMAN_FOCUS)
/obj/item/weapon/gun/proc/simulate_recoil(recoil_bonus = 0, firing_angle)
- if(CHECK_BITFIELD(flags_item, IS_DEPLOYED) || !gun_user)
+ if(CHECK_BITFIELD(item_flags, IS_DEPLOYED) || !gun_user)
return TRUE
var/total_recoil = recoil_bonus
- if((flags_item & FULLY_WIELDED) || master_gun)
+ if((item_flags & FULLY_WIELDED) || master_gun)
total_recoil += recoil
else
total_recoil += recoil_unwielded
if(HAS_TRAIT(src, TRAIT_GUN_BURST_FIRING))
total_recoil += 1
- if(!gun_user.skills.getRating(SKILL_FIREARMS)) //no training in any firearms
+ if(gun_user.skills.getRating(SKILL_FIREARMS) <= SKILL_FIREARMS_UNTRAINED) //no training in any firearms
total_recoil += 2
else
var/recoil_tweak = gun_user.skills.getRating(gun_skill_category)
@@ -1836,7 +1880,7 @@
muzzle_flash.applied = FALSE
//For letting xenos turn off the flashlights on any guns left lying around.
-/obj/item/weapon/gun/attack_alien(mob/living/carbon/xenomorph/X, isrightclick = FALSE)
+/obj/item/weapon/gun/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!HAS_TRAIT(src, TRAIT_GUN_FLASHLIGHT_ON))
return
for(var/attachment_slot in attachments_by_slot)
@@ -1845,5 +1889,36 @@
continue
lit_flashlight.turn_light(null, FALSE)
playsound(loc, "alien_claw_metal", 25, 1)
- X.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- to_chat(X, span_warning("We disable the metal thing's lights.") )
+ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
+ to_chat(xeno_attacker, span_warning("We disable the metal thing's lights.") )
+
+
+/particles/overheat_smoke
+ icon = 'icons/effects/particles/smoke.dmi'
+ icon_state = list("smoke_1" = 1, "smoke_2" = 1, "smoke_3" = 2)
+ width = 100
+ height = 200
+ count = 1000
+ spawning = 3
+ lifespan = 1.5 SECONDS
+ fade = 1 SECONDS
+ velocity = list(0, 0.3, 0)
+ position = list(8, 8)
+ drift = generator(GEN_SPHERE, 0, 1, NORMAL_RAND)
+ friction = 0.2
+ gravity = list(0, 0.95)
+ grow = 0.05
+
+//tried to make this a alpha mask that moved up and down over the bar but I failed so whatever
+/image/heat_bar
+ icon = 'icons/effects/overheat.dmi'
+ icon_state = "status_bar"
+ plane = ABOVE_HUD_PLANE
+ appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+
+///takes a 0-1 value and then animates to display that percentage on this bar
+/image/heat_bar/proc/animate_change(new_percentage, animate_time)
+ if(new_percentage != 0)
+ animate(src, color=gradient(COLOR_GREEN, COLOR_RED, new_percentage), alpha = 175, easing=SINE_EASING, time=animate_time)
+ return
+ animate(src, color=gradient(COLOR_GREEN, COLOR_RED, new_percentage), alpha = 0, easing=SINE_EASING, time=animate_time)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index e55fb6bfefc0a..4ba50fafac44a 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -3,9 +3,14 @@
//ENERGY GUNS/ETC
/obj/item/weapon/gun/energy
+ icon = 'icons/obj/items/guns/energy.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/energy_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/energy_right_1.dmi',
+ )
attachable_allowed = list()
rounds_per_shot = 10 //100 shots.
- flags_gun_features = GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
general_codex_key = "energy weapons"
placed_overlay_iconstate = "laser"
@@ -29,9 +34,9 @@
/obj/item/weapon/gun/energy/get_magazine_default_ammo(obj/item/mag)
return null
-/obj/item/weapon/gun/energy/get_flags_magazine_features(obj/item/mag)
+/obj/item/weapon/gun/energy/get_magazine_features_flags(obj/item/mag)
var/obj/item/cell/lasgun/cell = mag
- return cell ? cell.flags_magazine_features : NONE
+ return cell ? cell.magazine_features_flags : NONE
//based off of basegun proc, should work.
/obj/item/weapon/gun/energy/get_magazine_overlay(obj/item/mag)
var/obj/item/cell/lasgun/cell = mag
@@ -52,7 +57,7 @@
default_ammo_type = /obj/item/cell/lasgun/lasrifle
allowed_ammo_types = list(/obj/item/cell/lasgun/lasrifle)
rounds_per_shot = 500
- flags_gun_features = GUN_AMMO_COUNTER|GUN_ALLOW_SYNTHETIC|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_ALLOW_SYNTHETIC|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
gun_skill_category = SKILL_PISTOLS
movement_acc_penalty_mult = 0
@@ -80,15 +85,15 @@
fire_sound = 'sound/weapons/guns/fire/laser.ogg'
load_method = CELL //codex
ammo_datum_type = /datum/ammo/energy/lasgun
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
muzzleflash_iconstate = "muzzle_flash_laser"
w_class = WEIGHT_CLASS_BULKY
force = 15
overcharge = FALSE
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_DO_NOT_EJECT_HANDFULS|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
aim_slowdown = 0.75
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
gun_skill_category = SKILL_RIFLES
muzzle_flash_color = COLOR_LASER_RED
@@ -97,8 +102,7 @@
accuracy_mult_unwielded = 0.6
scatter_unwielded = 80 //Heavy and unwieldy
damage_falloff_mult = 0.5
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
+ akimbo_scatter_mod = 8
/obj/item/weapon/gun/energy/lasgun/unique_action(mob/user, dont_operate = FALSE)
QDEL_NULL(in_chamber)
@@ -170,7 +174,7 @@
/obj/item/attachable/stock/lasgun,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
starting_attachment_types = list(/obj/item/attachable/stock/lasgun)
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 23, "under_x" = 23, "under_y" = 15, "stock_x" = 22, "stock_y" = 12)
ammo_level_icon = "m43"
@@ -206,8 +210,8 @@
default_ammo_type = /obj/item/cell/lasgun/pulse
allowed_ammo_types = list(/obj/item/cell/lasgun/pulse)
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 23, "under_x" = 23, "under_y" = 15, "stock_x" = 22, "stock_y" = 12)
ammo_level_icon = "m19c4"
fire_delay = 4
@@ -244,7 +248,7 @@
/obj/item/weapon/gun/energy/lasgun/lasrifle
name = "\improper LR-73 lasrifle MK2"
desc = "A multifunctional laser based rifle with an integrated mode selector. Ideal for any situation. Uses power cells instead of ballistic magazines."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/energy64.dmi'
icon_state = "tx73"
item_state = "tx73"
max_shots = 50 //codex stuff
@@ -268,7 +272,7 @@
/obj/item/attachable/scope/marine,
/obj/item/attachable/scope/mini,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY
attachable_offset = list("muzzle_x" = 34, "muzzle_y" = 14,"rail_x" = 18, "rail_y" = 18, "under_x" = 23, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
ammo_level_icon = "tx73"
accuracy_mult_unwielded = 0.5 //Heavy and unwieldy; you don't one hand this.
@@ -276,7 +280,7 @@
damage_falloff_mult = 0.25
fire_delay = 2
default_ammo_type = /obj/item/cell/lasgun/lasrifle
- allowed_ammo_types = list(/obj/item/cell/lasgun/lasrifle, /obj/item/cell/lasgun/volkite/powerpack/marine, /obj/item/cell/lasgun/lasrifle/recharger)
+ allowed_ammo_types = list(/obj/item/cell/lasgun/lasrifle, /obj/item/cell/lasgun/lasrifle/recharger)
/// A list of available modes this gun can switch to
var/list/datum/lasrifle/mode_list = list()
/// The index of the current mode selected, used for non radial mode switches
@@ -291,10 +295,12 @@
var/fire_delay = 0
///Gives guns a burst amount, editable.
var/burst_amount = 0
+ ///heat amount per shot
+ var/heat_per_fire = 0
///The gun firing sound of this mode
var/fire_sound = null
///What message it sends to the user when you switch to this mode.
- var/message_to_user = ""
+ var/message_to_user = "" // todo delete me I'm useless
///Used to change the gun firemode, like automatic, semi-automatic and burst.
var/fire_mode = GUN_FIREMODE_SEMIAUTO
///what to change the gun icon_state to when switching to this mode.
@@ -308,6 +314,7 @@
///codex description
var/description = ""
+//TODO this proc should be generic so that you dont have to manually copy paste the default mode onto the item
/obj/item/weapon/gun/energy/lasgun/lasrifle/unique_action(mob/user)
if(!user)
CRASH("switch_modes called with no user.")
@@ -344,6 +351,7 @@
fire_sound = initial(choice.fire_sound)
rounds_per_shot = initial(choice.rounds_per_shot)
windup_delay = initial(choice.windup_delay)
+ heat_per_fire = initial(choice.heat_per_fire)
SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, burst_amount)
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay)
SEND_SIGNAL(src, COMSIG_GUN_FIRE_MODE_TOGGLE, initial(choice.fire_mode), user.client)
@@ -365,15 +373,14 @@
desc = "A Terra Experimental energy rifle that fires balls of elecricity that shock all those near them, it is meant to drain the plasma of unidentified creatures from within, limiting their abilities. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts. Uses standard Terra Experimental (TE) power cells."
icon_state = "tesla"
item_state = "tesla"
- icon = 'icons/Marine/gun64.dmi'
reload_sound = 'sound/weapons/guns/interact/standard_laser_rifle_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/tesla.ogg'
ammo_datum_type = /datum/ammo/energy/tesla
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
default_ammo_type = /obj/item/cell/lasgun/lasrifle
- allowed_ammo_types = list(/obj/item/cell/lasgun/lasrifle, /obj/item/cell/lasgun/volkite/powerpack/marine)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
+ allowed_ammo_types = list(/obj/item/cell/lasgun/lasrifle)
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SHOWS_AMMO_REMAINING
muzzle_flash_color = COLOR_TESLA_BLUE
ammo_level_icon = "tesla"
max_shots = 6 //codex stuff
@@ -385,7 +392,6 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
mode_list = list(
@@ -423,8 +429,8 @@
desc = "A Terra Experimental laser rifle, abbreviated as the TE-R. Has multiple firemodes for tactical flexibility. Uses standard Terra Experimental (abbreviated as TE) power cells. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts."
reload_sound = 'sound/weapons/guns/interact/standard_laser_rifle_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/Laser Rifle Standard.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "ter"
+ item_state = "ter"
max_shots = 60
ammo_datum_type = /datum/ammo/energy/lasgun/marine
rounds_per_shot = 10
@@ -432,14 +438,6 @@
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
turret_flags = TURRET_INACCURATE
ammo_level_icon = "te"
- greyscale_config = /datum/greyscale_config/gun/gun64/lasgun
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/ter,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/ter,
- slot_back_str = /datum/greyscale_config/worn_gun/ter,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/ter,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -454,7 +452,6 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/gyro,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/angledgrip,
@@ -462,11 +459,11 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 40, "muzzle_y" = 17,"rail_x" = 22, "rail_y" = 21, "under_x" = 29, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
aim_slowdown = 0.4
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
scatter = 0
scatter_unwielded = 10
fire_delay = 0.2 SECONDS
@@ -492,7 +489,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Rifle Standard.ogg'
message_to_user = "You set the laser rifle's charge mode to standard fire."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "ter"
description = "Fire a standard automatic laser pulse. Better armour penetration and sunder than common projectiles."
@@ -503,7 +500,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser overcharge standard.ogg'
message_to_user = "You set the laser rifle's charge mode to overcharge."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "ter"
radial_icon_state = "laser_overcharge"
description = "Fires a powerful overcharged laser pulse. Deals heavy damage with superior penetration at the cost of slower fire rate."
@@ -514,7 +511,7 @@
fire_sound = 'sound/weapons/guns/fire/laser.ogg'
message_to_user = "You set the laser rifle's charge mode to weakening."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "ter"
radial_icon_state = "laser_disabler"
description = "Fires a pulse of energy that inflicts slowdown, and deals stamina damage to humans, or drains plasma from xenomorphs."
@@ -526,7 +523,7 @@
fire_sound = 'sound/weapons/guns/fire/laser_rifle_2.ogg'
message_to_user = "You set the laser rifle's charge mode to microwave."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "ter"
radial_icon_state = "laser_microwave"
description = "Fires a deadly pulse of microwave radiation, dealing moderate damage but applying a 'microwave' effect that deals strong damage over time."
@@ -537,22 +534,17 @@
desc = "A TerraGov standard issue laser pistol abbreviated as TE-P. It has an integrated charge selector for normal, heat and taser settings. Uses standard Terra Experimental (abbreviated as TE) power cells. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts."
reload_sound = 'sound/weapons/guns/interact/standard_laser_pistol_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/Laser Pistol Standard.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tep"
+ item_state = "tep"
w_class = WEIGHT_CLASS_NORMAL
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
+ gun_skill_category = SKILL_PISTOLS
max_shots = 30 //codex stuff
ammo_datum_type = /datum/ammo/energy/lasgun/marine/pistol
ammo_level_icon = null
rounds_per_shot = 20
- gun_firemode = GUN_FIREMODE_SEMIAUTO
- gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
- greyscale_config = /datum/greyscale_config/gun/pistol/tep
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tep,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tep,
- )
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -566,11 +558,11 @@
/obj/item/attachable/flashlight/under,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 23, "muzzle_y" = 22,"rail_x" = 12, "rail_y" = 22, "under_x" = 16, "under_y" = 14, "stock_x" = 22, "stock_y" = 12)
akimbo_additional_delay = 0.9
- wield_delay = 0.2 SECONDS
+ wield_delay = 0.4 SECONDS
scatter = 2
scatter_unwielded = 4
fire_delay = 0.15 SECONDS
@@ -593,8 +585,8 @@
fire_delay = 0.15 SECONDS
fire_sound = 'sound/weapons/guns/fire/Laser Pistol Standard.ogg'
message_to_user = "You set the laser pistol's charge mode to standard fire."
- fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ icon_state = "tep"
description = "Fires a standard laser pulse. Moderate damage."
/datum/lasrifle/energy_pistol_mode/disabler
@@ -604,7 +596,7 @@
fire_sound = 'sound/weapons/guns/fire/disabler.ogg'
message_to_user = "You set the laser pistol's charge mode to disabler fire."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tep"
radial_icon_state = "laser_disabler"
description = "Fires a disabling pulse that drains stamina. Ineffective against xenomorphs."
@@ -615,7 +607,7 @@
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
message_to_user = "You set the laser pistol's charge mode to wave heat."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tep"
radial_icon_state = "laser_heat"
description = "Fires an incendiary laser pulse that ignites living targets."
@@ -626,22 +618,14 @@
desc = "A TerraGov standard issue laser carbine, otherwise known as TE-C for short. Has multiple firemodes for tactical flexibility. Uses standard Terra Experimental (abbreviated as TE) power cells. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts."
reload_sound = 'sound/weapons/guns/interact/standard_laser_rifle_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/Laser Carbine Scatter.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tec"
+ item_state = "tec"
max_shots = 12
ammo_datum_type = /datum/ammo/energy/lasgun/marine/blast
rounds_per_shot = 50
gun_firemode = GUN_FIREMODE_SEMIAUTO
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
ammo_level_icon = "te"
- greyscale_config = /datum/greyscale_config/gun/gun64/lasgun/tec
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tec,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tec,
- slot_back_str = /datum/greyscale_config/worn_gun/tec,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tec,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -655,18 +639,17 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/gyro,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/angledgrip,
/obj/item/attachable/flashlight/under,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 17, "rail_y" = 21, "under_x" = 23, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
aim_slowdown = 0.2
- wield_delay = 0.3 SECONDS
+ wield_delay = 0.5 SECONDS
scatter = 1
scatter_unwielded = 10
fire_delay = 1.5 SECONDS
@@ -703,6 +686,13 @@
/obj/item/attachable/gyro,
)
+/obj/item/weapon/gun/energy/lasgun/lasrifle/standard_marine_carbine/beginner
+ starting_attachment_types = list(
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/bayonet,
+ )
+
/datum/lasrifle/energy_carbine_mode/auto_burst
rounds_per_shot = 12
ammo_datum_type = /datum/ammo/energy/lasgun/marine/carbine
@@ -711,7 +701,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Rifle Standard.ogg'
message_to_user = "You set the laser carbine's charge mode to standard auto burst fire."
fire_mode = GUN_FIREMODE_AUTOBURST
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tec"
description = "Fires a rapid pulse laser, dealing good damage per second, but suffers from increased scatter and poorer falloff."
/datum/lasrifle/energy_carbine_mode/base/spread
@@ -722,7 +712,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Carbine Scatter.ogg'
message_to_user = "You set the laser carbine's charge mode to spread."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tec"
radial_icon_state = "laser_spread"
description = "Fire a 3 strong laser pulse dealing heavy damage with good penetration, but with a very slow rate of fire."
@@ -734,7 +724,7 @@
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
message_to_user = "You set the laser carbine's charge mode to impact."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tec"
radial_icon_state = "laser_impact"
description = "Fires an experimental laser pulse designed to apply significant kinetic force on a target, applying strong knockback, but modest direct damage."
@@ -746,7 +736,7 @@
fire_sound = 'sound/weapons/guns/fire/laser.ogg'
message_to_user = "You set the laser carbine's charge mode to cripple."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tec"
radial_icon_state = "laser_disabler"
description = "Fires a laser pulse dealing moderate damage and slowdown."
@@ -757,8 +747,8 @@
desc = "The T-ES, a Terra Experimental standard issue laser sniper rifle, has multiple powerful firemodes, although the lack of aim mode can limit its tactical flexibility. Uses standard Terra Experimental (abbreviated as TE) power cells. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts."
reload_sound = 'sound/weapons/guns/interact/standard_laser_sniper_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/Laser Sniper Standard.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tes"
+ item_state = "tes"
w_class = WEIGHT_CLASS_BULKY
max_shots = 20
ammo_datum_type = /datum/ammo/energy/lasgun/marine/sniper
@@ -770,14 +760,6 @@
ammo_level_icon = "te"
icon_overlay_x_offset = -1
icon_overlay_y_offset = -3
- greyscale_config = /datum/greyscale_config/gun/gun64/lasgun/tes
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tes,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tes,
- slot_back_str = /datum/greyscale_config/worn_gun/tes,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tes,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -789,7 +771,6 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/gyro,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/angledgrip,
@@ -797,12 +778,12 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 41, "muzzle_y" = 18,"rail_x" = 19, "rail_y" = 19, "under_x" = 28, "under_y" = 8, "stock_x" = 22, "stock_y" = 12)
starting_attachment_types = list(/obj/item/attachable/scope/unremovable/laser_sniper_scope)
aim_slowdown = 0.7
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
scatter = -4
scatter_unwielded = 10
fire_delay = 0.8 SECONDS
@@ -823,7 +804,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Sniper Standard.ogg'
message_to_user = "You set the sniper rifle's charge mode to standard fire."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tes"
description = "Fires a single strong laser pulse, with good damage and penetration, and no falloff."
/datum/lasrifle/energy_sniper_mode/heat
@@ -833,7 +814,7 @@
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
message_to_user = "You set the sniper rifle's charge mode to wave heat."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tes"
radial_icon_state = "laser_heat"
description = "Fires an incendiary laser pulse, designed to ignite victims at range."
@@ -844,7 +825,7 @@
fire_sound = 'sound/weapons/guns/fire/laser_rifle_2.ogg'
message_to_user = "You set the sniper rifle's charge mode to shatter."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tes"
radial_icon_state = "laser_charge"
description = "Fires a devestating laser pulse that significantly degrades the victims armor, at the cost of lower direct damage."
@@ -855,7 +836,7 @@
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
message_to_user = "You set the sniper rifle's charge mode to ricochet."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tes"
radial_icon_state = "laser_ricochet"
description = "Fires an experiment laser pulse capable of bouncing off many wall surfaces. The laser increases in potency when bouncing, before collapsing entirely after exceeding its threshold."
@@ -866,23 +847,16 @@
desc = "A Terra Experimental standard issue machine laser gun, often called as the TE-M by marines. High efficiency modulators ensure the TE-M has an extremely high fire count, and multiple firemodes makes it a flexible infantry support gun. Uses standard Terra Experimental (abbreviated as TE) power cells. As with all TE Laser weapons, they use a lightweight alloy combined without the need for bullets any longer decreases their weight and aiming speed quite some vs their ballistic counterparts."
reload_sound = 'sound/weapons/guns/interact/standard_machine_laser_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/Laser Rifle Standard.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tem"
+ item_state = "tem"
w_class = WEIGHT_CLASS_BULKY
+ gun_skill_category = SKILL_HEAVY_WEAPONS
max_shots = 150 //codex stuff
ammo_datum_type = /datum/ammo/energy/lasgun/marine/autolaser
rounds_per_shot = 4
gun_firemode = GUN_FIREMODE_AUTOMATIC
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
ammo_level_icon = "te"
- greyscale_config = /datum/greyscale_config/gun/gun64/lasgun/tem
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tem,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tem,
- slot_back_str = /datum/greyscale_config/worn_gun/tem,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tem,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -896,7 +870,6 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/gyro,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/angledgrip,
@@ -904,11 +877,11 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 41, "muzzle_y" = 15,"rail_x" = 22, "rail_y" = 24, "under_x" = 30, "under_y" = 8, "stock_x" = 22, "stock_y" = 12)
aim_slowdown = 0.7
- wield_delay = 0.8 SECONDS
+ wield_delay = 1 SECONDS
scatter = 1
fire_delay = 0.2 SECONDS
burst_delay = 0.25 SECONDS
@@ -940,7 +913,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Sniper Standard.ogg'
message_to_user = "You set the machine laser's charge mode to standard fire."
fire_mode = GUN_FIREMODE_AUTOMATIC
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tem"
description = "Fires a rapid laser pulse with slightly reduced damage, but improved penetration and vastly improved energy efficiency."
/datum/lasrifle/energy_mg_mode/standard/burst
@@ -951,7 +924,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Carbine Scatter.ogg'
message_to_user = "You set the machine laser's charge mode to burst."
fire_mode = GUN_FIREMODE_BURSTFIRE
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "tem"
radial_icon_state = "laser_spread"
description = "Fires a series of laser pulses in quick succession. Each pulse in a burst is more powerful than the last."
@@ -1001,7 +974,6 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/gyro,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/angledgrip,
@@ -1009,11 +981,11 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
attachable_offset = list("muzzle_x" = 40, "muzzle_y" = 19,"rail_x" = 20, "rail_y" = 21, "under_x" = 30, "under_y" = 13, "stock_x" = 22, "stock_y" = 14)
ammo_level_icon = "tex"
aim_slowdown = 0.4
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
scatter = 0
scatter_unwielded = 10
fire_delay = 0.5 SECONDS
@@ -1063,7 +1035,7 @@
gun_firemode = GUN_FIREMODE_AUTOMATIC
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list()
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_SHOWS_LOADED
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_SHOWS_LOADED
attachable_offset = list("muzzle_x" = 34, "muzzle_y" = 14,"rail_x" = 18, "rail_y" = 18, "under_x" = 23, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
accuracy_mult = 1
@@ -1074,8 +1046,7 @@
recoil_unwielded = 3
aim_slowdown = 0.35
- wield_delay = 0.4 SECONDS
- wield_penalty = 0.2 SECONDS
+ wield_delay = 0.6 SECONDS
damage_falloff_mult = 0.9
fire_delay = 0.2 SECONDS
@@ -1084,12 +1055,12 @@
light_power = 0.1
light_color = LIGHT_COLOR_ORANGE
-/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/update_icon(mob/user)
+/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/update_icon()
. = ..()
if(rounds)
- turn_light(user, TRUE)
+ turn_light(null, TRUE)
else
- turn_light(user, FALSE)
+ turn_light(null, FALSE)
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/turn_light(mob/user, toggle_on)
. = ..()
@@ -1108,14 +1079,15 @@
icon_state = "vx12"
item_state = "vx12"
w_class = WEIGHT_CLASS_NORMAL
+ gun_skill_category = SKILL_PISTOLS
max_shots = 15
rounds_per_shot = 36
ammo_datum_type = /datum/ammo/energy/volkite/medium
default_ammo_type = /obj/item/cell/lasgun/volkite/small
allowed_ammo_types = list(/obj/item/cell/lasgun/volkite/small)
fire_sound = 'sound/weapons/guns/fire/volkite_3.ogg'
- gun_firemode = GUN_FIREMODE_SEMIAUTO
- gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
fire_delay = 0.35 SECONDS
scatter = -1
scatter_unwielded = 5
@@ -1124,7 +1096,7 @@
recoil_unwielded = 0
movement_acc_penalty_mult = 2
aim_slowdown = 0.1
- wield_delay = 0.2 SECONDS
+ wield_delay = 0.4 SECONDS
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/serpenta/custom
name = "\improper VX-12c Serpenta"
@@ -1154,7 +1126,6 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 13,"rail_x" = 9, "rail_y" = 23, "under_x" = 30, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
scatter = 3
@@ -1180,14 +1151,13 @@
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver
name = "\improper VX-33 Caliver"
desc = "Volkite weapons are the pride of Martian weapons manufacturing, their construction being a tightly guarded secret. Infamous for its ability to deflagrate organic targets with its tremendous thermal energy, explosively burning flesh in a fiery blast that can be deadly to anyone unfortunate enough to be nearby. The caliver is the primary rifle of the volkite family, and effective at most ranges and situations. Drag click the powerpack to the gun to use that instead of magazines."
- icon = 'icons/Marine/gun64.dmi'
icon_state = "caliver"
item_state = "caliver"
inhand_x_dimension = 64
inhand_y_dimension = 32
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/energy_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/energy_right_64.dmi',
)
fire_sound = 'sound/weapons/guns/fire/volkite_3.ogg'
max_shots = 40
@@ -1208,13 +1178,12 @@
/obj/item/attachable/scope/marine,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
attachable_offset = list("muzzle_x" = 38, "muzzle_y" = 13,"rail_x" = 9, "rail_y" = 24, "under_x" = 45, "under_y" = 11, "stock_x" = 22, "stock_y" = 12)
accuracy_mult = 1.1
aim_slowdown = 0.65
damage_falloff_mult = 0.4
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
fire_delay = 0.25 SECONDS
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/caliver/magharness
@@ -1237,10 +1206,11 @@
inhand_x_dimension = 64
inhand_y_dimension = 32
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/energy_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/energy_right_64.dmi',
)
ammo_level_icon = null
+ gun_skill_category = SKILL_HEAVY_WEAPONS
max_shots = 120
ammo_datum_type = /datum/ammo/energy/volkite/heavy
rounds_per_shot = 30
@@ -1249,11 +1219,11 @@
attachable_allowed = list(
/obj/item/attachable/magnetic_harness,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_WIELDED_FIRING_ONLY|GUN_SHOWS_LOADED
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_WIELDED_FIRING_ONLY|GUN_SHOWS_LOADED
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_DO_NOT_EJECT_HANDFULS|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
attachable_offset = list("muzzle_x" = 34, "muzzle_y" = 14,"rail_x" = 11, "rail_y" = 29, "under_x" = 23, "under_y" = 10, "stock_x" = 22, "stock_y" = 12)
aim_slowdown = 1
- wield_delay = 1.2 SECONDS
+ wield_delay = 1.4 SECONDS
fire_delay = 0.15 SECONDS
scatter = 3
accuracy_mult_unwielded = 0.4
diff --git a/code/modules/projectiles/guns/flamer.dm b/code/modules/projectiles/guns/flamer.dm
index 37df4a7cdaa8d..78dbe81dc5317 100644
--- a/code/modules/projectiles/guns/flamer.dm
+++ b/code/modules/projectiles/guns/flamer.dm
@@ -5,15 +5,20 @@
/obj/item/weapon/gun/flamer
name = "flamer"
desc = "flame go froosh"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 15
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
fire_sound = "gun_flamethrower"
dry_fire_sound = 'sound/weapons/guns/fire/flamethrower_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/flamethrower_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/flamethrower_reload.ogg'
muzzle_flash = null
aim_slowdown = 1.75
+ wield_delay = 0.4 SECONDS
general_codex_key = "flame weapons"
attachable_allowed = list( //give it some flexibility.
/obj/item/attachable/flashlight,
@@ -23,7 +28,6 @@
/obj/item/attachable/flamer_nozzle,
/obj/item/attachable/flamer_nozzle/wide,
/obj/item/attachable/flamer_nozzle/wide/red,
- /obj/item/attachable/shoulder_mount,
)
attachments_by_slot = list(
ATTACHMENT_SLOT_MUZZLE,
@@ -34,7 +38,7 @@
ATTACHMENT_SLOT_FLAMER_NOZZLE,
)
starting_attachment_types = list(/obj/item/attachable/flamer_nozzle)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY
gun_skill_category = SKILL_HEAVY_WEAPONS
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_DO_NOT_EJECT_HANDFULS|AMMO_RECIEVER_DO_NOT_EMPTY_ROUNDS_AFTER_FIRE
attachable_offset = list("rail_x" = 12, "rail_y" = 23, "flamer_nozzle_x" = 33, "flamer_nozzle_y" = 20)
@@ -67,7 +71,7 @@
///Gun based modifier for burn time. Percentage based.
var/burn_time_mod = 1
///Bitfield flags for flamer specific traits.
- var/flags_flamer_features = NONE
+ var/flamer_features_flags = NONE
///Overlay icon state of the pilot light.
var/lit_overlay_icon_state = "+lit"
///Pixel offset on the X axis for the pilot light overlay.
@@ -114,24 +118,24 @@
///Makes the sound of the flamer being lit, and applies the overlay.
/obj/item/weapon/gun/flamer/proc/light_pilot(light)
- if(!CHECK_BITFIELD(flags_flamer_features, FLAMER_IS_LIT) == !light) //!s so we can check equivalence on truthy, rather than true, values
+ if(!CHECK_BITFIELD(flamer_features_flags, FLAMER_IS_LIT) == !light) //!s so we can check equivalence on truthy, rather than true, values
return
if(light)
- ENABLE_BITFIELD(flags_flamer_features, FLAMER_IS_LIT)
+ ENABLE_BITFIELD(flamer_features_flags, FLAMER_IS_LIT)
turn_light(null, TRUE)
else
- DISABLE_BITFIELD(flags_flamer_features, FLAMER_IS_LIT)
+ DISABLE_BITFIELD(flamer_features_flags, FLAMER_IS_LIT)
turn_light(null, FALSE)
- playsound(src, CHECK_BITFIELD(flags_flamer_features, FLAMER_IS_LIT) ? 'sound/weapons/guns/interact/flamethrower_on.ogg' : 'sound/weapons/guns/interact/flamethrower_off.ogg', 25, 1)
+ playsound(src, CHECK_BITFIELD(flamer_features_flags, FLAMER_IS_LIT) ? 'sound/weapons/guns/interact/flamethrower_on.ogg' : 'sound/weapons/guns/interact/flamethrower_off.ogg', 25, 1)
- if(CHECK_BITFIELD(flags_flamer_features, FLAMER_NO_LIT_OVERLAY))
+ if(CHECK_BITFIELD(flamer_features_flags, FLAMER_NO_LIT_OVERLAY))
return
update_icon()
/obj/item/weapon/gun/flamer/update_overlays()
. = ..()
- if(!CHECK_BITFIELD(flags_flamer_features, FLAMER_IS_LIT)|| CHECK_BITFIELD(flags_flamer_features, FLAMER_NO_LIT_OVERLAY))
+ if(!CHECK_BITFIELD(flamer_features_flags, FLAMER_IS_LIT)|| CHECK_BITFIELD(flamer_features_flags, FLAMER_NO_LIT_OVERLAY))
return
var/image/lit_overlay = image(icon, src, lit_overlay_icon_state)
@@ -237,7 +241,7 @@
if(!length(turfs_to_burn) || !length(chamber_items))
return FALSE
- var/datum/ammo/flamethrower/loaded_ammo = CHECK_BITFIELD(flags_flamer_features, FLAMER_USES_GUN_FLAMES) ? ammo_datum_type : get_magazine_default_ammo(chamber_items[current_chamber_position])
+ var/datum/ammo/flamethrower/loaded_ammo = CHECK_BITFIELD(flamer_features_flags, FLAMER_USES_GUN_FLAMES) ? ammo_datum_type : get_magazine_default_ammo(chamber_items[current_chamber_position])
var/burn_level = initial(loaded_ammo.burnlevel) * burn_level_mod
var/burn_time = initial(loaded_ammo.burntime) * burn_time_mod
var/fire_color = initial(loaded_ammo.fire_color)
@@ -286,21 +290,22 @@
/obj/item/weapon/gun/flamer/big_flamer
name = "\improper FL-240 incinerator unit"
desc = "The FL-240 has proven to be one of the most effective weapons at clearing out soft-targets. This is a weapon to be feared and respected as it is quite deadly."
+ icon = 'icons/obj/items/guns/special.dmi'
icon_state = "m240"
item_state = "m240"
/obj/item/weapon/gun/flamer/som
name = "\improper V-62 incinerator"
desc = "The V-62 is a deadly weapon employed in close quarter combat, favoured as much for the terror it inspires as the actual damage it inflicts. It has good range for a flamer, but lacks the integrated extinguisher of its TGMC equivalent."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "v62"
item_state = "v62"
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_SHOWS_LOADED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_SHOWS_LOADED
inhand_x_dimension = 64
inhand_y_dimension = 32
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_64.dmi',
)
lit_overlay_icon_state = "v62_lit"
lit_overlay_offset_x = 0
@@ -310,6 +315,7 @@
default_ammo_type = /obj/item/ammo_magazine/flamer_tank/large/som
allowed_ammo_types = list(
/obj/item/ammo_magazine/flamer_tank/large/som,
+ /obj/item/ammo_magazine/flamer_tank/large/X/som,
/obj/item/ammo_magazine/flamer_tank/backtank,
/obj/item/ammo_magazine/flamer_tank/backtank/X,
)
@@ -344,14 +350,21 @@
)
starting_attachment_types = list(/obj/item/attachable/flamer_nozzle, /obj/item/attachable/stock/t84stock)
+/obj/item/weapon/gun/flamer/big_flamer/marinestandard/engineer/beginner
+ starting_attachment_types = list(
+ /obj/item/attachable/motiondetector,
+ /obj/item/attachable/flamer_nozzle,
+ /obj/item/attachable/stock/t84stock,
+ )
+
/obj/item/weapon/gun/flamer/mini_flamer
name = "mini flamethrower"
desc = "A weapon-mounted refillable flamethrower attachment.\nIt is designed for short bursts."
icon = 'icons/Marine/marine-weapons.dmi'
icon_state = "flamethrower"
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY
- flags_flamer_features = FLAMER_NO_LIT_OVERLAY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY
+ flamer_features_flags = FLAMER_NO_LIT_OVERLAY
w_class = WEIGHT_CLASS_BULKY
fire_delay = 2.5 SECONDS
fire_sound = 'sound/weapons/guns/fire/flamethrower3.ogg'
@@ -378,7 +391,7 @@
wield_delay_mod = 0.2 SECONDS
/obj/item/weapon/gun/flamer/mini_flamer/unremovable
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/weapon/gun/flamer/big_flamer/marinestandard
@@ -387,7 +400,7 @@
default_ammo_type = /obj/item/ammo_magazine/flamer_tank/large
icon_state = "tl84"
item_state = "tl84"
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_WIELDED_STABLE_FIRING_ONLY
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_WIELDED_STABLE_FIRING_ONLY
attachable_offset = list("rail_x" = 10, "rail_y" = 23, "stock_x" = 16, "stock_y" = 13, "flamer_nozzle_x" = 33, "flamer_nozzle_y" = 20, "under_x" = 24, "under_y" = 15)
attachable_allowed = list(
/obj/item/attachable/flashlight,
@@ -458,7 +471,8 @@
/turf/open/floor/plating/ground/snow/ignite(fire_lvl, burn_lvl, f_color, fire_stacks = 0, fire_damage = 0)
if(slayer > 0)
slayer -= 1
- update_icon(1, 0)
+ update_appearance()
+ update_sides()
return ..()
@@ -635,8 +649,8 @@ GLOBAL_LIST_EMPTY(flamer_particles)
slot = ATTACHMENT_SLOT_UNDER
attach_delay = 3 SECONDS
detach_delay = 3 SECONDS
- flags_gun_features = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY
- flags_flamer_features = FLAMER_NO_LIT_OVERLAY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY
+ flamer_features_flags = FLAMER_NO_LIT_OVERLAY
flame_max_wall_pen = 1 //Actually means we'll hit one wall and then stop
flame_max_wall_pen_wide = 1
diff --git a/code/modules/projectiles/guns/grenade_launchers.dm b/code/modules/projectiles/guns/grenade_launchers.dm
index ba92c58e18f80..8f2742e1e5338 100644
--- a/code/modules/projectiles/guns/grenade_launchers.dm
+++ b/code/modules/projectiles/guns/grenade_launchers.dm
@@ -7,14 +7,20 @@ The Grenade Launchers
/obj/item/weapon/gun/grenade_launcher
w_class = WEIGHT_CLASS_BULKY
- gun_skill_category = SKILL_FIREARMS
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_skill_category = SKILL_HEAVY_WEAPONS
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
reciever_flags = NONE
throw_speed = 2
throw_range = 10
force = 5
+ wield_delay = 0.4 SECONDS
caliber = CALIBER_40MM //codex
load_method = SINGLE_CASING //codex
+ icon = 'icons/obj/items/guns/special.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/grenadelauncher.ogg'
fire_rattle = 'sound/weapons/guns/fire/grenadelauncher.ogg'
cocked_sound = 'sound/weapons/guns/interact/m92_cocked.ogg'
@@ -37,6 +43,7 @@ The Grenade Launchers
/obj/item/explosive/grenade/smokebomb/som,
/obj/item/explosive/grenade/smokebomb/cloak,
/obj/item/explosive/grenade/smokebomb/drain,
+ /obj/item/explosive/grenade/smokebomb/antigas,
/obj/item/explosive/grenade/smokebomb/neuro,
/obj/item/explosive/grenade/smokebomb/acid,
/obj/item/explosive/grenade/smokebomb/satrapine,
@@ -51,11 +58,13 @@ The Grenade Launchers
/obj/item/explosive/grenade/chem_grenade,
/obj/item/explosive/grenade/chem_grenade/large,
/obj/item/explosive/grenade/chem_grenade/metalfoam,
- /obj/item/explosive/grenade/chem_grenade/razorburn_smol,
+ /obj/item/explosive/grenade/chem_grenade/razorburn_small,
/obj/item/explosive/grenade/chem_grenade/razorburn_large,
/obj/item/explosive/grenade/chem_grenade/incendiary,
/obj/item/explosive/grenade/chem_grenade/teargas,
/obj/item/explosive/grenade/flashbang/stun,
+ /obj/item/explosive/grenade/bullet/laser,
+ /obj/item/explosive/grenade/bullet/hefa,
)
reciever_flags = NONE
@@ -87,7 +96,7 @@ The Grenade Launchers
grenade_to_launch.throw_at(target, max_range, 3, (gun_user ? gun_user : loc))
if(fire_animation)
flick("[fire_animation]", src)
- if(CHECK_BITFIELD(flags_gun_features, GUN_SMOKE_PARTICLES))
+ if(CHECK_BITFIELD(gun_features_flags, GUN_SMOKE_PARTICLES))
var/firing_angle = Get_Angle(user_turf, target)
var/x_component = sin(firing_angle) * 40
var/y_component = cos(firing_angle) * 40
@@ -110,11 +119,11 @@ The Grenade Launchers
/obj/item/weapon/gun/grenade_launcher/multinade_launcher
name = "\improper GL-70 grenade launcher"
desc = "The GL-70 is the standard grenade launcher used by the TerraGov Marine Corps for area denial and big explosions."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "t70"
item_state = "t70"
fire_animation = "t70_fire"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
max_shells = 6 //codex
wield_delay = 1 SECONDS
fire_sound = 'sound/weapons/guns/fire/underbarrel_grenadelauncher.ogg'
@@ -131,6 +140,9 @@ The Grenade Launchers
fire_delay = 1.2 SECONDS
max_chamber_items = 5
+/obj/item/weapon/gun/grenade_launcher/multinade_launcher/beginner
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness)
+
/obj/item/weapon/gun/grenade_launcher/multinade_launcher/unloaded
default_ammo_type = null
@@ -150,7 +162,7 @@ The Grenade Launchers
slot = ATTACHMENT_SLOT_UNDER
attach_delay = 3 SECONDS
detach_delay = 3 SECONDS
- flags_gun_features = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
pixel_shift_x = 14
pixel_shift_y = 18
allowed_ammo_types = list(
@@ -166,6 +178,7 @@ The Grenade Launchers
/obj/item/explosive/grenade/smokebomb/som,
/obj/item/explosive/grenade/smokebomb/cloak,
/obj/item/explosive/grenade/smokebomb/drain,
+ /obj/item/explosive/grenade/smokebomb/antigas,
/obj/item/explosive/grenade/smokebomb/neuro,
/obj/item/explosive/grenade/smokebomb/acid,
/obj/item/explosive/grenade/smokebomb/satrapine,
@@ -181,7 +194,7 @@ The Grenade Launchers
wield_delay_mod = 0.2 SECONDS
/obj/item/weapon/gun/grenade_launcher/underslung/invisible
- flags_attach_features = NONE
+ attach_features_flags = NONE
/obj/item/weapon/gun/grenade_launcher/underslung/battle_rifle
name = "\improper BR-64 underslung grenade launcher"
@@ -193,11 +206,11 @@ The Grenade Launchers
/obj/item/weapon/gun/grenade_launcher/underslung/mpi
icon_state = "grenade_mpi"
- flags_attach_features = NONE
+ attach_features_flags = NONE
default_ammo_type = /obj/item/explosive/grenade/som
/obj/item/weapon/gun/grenade_launcher/underslung/mpi/removeable
- flags_attach_features = ATTACH_REMOVABLE
+ attach_features_flags = ATTACH_REMOVABLE
/obj/item/weapon/gun/grenade_launcher/single_shot
name = "\improper GL-81 grenade launcher"
@@ -205,11 +218,14 @@ The Grenade Launchers
icon_state = "m81"
item_state = "m81"
max_shells = 1 //codex
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
wield_delay = 0.2 SECONDS
aim_slowdown = 1
- flags_gun_features = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
- attachable_allowed = list()
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ attachable_allowed = list(
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/flashlight,
+ )
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 14, "rail_y" = 22, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
fire_delay = 1.05 SECONDS
max_chamber_items = 0
@@ -231,7 +247,7 @@ The Grenade Launchers
fire_sound = 'sound/weapons/guns/fire/flare.ogg'
fire_sound = 'sound/weapons/guns/fire/flare.ogg'
w_class = WEIGHT_CLASS_SMALL
- flags_gun_features = NONE
+ gun_features_flags = NONE
gun_skill_category = SKILL_PISTOLS
fire_delay = 0.5 SECONDS
default_ammo_type = /obj/item/explosive/grenade/flare
diff --git a/code/modules/projectiles/guns/mounted.dm b/code/modules/projectiles/guns/mounted.dm
index a0640ed6d9d5c..1d02ab6651e41 100644
--- a/code/modules/projectiles/guns/mounted.dm
+++ b/code/modules/projectiles/guns/mounted.dm
@@ -1,5 +1,5 @@
///box for storage of ammo and gun
-/obj/item/storage/box/tl102
+/obj/item/storage/box/hsg_102
name = "\improper HSG-102 crate"
desc = "A large and rusted metal case. It has not seen much use. Written in faded letters on its top, it says, \"This is a HSG-102 heavy smartgun\". There are many other warning labels atop that are too faded to read."
icon = 'icons/Marine/marine-hmg.dmi'
@@ -7,29 +7,33 @@
w_class = WEIGHT_CLASS_HUGE
storage_slots = 7
bypass_w_limit = list(
- /obj/item/weapon/gun/tl102,
- /obj/item/ammo_magazine/tl102,
+ /obj/item/weapon/gun/hsg_102,
+ /obj/item/ammo_magazine/hsg_102,
)
-/obj/item/storage/box/tl102/Initialize(mapload)
+/obj/item/storage/box/hsg_102/Initialize(mapload)
. = ..()
- new /obj/item/weapon/gun/tl102(src) //gun itself
- new /obj/item/ammo_magazine/tl102(src) //ammo for the gun
+ new /obj/item/weapon/gun/hsg_102(src) //gun itself
+ new /obj/item/ammo_magazine/hsg_102(src) //ammo for the gun
///HSG-102, now with full auto. It is not a superclass of deployed guns, however there are a few varients.
-/obj/item/weapon/gun/tl102
+/obj/item/weapon/gun/hsg_102
name = "\improper HSG-102 mounted heavy smartgun"
desc = "The HSG-102 heavy machinegun, it's too heavy to be wielded or operated without the tripod. IFF capable. No extra work required, just deploy it with Ctrl-Click. Can be repaired with a blowtorch once deployed."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "turret"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/misc_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/misc_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/hmg2.ogg'
reload_sound = 'sound/weapons/guns/interact/minigun_cocked.ogg'
- default_ammo_type = /obj/item/ammo_magazine/tl102
+ default_ammo_type = /obj/item/ammo_magazine/hsg_102
scatter = 10
deployed_scatter_change = -10
@@ -42,20 +46,20 @@
burst_accuracy_bonus = 1
burst_scatter_mult = 0
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list(
- /obj/item/attachable/scope/unremovable/tl102,
+ /obj/item/attachable/scope/unremovable/hsg_102,
)
starting_attachment_types = list(
- /obj/item/attachable/scope/unremovable/tl102,
+ /obj/item/attachable/scope/unremovable/hsg_102,
)
allowed_ammo_types = list(
- /obj/item/ammo_magazine/tl102,
+ /obj/item/ammo_magazine/hsg_102,
)
deploy_time = 5 SECONDS
@@ -66,27 +70,27 @@
soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, FIRE = 0, ACID = 20)
///Unmovable ship mounted version.
-/obj/item/weapon/gun/tl102/hsg_nest
+/obj/item/weapon/gun/hsg_102/hsg_nest
name = "\improper HSG-102 heavy smartgun nest"
desc = "A HSG-102 heavy smartgun mounted upon a small reinforced post with sandbags to provide a small machinegun nest for all your defense purpose needs."
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "entrenched"
- default_ammo_type = /obj/item/ammo_magazine/tl102/hsg_nest
+ default_ammo_type = /obj/item/ammo_magazine/hsg_102/hsg_nest
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
starting_attachment_types = list(
- /obj/item/attachable/scope/unremovable/tl102/nest,
+ /obj/item/attachable/scope/unremovable/hsg_102/nest,
)
allowed_ammo_types = list(
- /obj/item/ammo_magazine/tl102,
- /obj/item/ammo_magazine/tl102/hsg_nest,
+ /obj/item/ammo_magazine/hsg_102,
+ /obj/item/ammo_magazine/hsg_102/hsg_nest,
)
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, FIRE = 0, ACID = 0)
-/obj/item/weapon/gun/tl102/hsg_nest/sandless
+/obj/item/weapon/gun/hsg_102/hsg_nest/sandless
icon_state = "entrenched_sandless"
//-------------------------------------------------------
@@ -97,7 +101,7 @@
desc = "The MG-2005 mounted minigun is a gun simple in principle, it will shoot a lot of bullets really fast and will rip through xeno hordes."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "minigun"
caliber = CALIBER_762X51
@@ -113,16 +117,16 @@
windup_delay = 0.4 SECONDS
windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg'
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
actions_types = list(/datum/action/item_action/aim_mode)
aim_time = 2 SECONDS
aim_fire_delay = 0.05 SECONDS
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102)
- starting_attachment_types = list(/obj/item/attachable/scope/unremovable/tl102)
+ starting_attachment_types = list(/obj/item/attachable/scope/unremovable/hsg_102)
allowed_ammo_types = list(/obj/item/ammo_magazine/heavy_minigun)
@@ -140,11 +144,11 @@
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "minigun_nest"
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
- starting_attachment_types = list(/obj/item/attachable/scope/unremovable/tl102/nest,)
+ starting_attachment_types = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, FIRE = 0, ACID = 20)
@@ -155,9 +159,13 @@
name = "\improper ATR-22 mounted flak gun"
desc = "The ATR-22 is a recoiling barrel 20mm autocannon, created to be used against low flying targets, it is however able to engage ground targets at medium ranges with extreme efficency even if the recoil makes it near impossible to hit anything close by, its bullets will shred hard targets such as armored foes or walls. Both barrels can be fired at the same time rather than in sequence, but will incur large scatter penalties do so."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-ac.dmi'
icon_state = "autocannon"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/misc_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/misc_right_1.dmi',
+ )
fire_sound = "ac_fire"
reload_sound = 'sound/weapons/guns/interact/minigun_cocked.ogg'
@@ -171,8 +179,8 @@
burst_scatter_mult = 0.65
extra_delay = 1.5 SECONDS
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
attachable_allowed = list(/obj/item/attachable/scope/unremovable/standard_atgun)
@@ -202,9 +210,9 @@
desc = "The TE-9001 mounted heavy laser is a non-IFF heavy laser that is powerful enough to start a sizeable fire on its impact, this weapon is exceptional at area denial and has direct fire capability on the side."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-hmg.dmi'
- icon_state = "heavylaser"
+ icon_state = "heavylaser_deployed"
fire_sound = 'sound/weapons/guns/fire/tank_flamethrower.ogg'
reload_sound = 'sound/weapons/guns/interact/minigun_cocked.ogg'
@@ -216,13 +224,13 @@
deployed_scatter_change = -10
fire_delay = 0.7 SECONDS
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
- starting_attachment_types = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ starting_attachment_types = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
allowed_ammo_types = list(/obj/item/cell/lasgun/heavy_laser)
@@ -258,7 +266,7 @@
fire_sound = 'sound/weapons/guns/fire/Laser Rifle Standard.ogg'
message_to_user = "You set the heavy laser to burst fire mode."
fire_mode = GUN_FIREMODE_AUTOBURST
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "heavylaser"
description = "Fires a rapid pulse laser, dealing mediocre damage and shattering armor, but suffers from increased scatter and poorer falloff."
/datum/lasrifle/heavy_laser/ricochet
@@ -268,14 +276,14 @@
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
message_to_user = "You set the heavy laser to ricochet mode."
fire_mode = GUN_FIREMODE_SEMIAUTO
- icon_state = GUN_ICONSTATE_LOADED
+ icon_state = "heavylaser"
radial_icon_state = "laser_ricochet"
description = "Fires an experiment laser pulse capable of bouncing off many wall surfaces. The laser increases in potency when bouncing, before collapsing entirely after exceeding its threshold."
/obj/item/weapon/gun/energy/lasgun/lasrifle/heavy_laser/deployable
icon_state = "heavylaser_deployable"
- flags_item = IS_DEPLOYABLE|TWOHANDED
+ item_flags = IS_DEPLOYABLE|TWOHANDED
//-------------------------------------------------------
//FK-88 mounted heavy infantry support gun
@@ -285,7 +293,7 @@
desc = "The FK-88 is a big gun, offically meant to be used against large hostile wildlife or unruly crowds, this cannon will most definitely give a very bad day to anything that gets caught in its line of fire. Takes quite a while to dial in your shots. Uses 15cm shells."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-fkgun.dmi'
icon_state = "isg"
fire_sound = 'sound/weapons/guns/fire/tank_cannon1.ogg'
@@ -300,13 +308,13 @@
deployed_scatter_change = -10
fire_delay = 10 SECONDS
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE|DEPLOYED_ANCHORED_FIRING_ONLY
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE|DEPLOYED_ANCHORED_FIRING_ONLY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
- starting_attachment_types = list(/obj/item/attachable/scope/unremovable/tl102/nest)
+ starting_attachment_types = list(/obj/item/attachable/scope/unremovable/hsg_102/nest)
allowed_ammo_types = list(
/obj/item/ammo_magazine/heavy_isg/he,
@@ -328,7 +336,7 @@
pixel_y = -11
///This is my meme version, the first version of the HSG-102 to have auto-fire, revel in its presence.
-/obj/item/weapon/gun/tl102/death
+/obj/item/weapon/gun/hsg_102/death
name = "\improper \"Death incarnate\" heavy machine gun"
desc = "It looks like a regular HSG-102, however glowing archaeic writing glows faintly on its sides and top. It beckons for blood."
icon = 'icons/Marine/marine-hmg.dmi'
@@ -344,7 +352,7 @@
aim_slowdown = 3
wield_delay = 5 SECONDS
- flags_gun_features = GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
// This is a deployed IFF-less MACHINEGUN, has 500 rounds, drums do not fit anywhere but your belt slot and your back slot. But it has 500 rounds. That's nice.
@@ -352,9 +360,13 @@
name = "\improper HMG-08 heavy machinegun"
desc = "An absolute monster of a weapon, this is a watercooled heavy machinegun modernized by some crazy armorer with a wheeling kit included. Considering the mish mash of parts for the wheeling kit, you think its from another model of the gun. The pinnacle at holding a chokepoint. Holds 500 rounds of 10x28mm caseless in a box case. IS NOT IFF CAPABLE. Aiming carefully recommended. Can be repaired with a blowtorch once deployed. Alt Right click to unanchor and reanchor it."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "mg08"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/misc_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/misc_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/mg08.ogg'
reload_sound = 'sound/weapons/guns/interact/minigun_cocked.ogg'
@@ -370,8 +382,8 @@
burst_amount = 1
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list(
@@ -397,16 +409,20 @@
/obj/item/weapon/gun/standard_mmg
name = "\improper MG-27 medium machinegun"
desc = "The MG-27 is the SG-29s aging IFF-less cousin, made for rapid accurate machinegun fire in a short amount of time, you could use it while standing, not a great idea. Use the tripod for actual combat. It uses 10x27mm boxes."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
icon = 'icons/Marine/marine-mmg.dmi'
icon_state = "t27"
item_state = "t27"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
caliber = CALIBER_10x27_CASELESS // codex
max_shells = 150 //codex
force = 40
aim_slowdown = 1.2
- wield_delay = 2 SECONDS
+ wield_delay = 2.2 SECONDS
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg27.ogg'
fire_rattle = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg27_low.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
@@ -432,8 +448,8 @@
starting_attachment_types = list(/obj/item/attachable/stock/t27)
attachable_offset = list("muzzle_x" = 45, "muzzle_y" = 19,"rail_x" = 18, "rail_y" = 24, "under_x" = 28, "under_y" = 13, "stock_x" = 0, "stock_y" = 0)
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
deployable_item = /obj/machinery/deployable/mounted
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -466,8 +482,8 @@
icon_state = "ptrs"
item_state = "ptrs"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -481,7 +497,7 @@
hand_reload_sound = 'sound/weapons/guns/interact/shotgun_shell_insert.ogg'
cocked_sound = 'sound/weapons/guns/interact/shotgun_reload.ogg'
opened_sound = 'sound/weapons/guns/interact/shotgun_open.ogg'
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY
reciever_flags = AMMO_RECIEVER_HANDFULS
default_ammo_type = /datum/ammo/bullet/sniper/clf_heavyrifle
attachable_allowed = list(
@@ -495,8 +511,8 @@
starting_attachment_types = list(/obj/item/attachable/stock/clf_heavyrifle)
attachable_offset = list("muzzle_x" = 45, "muzzle_y" = 19,"rail_x" = 18, "rail_y" = 24, "under_x" = 28, "under_y" = 13, "stock_x" = 8, "stock_y" = 0)
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY
deployable_item = /obj/machinery/deployable/mounted
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -543,8 +559,8 @@
starting_attachment_types = list(/obj/item/attachable/scope/unremovable/standard_atgun)
attachable_allowed = list(/obj/item/attachable/scope/unremovable/standard_atgun)
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_ROTATE_ANCHORED|DEPLOYED_ANCHORED_FIRING_ONLY
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_ROTATE_ANCHORED|DEPLOYED_ANCHORED_FIRING_ONLY
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -617,9 +633,9 @@
/obj/item/weapon/gun/standard_agls
name = "\improper AGLS-37 Kauser automatic grenade launcher"
- desc = "The AGLS-37 automatic grenade launching IFF capable system, it's too heavy to be wielded or operated without the tripod. On the back, it reads: \"The Explosions and Fragmentation from this weapon ARE NOT friendly fire capable. Kauser is not obligated to buy you new body parts for you or your friends if you lose them.\"\nCan be deployed with Crtl-Click. It CANNOT be turned once deployed, due to a lack of swivels, pick it up to move your cone of fire. Can be repaired with a blowtorch once deployed."
+ desc = "The AGLS-37 automatic grenade launching IFF capable system, it's too heavy to be wielded or operated without the tripod. On the back, it reads: \"The Explosions and Fragmentation from this weapon ARE NOT friendly fire capable. Kauser is not obligated to buy you new body parts for you or your friends if you lose them.\"\nCan be deployed with Crtl-Click. Can be repaired with a blowtorch once deployed."
w_class = WEIGHT_CLASS_HUGE
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
caliber = CALIBER_40MM
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "ags"
@@ -630,8 +646,8 @@
fire_delay = 1.1 SECONDS
burst_amount = 0
accuracy_mult = 1.2 //it's got a bipod
- flags_item = IS_DEPLOYABLE|TWOHANDED
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list(
@@ -667,3 +683,57 @@
gun_user?.record_war_crime()
+// Non-TGMC HMG
+
+/obj/item/weapon/gun/icc_hmg
+ name = "\improper KRD-61ES mounted heavy machinegun"
+ desc = "The KRD-61ES machinegun is the export variant of the ML-91 HMG. It's too heavy to be wielded or operated without the tripod. No extra work required, just deploy it with Ctrl-Click. Can be repaired with a blowtorch once deployed."
+ icon = 'icons/Marine/marine-mmg.dmi'
+ icon_state = "kord"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/misc_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/misc_right_1.dmi',
+ )
+
+ fire_sound = 'sound/weapons/guns/fire/hmg2.ogg'
+ reload_sound = 'sound/weapons/guns/interact/minigun_cocked.ogg'
+
+ w_class = WEIGHT_CLASS_HUGE
+ equip_slot_flags = ITEM_SLOT_BACK
+
+ scatter = 10
+ deployed_scatter_change = -10
+ accuracy_mult = 1.2 //it's got a bipod
+ fire_delay = 0.25 SECONDS
+
+ default_ammo_type = /obj/item/ammo_magazine/icc_hmg
+
+ allowed_ammo_types = list(
+ /obj/item/ammo_magazine/icc_hmg,
+ )
+
+ item_flags = IS_DEPLOYABLE|TWOHANDED
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+ actions_types = list(/datum/action/item_action/aim_mode)
+ aim_fire_delay = 0.05 SECONDS
+ aim_speed_modifier = 5
+
+ attachable_allowed = list(
+ /obj/item/attachable/scope/unremovable/hsg_102,
+ )
+
+ starting_attachment_types = list(
+ /obj/item/attachable/scope/unremovable/hsg_102,
+ )
+
+ deploy_time = 1.5 SECONDS
+ undeploy_time = 0.5 SECONDS
+ deployable_item = /obj/machinery/deployable/mounted
+
+ max_integrity = 200
+ soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, FIRE = 0, ACID = 20)
+
+ allowed_ammo_types = list(
+ /obj/item/ammo_magazine/icc_hmg,
+ )
diff --git a/code/modules/projectiles/guns/pistols.dm b/code/modules/projectiles/guns/pistols.dm
index 856b4117cb6a9..1c61ae7abf681 100644
--- a/code/modules/projectiles/guns/pistols.dm
+++ b/code/modules/projectiles/guns/pistols.dm
@@ -2,18 +2,23 @@
//--------------------------------------------------
/obj/item/weapon/gun/pistol
+ icon = 'icons/obj/items/guns/pistols.dmi'
icon_state = "" //Defaults to revolver pistol when there's no sprite.
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/pistols_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/pistols_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/pistol.ogg'
unload_sound = 'sound/weapons/guns/interact/pistol_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/pistol_reload.ogg'
cocked_sound = 'sound/weapons/guns/interact/pistol_cocked.ogg'
muzzleflash_iconstate = "muzzle_flash_light"
load_method = MAGAZINE //codex
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
force = 6
movement_acc_penalty_mult = 2
- wield_delay = 0.2 SECONDS //If you modify your pistol to be two-handed, it will still be fast to aim
+ wield_delay = 0.4 SECONDS
type_of_casings = "bullet"
gun_skill_category = SKILL_PISTOLS
attachable_allowed = list(
@@ -31,7 +36,7 @@
/obj/item/attachable/buildasentry,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
actions_types = list(/datum/action/item_action/aim_mode) // all pistols can aim mode
aim_speed_modifier = 0.65
scatter = -2
@@ -47,18 +52,12 @@
/obj/item/weapon/gun/pistol/standard_pistol
name = "\improper P-14 pistol"
desc = "The P-14, produced by Terran Armories. A reliable sidearm that loads 9x19mm Parabellum Auto munitions. Capable of mounting a limited amount of attachments, and firing at a respectable rate of fire, often as fast as you can pull the trigger. Takes 21-round 9mm magazines."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tp14"
+ item_state = "tp14"
caliber = CALIBER_9X19 //codex
max_shells = 21 //codex
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_p14.ogg'
reload_sound = 'sound/weapons/guns/interact/tp14_reload.ogg'
- greyscale_config = /datum/greyscale_config/gun/pistol
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tp14,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tp14,
- )
default_ammo_type = /obj/item/ammo_magazine/pistol/standard_pistol
allowed_ammo_types = list(/obj/item/ammo_magazine/pistol/standard_pistol)
@@ -70,30 +69,28 @@
scatter_unwielded = 4
recoil = -2
recoil_unwielded = -2
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 4
+ akimbo_scatter_mod = 8
//-------------------------------------------------------
//PP-7 Plasma Pistol
/obj/item/weapon/gun/pistol/plasma_pistol
name = "\improper PP-7 plasma pistol"
desc = "An experimental weapon designed to set the terrain and targets on fire. It hums with power as magnetic fields coil round each other."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tx7"
+ item_state = "tx7"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/energy_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/energy_right_1.dmi',
+ )
caliber = CALIBER_PLASMA
max_shots = 10
+ icon = 'icons/obj/items/guns/energy.dmi'
reload_sound = 'sound/weapons/guns/interact/tp14_reload.ogg'
fire_sound = 'sound/weapons/guns/fire/laser3.ogg'
default_ammo_type = /obj/item/ammo_magazine/pistol/plasma_pistol
allowed_ammo_types = list(/obj/item/ammo_magazine/pistol/plasma_pistol)
type_of_casings = null
attachable_offset = list("muzzle_x" = 29, "muzzle_y" = 20,"rail_x" = 13, "rail_y" = 23, "under_x" = 19, "under_y" = 13, "stock_x" = 21, "stock_y" = 17)
- greyscale_config = /datum/greyscale_config/gun/pistol/tx7
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tx7,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tx7,
- )
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/flashlight,
@@ -101,16 +98,15 @@
/obj/item/attachable/gyro,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/scope/marine,
/obj/item/weapon/gun/shotgun/combat/masterkey,
)
muzzleflash_iconstate = "muzzle_flash_laser"
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_ENERGY|GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_DO_NOT_EJECT_HANDFULS|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
actions_types = list()
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
muzzle_flash_color = COLOR_GREEN
fire_delay = 1.5 SECONDS
@@ -128,6 +124,9 @@
placed_overlay_iconstate = "tx7"
+/obj/item/weapon/gun/pistol/plasma_pistol/beginner
+ starting_attachment_types = list(/obj/item/weapon/gun/shotgun/combat/masterkey, /obj/item/attachable/reddot, /obj/item/attachable/lasersight)
+
/obj/item/weapon/gun/pistol/plasma_pistol/can_attach(obj/item/attaching_to, mob/attacher)
if(!attachments_by_slot[ATTACHMENT_SLOT_RAIL])
return TRUE
@@ -135,11 +134,11 @@
return FALSE
/obj/item/weapon/gun/pistol/plasma_pistol/on_attach(obj/item/attached_to, mob/user)
- flags_gun_features |= (GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY)
+ gun_features_flags |= (GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY)
return ..()
/obj/item/weapon/gun/pistol/plasma_pistol/on_detach(obj/item/attached_to, mob/user)
- flags_gun_features &= ~(GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY)
+ gun_features_flags &= ~(GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY)
return ..()
/obj/item/weapon/gun/pistol/plasma_pistol/guardsman_pistol
@@ -179,20 +178,14 @@
/obj/item/weapon/gun/pistol/standard_heavypistol
name = "\improper P-23 service pistol"
desc = "A standard P-23 chambered in .45 ACP. Has a smaller magazine capacity, but packs a better punch. Has an irremovable laser sight. Uses .45 magazines."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tp23"
+ item_state = "tp23"
caliber = CALIBER_45ACP //codex
max_shells = 14 //codex
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_p23.ogg'
unload_sound = 'sound/weapons/guns/interact/colt_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/colt_reload.ogg'
cocked_sound = 'sound/weapons/guns/interact/colt_cocked.ogg'
- greyscale_config = /datum/greyscale_config/gun/pistol/tp23
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tp23,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tp23,
- )
default_ammo_type = /obj/item/ammo_magazine/pistol/standard_heavypistol
allowed_ammo_types = list(/obj/item/ammo_magazine/pistol/standard_heavypistol)
attachable_allowed = list(
@@ -204,10 +197,9 @@
/obj/item/attachable/heavy_barrel,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 31, "muzzle_y" = 22,"rail_x" = 13, "rail_y" = 24, "under_x" = 21, "under_y" = 17, "stock_x" = 21, "stock_y" = 17)
fire_delay = 0.2 SECONDS
@@ -215,7 +207,6 @@
accuracy_mult_unwielded = 0.95
recoil = -2
recoil_unwielded = -2
- lower_akimbo_accuracy = 2
/obj/item/weapon/gun/pistol/standard_heavypistol/suppressed
starting_attachment_types = list(/obj/item/attachable/suppressor, /obj/item/attachable/flashlight) //Tacticool
@@ -225,6 +216,10 @@
/obj/item/weapon/gun/pistol/standard_heavypistol/tactical
starting_attachment_types = list(/obj/item/attachable/reddot)
+
+/obj/item/weapon/gun/pistol/standard_heavypistol/beginner
+ starting_attachment_types = list(/obj/item/attachable/lace, /obj/item/attachable/reddot)
+
//-------------------------------------------------------
//P-1911
@@ -248,7 +243,6 @@
accuracy_mult_unwielded = 0.85
damage_mult = 1.15
recoil = -2
- lower_akimbo_accuracy = 2
/obj/item/weapon/gun/pistol/m1911/custom
name = "\improper P-1911A1 custom pistol"
@@ -262,9 +256,8 @@
/obj/item/attachable/quickfire,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
fire_delay = 0.15 SECONDS
damage_mult = 1.3
@@ -342,10 +335,9 @@
/obj/item/attachable/flashlight/under,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 31, "muzzle_y" = 19,"rail_x" = 9, "rail_y" = 23, "under_x" = 22, "under_y" = 14, "stock_x" = 20, "stock_y" = 17)
fire_delay = 0.45 SECONDS
@@ -388,10 +380,9 @@
/obj/item/attachable/buildasentry,
/obj/item/attachable/flashlight/under,
/obj/item/attachable/suppressor/unremovable/invisible,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 19,"rail_x" = 10, "rail_y" = 22, "under_x" = 21, "under_y" = 18, "stock_x" = 21, "stock_y" = 18)
//Making the gun have an invisible silencer since it's supposed to have one.
starting_attachment_types = list(/obj/item/attachable/suppressor/unremovable/invisible)
@@ -431,7 +422,7 @@
/obj/item/attachable/lace,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 25, "muzzle_y" = 20,"rail_x" = 12, "rail_y" = 22, "under_x" = 17, "under_y" = 15, "stock_x" = 22, "stock_y" = 17)
fire_delay = 0.15 SECONDS
@@ -459,7 +450,7 @@
/obj/item/attachable/lace,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 28, "muzzle_y" = 20,"rail_x" = 10, "rail_y" = 22, "under_x" = 17, "under_y" = 15, "stock_x" = 22, "stock_y" = 17)
fire_delay = 0.15 SECONDS
@@ -487,7 +478,7 @@
allowed_ammo_types = list(/obj/item/ammo_magazine/pistol/highpower)
force = 10
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 27, "muzzle_y" = 20,"rail_x" = 8, "rail_y" = 22, "under_x" = 18, "under_y" = 15, "stock_x" = 16, "stock_y" = 15)
fire_delay = 0.45 SECONDS
@@ -542,12 +533,14 @@
aim_slowdown = 0.2
scatter = 0
scatter_unwielded = 6
- lower_akimbo_accuracy = 2
akimbo_additional_delay = 2
/obj/item/weapon/gun/pistol/vp70/tactical
starting_attachment_types = list(/obj/item/attachable/reddot, /obj/item/attachable/lasersight, /obj/item/attachable/compensator)
+/obj/item/weapon/gun/pistol/vp70/beginner
+ starting_attachment_types = list(/obj/item/attachable/reddot, /obj/item/attachable/lasersight, /obj/item/attachable/lace)
+
//-------------------------------------------------------
//VP78
@@ -664,7 +657,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
desc = "The PL-5 is a true and tested ICCAF handgun, used for a very long time with minimal changes to the core design, best used at close quarters with its higher than usual magazine size for its caliber. It is chambered in .45 ACP."
icon_state = "pl5"
item_state = "pl5"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/pistols64.dmi'
caliber = CALIBER_45ACP //codex
max_shells = 18 //codex
fire_sound = 'sound/weapons/guns/fire/colt.ogg'
@@ -701,7 +694,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
type_of_casings = null
gun_skill_category = SKILL_PISTOLS
attachable_allowed = list()
- flags_gun_features = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
fire_delay = 0.3 SECONDS
burst_delay = 0.2 SECONDS
@@ -716,7 +709,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
reload_sound = 'sound/weapons/flipblade.ogg'
cocked_sound = 'sound/weapons/guns/interact/pistol_cocked.ogg'
caliber = CALIBER_ALIEN
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
force = 30
movement_acc_penalty_mult = 3
@@ -753,7 +746,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
/obj/item/weapon/gun/pistol/smart_pistol
name = "\improper SP-13 smart pistol"
desc = "The SP-13 is a IFF-capable sidearm used by the TerraGov Marine Corps. A cutting-edge miniaturization technology allows mounting of a KTLD IFF system on the pistol, albeit at high manufactoring cost and the usual specialized training required to use such a pistol. Unique design feature high-capacity mag on top of the barrel, with integrated sight."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/pistols64.dmi'
icon_state = "sp13"
item_state = "sp13"
caliber = CALIBER_9X19 //codex
@@ -773,7 +766,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
/obj/item/attachable/lace,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
gun_skill_category = SKILL_SMARTGUN
actions_types = list() // Inherits aimmode, but has IFF so..
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_SEMIAUTO)
@@ -781,7 +774,7 @@ It is a modified Beretta 93R, and can fire three round burst or single fire. Whe
attachable_offset = list("muzzle_x" = 29, "muzzle_y" = 20,"rail_x" = 13, "rail_y" = 23, "under_x" = 19, "under_y" = 13, "stock_x" = 21, "stock_y" = 17)
aim_slowdown = 0.2
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
fire_delay = 0.2 SECONDS
accuracy_mult = 1.2
accuracy_mult_unwielded = 0.85
diff --git a/code/modules/projectiles/guns/plasma.dm b/code/modules/projectiles/guns/plasma.dm
new file mode 100644
index 0000000000000..6bbbfe5b43656
--- /dev/null
+++ b/code/modules/projectiles/guns/plasma.dm
@@ -0,0 +1,274 @@
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma
+ name = "generic plasma weapon"
+ icon = 'icons/obj/items/guns/plasma64.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/plasma_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/plasma_right_1.dmi',
+ )
+ default_ammo_type = /obj/item/cell/lasgun/plasma
+ allowed_ammo_types = list(/obj/item/cell/lasgun/plasma)
+ heat_per_fire = 5
+ muzzle_flash_color = COLOR_DISABLER_BLUE
+ muzzleflash_iconstate = "muzzle_flash_pulse"
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING
+ accuracy_mult = 1
+ accuracy_mult_unwielded = 0.5
+ scatter = 4
+ scatter_unwielded = 35
+ movement_acc_penalty_mult = 5
+ damage_falloff_mult = 0.25
+ overheat_multiplier = 0.5
+ cool_amount = 9
+ ammo_level_icon = null
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle
+ name = "\improper PL-38 plasma rifle"
+ desc = "The PL-38 Plasma Rifle is an experimental addition to the TerraGov Marine Corps arsenal, rumored to be the child of some back door contract deals, it is a versatile weapon if you mind the rather cheap cooling systems. It has a normal beam mode similar to a rifle, a hipower mode that easily pierces through soft targets, and a blast mode that will easily melt through the armor of anything hit by it."
+ icon_state = "plasma_rifle"
+ item_state = "plasma_rifle"
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_med.ogg'
+ unload_sound = 'sound/weapons/guns/interact/plasma_unload_3.ogg'
+ reload_sound = 'sound/weapons/guns/interact/plasma_reload_2.ogg'
+
+ wield_delay = 0.7 SECONDS
+ aim_slowdown = 0.5
+
+ accuracy_mult = 1.15
+ scatter = 0
+
+ fire_delay = 0.2 SECONDS
+ heat_per_fire = 3
+ rounds_per_shot = 12
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ ammo_datum_type = /datum/ammo/energy/plasma/rifle_standard
+ force = 20
+ mode_list = list(
+ "Standard" = /datum/lasrifle/base/plasma_rifle/rifle_standard,
+ "Piercing" = /datum/lasrifle/base/plasma_rifle/rifle_marksman,
+ "Blast" = /datum/lasrifle/base/plasma_rifle/rifle_blast,
+ )
+ attachable_offset = list("muzzle_x" = 50, "muzzle_y" = 16,"rail_x" = 25, "rail_y" = 25, "under_x" = 37, "under_y" = 10, "stock_x" = 0, "stock_y" = 13)
+ attachable_allowed = list(
+ /obj/item/attachable/bayonet,
+ /obj/item/attachable/bayonetknife,
+ /obj/item/attachable/bayonetknife/som,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/lasersight,
+ /obj/item/attachable/flashlight,
+ /obj/item/attachable/flashlight/under,
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/angledgrip,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/scope/marine,
+ /obj/item/attachable/scope/mini,
+ /obj/item/weapon/gun/shotgun/combat/masterkey,
+ /obj/item/weapon/gun/flamer/mini_flamer,
+ /obj/item/weapon/gun/grenade_launcher/underslung,
+ /obj/item/attachable/motiondetector,
+ /obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
+ )
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/standard
+ starting_attachment_types = list(
+ /obj/item/weapon/gun/flamer/mini_flamer,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/bayonet,
+ )
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle/v_grip
+ starting_attachment_types = list(
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/bayonet,
+ )
+
+/datum/lasrifle/base/plasma_rifle/rifle_standard
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_med.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/rifle_standard
+ icon_state = "plasma_rifle"
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 0.2 SECONDS
+ heat_per_fire = 3
+ rounds_per_shot = 12
+ radial_icon_state = "plasma_weak"
+ message_to_user = "You set the plasma rifle's charge mode to standard fire."
+
+/datum/lasrifle/base/plasma_rifle/rifle_marksman
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_heavy.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/rifle_marksman
+ icon_state = "plasma_rifle"
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 0.6 SECONDS
+ heat_per_fire = 12
+ rounds_per_shot = 48
+ radial_icon_state = "plasma_strong"
+ message_to_user = "You set the plasma rifle's charge mode to piercing fire."
+
+/datum/lasrifle/base/plasma_rifle/rifle_blast
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_blast.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/blast/melting
+ icon_state = "plasma_rifle"
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 1.5 SECONDS
+ heat_per_fire = 33
+ rounds_per_shot = 100
+ radial_icon_state = "plasma_multi"
+ message_to_user = "You set the plasma rifle's charge mode to blast fire."
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/cannon
+ name = "\improper PL-96 plasma cannon"
+ desc = "The PL-96 Plasma Cannon is an experimental addition to the TerraGov Marine Corps arsenal, rumored to be the child of some back door contract deals, is an absolutely incredibly devastating weapon to behold... if you mind the incredibly poor cooling mechanisms and unwieldiness of the whole package. It has a normal beam mode similar to a machinegun, a fire glob mode that leaves devastating flames in the aftermath, and a Charge mode nicknamed the 'Femur breaker' due to its incredible armor shattering potiential upon hitting a target."
+ icon_state = "plasma_cannon"
+ item_state = "plasma_cannon"
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY
+ gun_skill_category = SKILL_HEAVY_WEAPONS
+
+ aim_slowdown = 1.2
+ wield_delay = 1.7 SECONDS
+ movement_acc_penalty_mult = 7
+
+ accuracy_mult = 1
+ accuracy_mult_unwielded = 0.5
+ scatter = 2
+
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_heavy.ogg'
+ unload_sound = 'sound/weapons/guns/interact/plasma_unload_2.ogg'
+ reload_sound = 'sound/weapons/guns/interact/plasma_reload_1.ogg'
+ force = 35
+ ammo_datum_type = /datum/ammo/energy/plasma/cannon_heavy
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 2 SECONDS
+ heat_per_fire = 50
+ rounds_per_shot = 180
+ windup_delay = 0.5 SECONDS
+ mode_list = list(
+ "Standard" = /datum/lasrifle/base/plasma_cannon/cannon_standard,
+ "Shatter" = /datum/lasrifle/base/plasma_cannon/shatter_blast,
+ "Incendiary" = /datum/lasrifle/base/plasma_cannon/incendiary_blast,
+ )
+ attachable_offset = list("muzzle_x" = 49, "muzzle_y" = 16,"rail_x" = 25, "rail_y" = 26, "under_x" = 42, "under_y" = 11, "stock_x" = 0, "stock_y" = 13)
+ attachable_allowed = list(
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/magnetic_harness,
+ )
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/cannon/mag_harness
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness)
+
+/datum/lasrifle/base/plasma_cannon/cannon_standard
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_heavy.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/cannon_heavy
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 2 SECONDS
+ heat_per_fire = 50
+ rounds_per_shot = 180
+ windup_delay = 0.5 SECONDS
+ icon_state = "plasma_cannon"
+ radial_icon_state = "plasma_cannon"
+ message_to_user = "You set the plasma cannon's charge mode to standard."
+
+/datum/lasrifle/base/plasma_cannon/shatter_blast
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_blast.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/blast/shatter
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 1.5 SECONDS
+ heat_per_fire = 45
+ rounds_per_shot = 150
+ windup_delay = 0.5 SECONDS
+ icon_state = "plasma_cannon"
+ radial_icon_state = "plasma_fire"
+ message_to_user = "You set the gun's charge mode to shatter."
+
+/datum/lasrifle/base/plasma_cannon/incendiary_blast
+ fire_sound = 'sound/weapons/guns/fire/flamethrower3.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/blast/incendiary
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 1.5 SECONDS
+ heat_per_fire = 40
+ rounds_per_shot = 100
+ windup_delay = 0.5 SECONDS
+ icon_state = "plasma_cannon"
+ radial_icon_state = "plasma_strong"
+ message_to_user = "You set the plasma cannon's charge mode to incendiary."
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg
+ name = "\improper PL-51 plasma SMG"
+ desc = "The PL-51 Plasma SMG, ."
+ icon_state = "plasma_smg"
+ item_state = "plasma_smg"
+ gun_skill_category = SKILL_SMGS
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_fast.ogg'
+ unload_sound = 'sound/weapons/guns/interact/plasma_unload_3.ogg'
+ reload_sound = 'sound/weapons/guns/interact/plasma_reload_3.ogg'
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_fast.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/smg_standard/four
+
+ wield_delay = 0.3 SECONDS
+ aim_slowdown = 0.25
+ movement_acc_penalty_mult = 3
+
+ accuracy_mult = 1.1
+ accuracy_mult_unwielded = 0.7
+ scatter = 6
+ scatter_unwielded = 12
+
+ damage_falloff_mult = 0.75
+
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 0.15 SECONDS
+ heat_per_fire = 3
+ rounds_per_shot = 12
+ mode_list = list(
+ "Standard" = /datum/lasrifle/base/plasma_smg/smg_standard,
+ "Overcharge" = /datum/lasrifle/base/plasma_smg/smg_overcharge,
+ )
+ attachable_offset = list("muzzle_x" = 43, "muzzle_y" = 17,"rail_x" = 25, "rail_y" = 25, "under_x" = 33, "under_y" = 11, "stock_x" = 0, "stock_y" = 13)
+ attachable_allowed = list(
+ /obj/item/attachable/bayonet,
+ /obj/item/attachable/bayonetknife,
+ /obj/item/attachable/bayonetknife/som,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/lasersight,
+ /obj/item/attachable/flashlight,
+ /obj/item/attachable/flashlight/under,
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/angledgrip,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/motiondetector,
+ )
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/standard
+ starting_attachment_types = list(
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/bayonet,
+ )
+
+/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg/motion_sensor
+ starting_attachment_types = list(
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/motiondetector,
+ /obj/item/attachable/bayonet,
+ )
+
+/datum/lasrifle/base/plasma_smg/smg_standard
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_fast.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/smg_standard/four
+ icon_state = "plasma_smg"
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 0.15 SECONDS
+ heat_per_fire = 3
+ rounds_per_shot = 12
+ radial_icon_state = "plasma_bouncy"
+ message_to_user = "You set the guns's firemode to standard fire."
+
+/datum/lasrifle/base/plasma_smg/smg_overcharge
+ fire_sound = 'sound/weapons/guns/fire/plasma_fire_heavy.ogg'
+ ammo_datum_type = /datum/ammo/energy/plasma/blast
+ icon_state = "plasma_smg"
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ fire_delay = 1 SECONDS
+ heat_per_fire = 25
+ rounds_per_shot = 90
+ radial_icon_state = "plasma_cannon"
+ message_to_user = "You set the guns's firemode to overcharge."
diff --git a/code/modules/projectiles/guns/revolvers.dm b/code/modules/projectiles/guns/revolvers.dm
index d1510026fd017..db6f85b273aff 100644
--- a/code/modules/projectiles/guns/revolvers.dm
+++ b/code/modules/projectiles/guns/revolvers.dm
@@ -2,21 +2,26 @@
//---------------------------------------------------
/obj/item/weapon/gun/revolver
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/pistols_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/pistols_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/44mag.ogg'
reload_sound = 'sound/weapons/guns/interact/revolver_spun.ogg'
cocked_sound = 'sound/weapons/guns/interact/revolver_cocked.ogg'
unload_sound = 'sound/weapons/guns/interact/revolver_unload.ogg'
+ icon = 'icons/obj/items/guns/pistols.dmi'
muzzleflash_iconstate = "muzzle_flash_medium"
hand_reload_sound = 'sound/weapons/guns/interact/revolver_load.ogg'
type_of_casings = "bullet"
load_method = SINGLE_CASING|SPEEDLOADER //codex
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_SMOKE_PARTICLES
actions_types = list(/datum/action/item_action/aim_mode)
aim_speed_modifier = 0.75
aim_fire_delay = 0.25 SECONDS
- wield_delay = 0.2 SECONDS //If you modify your revolver to be two-handed, it will still be fast to aim
+ wield_delay = 0.4 SECONDS
gun_skill_category = SKILL_PISTOLS
reciever_flags = AMMO_RECIEVER_HANDFULS|AMMO_RECIEVER_ROTATES_CHAMBER|AMMO_RECIEVER_TOGGLES_OPEN|AMMO_RECIEVER_TOGGLES_OPEN_EJECTS
@@ -60,20 +65,14 @@
/obj/item/weapon/gun/revolver/standard_revolver
name = "\improper R-44 combat revolver"
desc = "The R-44 standard combat revolver, produced by Terran Armories. A sturdy and hard hitting firearm that loads .44 Magnum rounds. Holds 7 rounds in the cylinder. Due to an error in the cylinder rotation system the fire rate of the gun is much faster than intended, it ended up being billed as a feature of the system."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tp44"
+ item_state = "tp44"
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_r44.ogg'
caliber = CALIBER_44 //codex
max_chamber_items = 7 //codex
default_ammo_type = /obj/item/ammo_magazine/revolver/standard_revolver
allowed_ammo_types = list(/obj/item/ammo_magazine/revolver/standard_revolver)
force = 8
- greyscale_config = /datum/greyscale_config/gun/revolver
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tp44,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tp44,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/reddot,
@@ -85,7 +84,6 @@
/obj/item/attachable/lasersight,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 19,"rail_x" = 13, "rail_y" = 23, "under_x" = 22, "under_y" = 14, "stock_x" = 22, "stock_y" = 19)
fire_delay = 0.15 SECONDS
@@ -184,7 +182,6 @@
/obj/item/attachable/compensator,
/obj/item/attachable/lace,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 19,"rail_x" = 8, "rail_y" = 23, "under_x" = 24, "under_y" = 15, "stock_x" = 22, "stock_y" = 15)
@@ -281,7 +278,7 @@
/obj/item/weapon/gun/revolver/standard_magnum
name = "\improper R-76 KC magnum"
desc = "The R-76 magnum is an absolute beast of a handgun used by the TGMC, rumors say it was created as a money laundering scheme by some general due to the sheer inpracticality of this firearm. Hits hard, recommended to be used with its stock attachment. Chambered in 12.7mm."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/pistols64.dmi'
icon_state = "t76"
item_state = "t76"
fire_animation = "t76_fire"
@@ -299,7 +296,6 @@
/obj/item/attachable/extended_barrel,
/obj/item/attachable/lasersight,
/obj/item/attachable/lace,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/stock/t76,
/obj/item/attachable/scope/standard_magnum,
)
@@ -329,7 +325,6 @@
/obj/item/attachable/extended_barrel,
/obj/item/attachable/lasersight,
/obj/item/attachable/lace,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/stock/t76,
/obj/item/attachable/scope/standard_magnum,
/obj/item/attachable/compensator,
diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm
index 1b6719038e0f8..03f58e680eab4 100644
--- a/code/modules/projectiles/guns/rifles.dm
+++ b/code/modules/projectiles/guns/rifles.dm
@@ -1,15 +1,16 @@
//-------------------------------------------------------
/obj/item/weapon/gun/rifle
+ icon = 'icons/obj/items/guns/rifles.dmi'
reload_sound = 'sound/weapons/guns/interact/rifle_reload.ogg'
cocked_sound = 'sound/weapons/guns/interact/cocked.ogg'
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 15
- flags_gun_features = GUN_CAN_POINTBLANK||GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK||GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
load_method = MAGAZINE //codex
aim_slowdown = 0.35
- wield_delay = 0.6 SECONDS
+ wield_delay = 0.8 SECONDS
gun_skill_category = SKILL_RIFLES
burst_amount = 3
@@ -19,8 +20,7 @@
scatter_unwielded = 13
recoil_unwielded = 4
damage_falloff_mult = 0.5
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
+ akimbo_scatter_mod = 8
//-------------------------------------------------------
//AR-18 Carbine
@@ -28,8 +28,8 @@
/obj/item/weapon/gun/rifle/standard_carbine
name = "\improper AR-18 Kauser carbine"
desc = "The Keckler and Hoch AR-18 carbine is one of the standard rifles used by the TerraGov Marine Corps. It's commonly used by people who prefer greater mobility in combat, like scouts and other light infantry. Uses 10x24mm caseless ammunition."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "t18"
+ item_state = "t18"
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_ar18.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/t18_unload.ogg'
@@ -38,15 +38,7 @@
max_shells = 36 //codex
force = 20
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine
- allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_carbine)
- greyscale_config = /datum/greyscale_config/gun
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t18,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t18,
- slot_back_str = /datum/greyscale_config/worn_gun/t18,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t18,
- )
+ allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_carbine, /obj/item/ammo_magazine/rifle/standard_carbine/ap)
attachable_allowed = list(
/obj/item/attachable/stock/t18stock,
/obj/item/attachable/reddot,
@@ -76,11 +68,10 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/weapon/gun/energy/lasgun/lasrifle/pocket_beam, //RUTGMC EDIT
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(/obj/item/attachable/stock/t18stock)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 16,"rail_x" = 5, "rail_y" = 19, "under_x" = 18, "under_y" = 14, "stock_x" = 0, "stock_y" = 13)
@@ -108,19 +99,25 @@
starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/weapon/gun/grenade_launcher/underslung, /obj/item/attachable/motiondetector, /obj/item/attachable/extended_barrel)
/obj/item/weapon/gun/rifle/standard_carbine/engineer
- starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/attachable/magnetic_harness, /obj/item/attachable/lasersight)
+ starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/attachable/magnetic_harness, /obj/item/attachable/verticalgrip, /obj/item/attachable/extended_barrel)
/obj/item/weapon/gun/rifle/standard_carbine/plasma_pistol
starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/weapon/gun/pistol/plasma_pistol, /obj/item/attachable/motiondetector, /obj/item/attachable/compensator)
+/obj/item/weapon/gun/rifle/standard_carbine/beginner
+ starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/attachable/magnetic_harness, /obj/item/attachable/angledgrip, /obj/item/attachable/compensator)
+
+/obj/item/weapon/gun/rifle/standard_carbine/suppressed
+ starting_attachment_types = list(/obj/item/attachable/stock/t18stock, /obj/item/weapon/gun/grenade_launcher/underslung, /obj/item/attachable/reddot, /obj/item/attachable/suppressor)
+
//-------------------------------------------------------
//AR-12 Assault Rifle
/obj/item/weapon/gun/rifle/standard_assaultrifle
name = "\improper AR-12 K&H assault rifle"
desc = "The Keckler and Hoch AR-12 assault rifle used to be the TerraGov Marine Corps standard issue rifle before the AR-18 carbine replaced it. It is, however, still used widely despite that. The gun itself is very good at being used in most situations however it suffers in engagements at close quarters and is relatively hard to shoulder than some others. It uses 10x24mm caseless ammunition."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "t12"
+ item_state = "t12"
fire_sound = "gun_ar12"
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/t18_unload.ogg'
@@ -129,16 +126,9 @@
max_shells = 50 //codex
force = 20
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_assaultrifle
- allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_assaultrifle)
- greyscale_config = /datum/greyscale_config/gun/gun64
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand,
- slot_back_str = /datum/greyscale_config/worn_gun,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit,
- )
+ allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_assaultrifle, /obj/item/ammo_magazine/rifle/standard_assaultrifle/ap)
attachable_allowed = list(
+ /obj/item/attachable/stock/t12stock,
/obj/item/attachable/reddot,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/lasersight,
@@ -166,12 +156,12 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
- attachable_offset = list("muzzle_x" = 46, "muzzle_y" = 17,"rail_x" = 16, "rail_y" = 23, "under_x" = 33, "under_y" = 13, "stock_x" = 0, "stock_y" = 13)
+ starting_attachment_types = list(/obj/item/attachable/stock/t12stock)
+ attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 17,"rail_x" = 0, "rail_y" = 23, "under_x" = 17, "under_y" = 13, "stock_x" = 0, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
aim_fire_delay = 0.1 SECONDS
aim_speed_modifier = 2
@@ -181,7 +171,7 @@
extra_delay = 0.05 SECONDS
accuracy_mult = 1.1
scatter = -2
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
burst_amount = 3
aim_slowdown = 0.4
damage_falloff_mult = 0.5
@@ -189,13 +179,13 @@
placed_overlay_iconstate = "t12"
/obj/item/weapon/gun/rifle/standard_assaultrifle/rifleman
- starting_attachment_types = list(/obj/item/attachable/reddot, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/grenade_launcher/underslung)
+ starting_attachment_types = list(/obj/item/attachable/stock/t12stock, /obj/item/attachable/reddot, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/grenade_launcher/underslung)
/obj/item/weapon/gun/rifle/standard_assaultrifle/engineer
- starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/flamer/mini_flamer)
+ starting_attachment_types = list(/obj/item/attachable/stock/t12stock, /obj/item/attachable/magnetic_harness, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/flamer/mini_flamer)
/obj/item/weapon/gun/rifle/standard_assaultrifle/medic
- starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/grenade_launcher/underslung)
+ starting_attachment_types = list(/obj/item/attachable/stock/t12stock, /obj/item/attachable/magnetic_harness, /obj/item/attachable/extended_barrel, /obj/item/weapon/gun/grenade_launcher/underslung)
//-------------------------------------------------------
//DMR-37 DMR
@@ -203,16 +193,12 @@
/obj/item/weapon/gun/rifle/standard_dmr
name = "\improper DMR-37 SCA designated marksman rifle"
desc = "The San Cristo Arms DMR-37 is the TerraGov Marine Corps designated marksman rifle. It is rather well-known for it's very consistent target placement at longer than usual range, it however lacks a burst fire mode or an automatic mode. It is mostly used by people who prefer to do more careful shooting than most. Uses 10x27mm caseless caliber."
- icon = 'icons/Marine/gun64.dmi'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
- greyscale_config = /datum/greyscale_config/gun/gun64/t37
- colorable_allowed = PRESET_COLORS_ALLOWED
+ icon = 'icons/obj/items/guns/marksman64.dmi'
+ icon_state = "t37"
+ item_state = "t37"
item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t37,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t37,
- slot_back_str = /datum/greyscale_config/worn_gun/t37,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t37,
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -225,7 +211,7 @@
reload_sound = 'sound/weapons/guns/interact/m41a_reload.ogg'
caliber = CALIBER_10x27_CASELESS //codex
aim_slowdown = 0.75
- wield_delay = 0.8 SECONDS
+ wield_delay = 1 SECONDS
force = 20
max_shells = 20 //codex
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_dmr
@@ -257,10 +243,9 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
starting_attachment_types = list(/obj/item/attachable/scope/mini/dmr)
attachable_offset = list("muzzle_x" = 50, "muzzle_y" = 20,"rail_x" = 21, "rail_y" = 22, "under_x" = 31, "under_y" = 15, "stock_x" = 14, "stock_y" = 10)
@@ -277,6 +262,8 @@
/obj/item/weapon/gun/rifle/standard_dmr/marksman
starting_attachment_types = list(/obj/item/attachable/scope, /obj/item/attachable/angledgrip, /obj/item/attachable/extended_barrel)
+/obj/item/weapon/gun/rifle/standard_dmr/beginner
+ starting_attachment_types = list(/obj/item/attachable/scope, /obj/item/attachable/verticalgrip, /obj/item/attachable/extended_barrel)
//-------------------------------------------------------
@@ -287,10 +274,10 @@
desc = "The San Cristo Arms BR-64 is the TerraGov Marine Corps main battle rifle. It is known for its consistent ability to perform well at most ranges, and medium range stopping power with bursts. It is mostly used by people who prefer a bigger round than the average. Uses 10x26.5smm caseless caliber."
icon_state = "t64"
item_state = "t64"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -303,7 +290,7 @@
reload_sound = 'sound/weapons/guns/interact/m41a_reload.ogg'
caliber = CALIBER_10x265_CASELESS //codex
aim_slowdown = 0.55
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
force = 20
max_shells = 36 //codex
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_br
@@ -334,11 +321,10 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/weapon/gun/energy/lasgun/lasrifle/pocket_beam, //RUTGMC EDIT
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(/obj/item/attachable/stock/t64stock, /obj/item/weapon/gun/grenade_launcher/underslung/battle_rifle, /obj/item/attachable/scope/mini)
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 19,"rail_x" = 18, "rail_y" = 23, "under_x" = 33, "under_y" = 13, "stock_x" = 11, "stock_y" = 14)
@@ -362,7 +348,7 @@
/obj/item/weapon/gun/rifle/m412
name = "\improper PR-412 pulse rifle"
desc = "The PR-412 rifle is a Pulse Industries rifle, billed as a pulse rifle due to its use of electronic firing for faster velocity. A rather common sight in most systems. Uses 10x24mm caseless ammunition."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "m412"
item_state = "m412"
muzzleflash_iconstate = "muzzle_flash_medium"
@@ -405,11 +391,10 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
/obj/item/weapon/gun/energy/lasgun/lasrifle/pocket_beam, //RUTGMC EDIT
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(/obj/item/weapon/gun/grenade_launcher/underslung)
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 19,"rail_x" = 15, "rail_y" = 21, "under_x" = 25, "under_y" = 16, "stock_x" = 18, "stock_y" = 15)
@@ -418,7 +403,7 @@
burst_delay = 0.15 SECONDS
accuracy_mult = 1.1
scatter = -1
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
burst_amount = 3
aim_slowdown = 0.4
damage_mult = 1.05 //Has smaller magazines
@@ -457,7 +442,6 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
)
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 19,"rail_x" = 15, "rail_y" = 21, "under_x" = 25, "under_y" = 16, "stock_x" = 18, "stock_y" = 15)
@@ -479,15 +463,19 @@
/obj/item/weapon/gun/rifle/m41a
name = "\improper PR-11 pulse rifle"
desc = "A strange failed electronically fired rifle, a rather unknown weapon of its time. It caused a surge in the use of electronic firing in the modern era though. Uses 10x24mm caseless ammunition. Has a irremoveable grenade launcher."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
icon_state = "m41a"
item_state = "m41a"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
fire_sound = "gun_pulse"
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/m41a_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/m41a_reload.ogg'
aim_slowdown = 0.5
- wield_delay = 1.35 SECONDS
+ wield_delay = 1.55 SECONDS
max_shells = 95 //codex
default_ammo_type = /obj/item/ammo_magazine/rifle/m41a
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/m41a)
@@ -507,10 +495,9 @@
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/m41a,
/obj/item/weapon/gun/grenade_launcher/underslung/invisible,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(/obj/item/attachable/stock/m41a, /obj/item/weapon/gun/grenade_launcher/underslung/invisible)
attachable_offset = list("muzzle_x" = 41, "muzzle_y" = 19,"rail_x" = 12, "rail_y" = 24, "under_x" = 24, "under_y" = 13, "stock_x" = 22, "stock_y" = 16)
@@ -520,14 +507,27 @@
scatter = 0
fire_delay = 0.2 SECONDS
+/obj/item/weapon/gun/rifle/m41a/field_commander
+ starting_attachment_types = list(
+ /obj/item/attachable/stock/m41a,
+ /obj/item/weapon/gun/grenade_launcher/underslung/invisible,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/extended_barrel,
+ )
+/obj/item/weapon/gun/rifle/m41a/magharness
+ starting_attachment_types = list(
+ /obj/item/attachable/stock/m41a,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/weapon/gun/grenade_launcher/underslung/invisible,
+ )
//-------------------------------------------------------
/obj/item/weapon/gun/rifle/mpi_km
name = "\improper MPi-KM assault rifle"
desc = "A cheap and robust rifle, sometimes better known as an 'AK'. Chambers 7.62x39mm. Despite lacking attachment points beyond its underbarrel, remains a popular product on the black market with its cheap cost and higher than usual caliber rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "ak47"
item_state = "ak47"
caliber = CALIBER_762X39 //codex
@@ -556,7 +556,6 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/mpi_km,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/verticalgrip,
/obj/item/weapon/gun/pistol/plasma_pistol,
/obj/item/weapon/gun/shotgun/combat/masterkey,
@@ -566,7 +565,7 @@
/obj/item/weapon/gun/grenade_launcher/underslung/mpi, //alt sprite, unremovable
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 35, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 20, "under_x" = 19, "under_y" = 14, "stock_x" = 5, "stock_y" = 12)
starting_attachment_types = list(/obj/item/attachable/stock/mpi_km)
@@ -575,7 +574,7 @@
burst_amount = 1
fire_delay = 0.25 SECONDS
scatter = 0
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
placed_overlay_iconstate = "ak47"
@@ -608,7 +607,6 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/mpi_km/black,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/verticalgrip,
/obj/item/weapon/gun/pistol/plasma_pistol,
/obj/item/weapon/gun/shotgun/combat/masterkey,
@@ -642,14 +640,18 @@
/obj/item/weapon/gun/rifle/lmg_d
name = "\improper lMG-D light machinegun"
desc = "A cheap and robust machinegun, sometimes better known as an 'RPD'. Chambers 7.62x39mm. Despite lacking attachment points beyond its underbarrel, remains a popular product on the black market with its cheap cost, high capacity and higher than usual caliber rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
icon_state = "rpd"
item_state = "rpd"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
fire_animation = "rpd_fire"
caliber = CALIBER_762X39 //codex
muzzleflash_iconstate = "muzzle_flash_medium"
max_shells = 100 //codex
- wield_delay = 1.2 SECONDS
+ wield_delay = 1.4 SECONDS
aim_slowdown = 0.95
fire_sound = 'sound/weapons/guns/fire/ak47.ogg'
unload_sound = 'sound/weapons/guns/interact/ak47_unload.ogg'
@@ -666,7 +668,6 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/lmg_d,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/foldable/bipod,
/obj/item/weapon/gun/pistol/plasma_pistol,
@@ -680,7 +681,7 @@
/obj/item/attachable/flashlight/under,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 35, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 20, "under_x" = 19, "under_y" = 14, "stock_x" = 6, "stock_y" = 14)
@@ -704,9 +705,13 @@
/obj/item/weapon/gun/rifle/dpm
name = "\improper Degtyaryov 'RP' machine gun"
desc = "A cheap and robust machine gun seen commonly in the fringes of the bubble. Fires high caliber rounds to accommodate for its sluggish rate of fire, it is generally found being called 'The Record Player' due to the resemblance. Fires 7.62x39mm AP rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
icon_state = "dp27"
item_state = "dp27"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
max_shells = 47 //codex
caliber = CALIBER_762X39 //codex
fire_sound = "svd_fire"
@@ -722,7 +727,7 @@
/obj/item/attachable/stock/dpm,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 17,"rail_x" = 22, "rail_y" = 17, "under_x" = 32, "under_y" = 14, "stock_x" = 13, "stock_y" = 9)
starting_attachment_types = list(/obj/item/attachable/stock/dpm)
@@ -736,7 +741,7 @@
accuracy_mult = 1
scatter = 2
recoil = -1
- wield_delay = 0.9 SECONDS
+ wield_delay = 1.1 SECONDS
aim_slowdown = 0.85
movement_acc_penalty_mult = 4
@@ -746,7 +751,7 @@
/obj/item/weapon/gun/rifle/m16
name = "\improper FN M16A4 assault rifle"
desc = "A light, versatile assault rifle with a 30 round magazine, chambered to fire the 5.56x45mm NATO cartridge. The 4th generation in the M16 platform, this FN variant has added automatic fire selection and retains relevance among mercenaries and militias thanks to its high customizability. It is incredibly good at rapid burst fire, but must be paced correctly."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "m16a4"
item_state = "m16a4"
muzzleflash_iconstate = "muzzle_flash_medium"
@@ -784,10 +789,9 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE)
attachable_offset = list("muzzle_x" = 47, "muzzle_y" = 19,"rail_x" = 18, "rail_y" = 24, "under_x" = 29, "under_y" = 15, "stock_x" = 19, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -799,7 +803,7 @@
extra_delay = -0.05 SECONDS
burst_delay = 0.15 SECONDS
accuracy_mult = 1.1
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
damage_mult = 1.2
/obj/item/weapon/gun/rifle/m16/freelancer
@@ -817,7 +821,7 @@
/obj/item/weapon/gun/rifle/famas
name = "\improper FAMAS assault rifle"
desc = "A light, versatile fast firing assault rifle with a 24 round magazine and short range scope, chambered to fire the 5.56x45mm NATO cartridge within a short amount of time."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "famas"
item_state = "famas"
muzzleflash_iconstate = "muzzle_flash_medium"
@@ -852,14 +856,14 @@
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
attachable_offset = list("muzzle_x" = 38, "muzzle_y" = 17,"rail_x" = 22, "rail_y" = 24, "under_x" = 28, "under_y" = 12, "stock_x" = 19, "stock_y" = 13)
fire_delay = 0.15 SECONDS
burst_delay = 0.15 SECONDS
accuracy_mult = 1.15
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
damage_mult = 1.2
scatter = 1
movement_acc_penalty_mult = 4
@@ -875,13 +879,11 @@
name = "\improper MG-42 Kauser light machine gun"
desc = "The Kauser MG-42 is the TGMC's current standard non-IFF-capable LMG. It's known for its ability to lay down heavy fire support very well. It is generally used when someone wants to hold a position or provide fire support. It uses 10x24mm ammunition."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "t42"
+ item_state = "t42"
item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t42,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t42,
- slot_back_str = /datum/greyscale_config/worn_gun/t42,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t42,
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -890,16 +892,15 @@
max_shells = 120 //codex
force = 30
aim_slowdown = 0.8
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg42.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/T42_reload.ogg'
default_ammo_type = /obj/item/ammo_magazine/standard_lmg
allowed_ammo_types = list(/obj/item/ammo_magazine/standard_lmg)
- greyscale_config = /datum/greyscale_config/gun/gun64/t42
- colorable_allowed = PRESET_COLORS_ALLOWED
attachable_allowed = list(
+ /obj/item/attachable/stock/t42stock,
/obj/item/attachable/reddot,
/obj/item/attachable/verticalgrip,
/obj/item/attachable/flashlight,
@@ -927,9 +928,10 @@
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_AUTOBURST)
gun_skill_category = SKILL_HEAVY_WEAPONS
+ starting_attachment_types = list(/obj/item/attachable/stock/t42stock)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 17,"rail_x" = 4, "rail_y" = 20, "under_x" = 16, "under_y" = 14, "stock_x" = 0, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
aim_fire_delay = 0.1 SECONDS
@@ -944,23 +946,25 @@
scatter_unwielded = 80
movement_acc_penalty_mult = 6
+/obj/item/weapon/gun/rifle/standard_lmg/autorifleman
+ starting_attachment_types = list(/obj/item/attachable/verticalgrip, /obj/item/attachable/reddot)
+
+/obj/item/weapon/gun/rifle/standard_lmg/beginner
+ starting_attachment_types = list(/obj/item/attachable/extended_barrel, /obj/item/attachable/reddot, /obj/item/attachable/verticalgrip)
+
//-------------------------------------------------------
//MG-60 General Purpose Machine Gun
/obj/item/weapon/gun/rifle/standard_gpmg
name = "\improper MG-60 Raummetall general purpose machine gun"
desc = "The Raummetall MG-60 general purpose machinegun is the TGMC's current standard GPMG. Though usually seen mounted on vehicles, it is sometimes used by infantry to hold chokepoints or suppress enemies, or in rare cases for marching fire. It uses 10x26mm boxes."
- icon = 'icons/Marine/gun64.dmi'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
- fire_animation = "loaded_fire"
- greyscale_config = /datum/greyscale_config/gun/gun64/t60
- colorable_allowed = PRESET_COLORS_ALLOWED
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
+ icon_state = "t60"
+ item_state = "t60"
+ fire_animation = "t60_fire"
item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t60,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t60,
- slot_back_str = /datum/greyscale_config/worn_gun/t60,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t60,
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -969,7 +973,7 @@
max_shells = 200 //codex
force = 35
aim_slowdown = 1.2
- wield_delay = 1.5 SECONDS
+ wield_delay = 1.7 SECONDS
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg60.ogg'
fire_rattle = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg60_low.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
@@ -992,10 +996,9 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
starting_attachment_types = list(/obj/item/attachable/stock/t60stock)
gun_skill_category = SKILL_HEAVY_WEAPONS
@@ -1015,25 +1018,30 @@
placed_overlay_iconstate = "lmg"
-/obj/item/weapon/gun/rifle/standard_lmg/autorifleman
- starting_attachment_types = list(/obj/item/attachable/verticalgrip, /obj/item/attachable/reddot)
-
/obj/item/weapon/gun/rifle/standard_gpmg/machinegunner
starting_attachment_types = list(/obj/item/attachable/stock/t60stock, /obj/item/attachable/foldable/bipod, /obj/item/attachable/magnetic_harness, /obj/item/attachable/extended_barrel)
+/obj/item/weapon/gun/rifle/standard_gpmg/beginner
+ starting_attachment_types = list(/obj/item/attachable/stock/t60stock, /obj/item/attachable/foldable/bipod, /obj/item/attachable/magnetic_harness, /obj/item/attachable/heavy_barrel)
+
//-------------------------------------------------------
//M41AE2 Heavy Pulse Rifle
/obj/item/weapon/gun/rifle/m412l1_hpr
name = "\improper PR-412L1 heavy pulse rifle"
desc = "A large weapon capable of laying down supressing fire, based on the PR-412 pulse rifle platform. Effective in burst fire. Uses 10x24mm caseless ammunition."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
icon_state = "m412l1"
item_state = "m412l1"
+ fire_animation = "m412l1_fire"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
caliber = CALIBER_10X24_CASELESS //codex
max_shells = 200 //codex
aim_slowdown = 0.8
- wield_delay = 2 SECONDS
+ wield_delay = 2.2 SECONDS
fire_sound = 'sound/weapons/guns/fire/hmg.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/m41a_unload.ogg'
@@ -1059,10 +1067,9 @@
/obj/item/weapon/gun/grenade_launcher/underslung,
/obj/item/attachable/buildasentry,
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
gun_skill_category = SKILL_HEAVY_WEAPONS
attachable_offset = list("muzzle_x" = 42, "muzzle_y" = 19,"rail_x" = 17, "rail_y" = 21, "under_x" = 31, "under_y" = 15, "stock_x" = 18, "stock_y" = 15)
@@ -1094,7 +1101,7 @@
/obj/item/weapon/gun/rifle/type71
name = "\improper Type 71 pulse rifle"
desc = "The primary rifle of the USL pirates, the Type 71 is a reliable rifle chambered in 7.62x39mm, firing in three round bursts to conserve ammunition. A newer model for surpression roles to comply with overmatch doctrines is in progress and only issued to a limited number of privates in the USL."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "type71"
item_state = "type71"
muzzleflash_iconstate = "muzzle_flash_medium"
@@ -1107,7 +1114,7 @@
default_ammo_type = /obj/item/ammo_magazine/rifle/type71
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/type71)
aim_slowdown = 0.6
- wield_delay = 0.7 SECONDS
+ wield_delay = 0.9 SECONDS
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/verticalgrip,
@@ -1138,7 +1145,7 @@
/obj/item/attachable/scope/unremovable,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 41, "muzzle_y" = 19,"rail_x" = 18, "rail_y" = 24, "under_x" = 34, "under_y" = 16, "stock_x" = 19, "stock_y" = 13)
gun_firemode_list = list(GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -1186,7 +1193,7 @@
desc = "An much rarer variant of the standard Type 71, this version contains an integrated supressor, a scope, and lots of fine-tuning. Many parts have been replaced, filed down, and improved upon. As a result, this variant is rarely seen outside of elite units."
icon_state = "type71"
item_state = "type71"
- wield_delay = 0 //Ends up being .5 seconds due to scope
+ wield_delay = 0.2 SECONDS
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 19,"rail_x" = 10, "rail_y" = 22, "under_x" = 21, "under_y" = 18, "stock_x" = 21, "stock_y" = 18)
starting_attachment_types = list(/obj/item/attachable/suppressor/unremovable/invisible, /obj/item/attachable/scope/unremovable)
@@ -1205,22 +1212,19 @@
/obj/item/weapon/gun/rifle/standard_autoshotgun
name = "\improper Zauer SH-15 automatic shotgun"
desc = "The Zauer SH-15 Automatic Assault Shotgun, this is a Terran Armories variant. Another iteration of the ZX series of firearms though it has been since regulated as part of the TGMC arsenal, hence the SH designation. It took over the various shotgun models as the semi-automatic shotgun provided to the TGMC. It is rifled, and loads primarily longer ranged munitions, being incompatible with buckshot shells. Takes 12-round 16 gauge magazines."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tx15"
+ item_state = "tx15"
+ icon = 'icons/obj/items/guns/shotguns.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/shotguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/shotguns_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_sh15.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/shotgun_empty.ogg'
caliber = CALIBER_16G //codex
max_shells = 12 //codex
force = 20
default_ammo_type = /obj/item/ammo_magazine/rifle/tx15_slug
- greyscale_config = /datum/greyscale_config/gun/tx15
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tx15,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tx15,
- slot_back_str = /datum/greyscale_config/worn_gun/tx15,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tx15,
- )
allowed_ammo_types = list(
/obj/item/ammo_magazine/rifle/tx15_slug,
/obj/item/ammo_magazine/rifle/tx15_flechette,
@@ -1248,7 +1252,7 @@
/obj/item/weapon/gun/energy/lasgun/lasrifle/pocket_beam, //RUTGMC EDIT
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES //Its a shotgun type weapon effectively, most shotgun type weapons shouldn't be able to point blank 1 handed.
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES //Its a shotgun type weapon effectively, most shotgun type weapons shouldn't be able to point blank 1 handed.
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
starting_attachment_types = list(/obj/item/attachable/stock/tx15)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 16,"rail_x" = 12, "rail_y" = 17, "under_x" = 20, "under_y" = 13, "stock_x" = 26, "stock_y" = 13)
@@ -1275,30 +1279,26 @@
/obj/item/weapon/gun/rifle/standard_smartmachinegun
name = "\improper SG-29 Raummetall-KT smart machine gun"
desc = "The Raummetall-KT SG-29 is the TGMC's current standard IFF-capable medium machine gun. It's known for its ability to lay down heavy fire support very well. It is generally used when someone wants to hold a position or provide fire support. Requires special training and it cannot turn off IFF. It uses 10x26mm ammunition."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "sg29"
+ item_state = "sg29"
+ icon = 'icons/obj/items/guns/machineguns.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
caliber = CALIBER_10x26_CASELESS //codex
max_shells = 300 //codex
force = 30
aim_slowdown = 0.95
- wield_delay = 1.3 SECONDS
+ wield_delay = 1.5 SECONDS
fire_sound = "gun_smartgun"
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/T42_reload.ogg'
- greyscale_config = /datum/greyscale_config/gun/sg29
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/sg29,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/sg29,
- slot_back_str = /datum/greyscale_config/worn_gun/sg29,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/sg29,
- )
default_ammo_type = /obj/item/ammo_magazine/standard_smartmachinegun
allowed_ammo_types = list(/obj/item/ammo_magazine/standard_smartmachinegun)
attachable_allowed = list(
/obj/item/attachable/reddot,
- /obj/item/attachable/verticalgrip,
/obj/item/attachable/flashlight,
/obj/item/attachable/lasersight,
/obj/item/attachable/foldable/bipod,
@@ -1309,10 +1309,9 @@
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/sgstock,
/obj/item/attachable/sgbarrel,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
starting_attachment_types = list(/obj/item/attachable/stock/sgstock, /obj/item/attachable/sgbarrel)
gun_skill_category = SKILL_SMARTGUN //Uses SG skill for the penalties.
@@ -1334,7 +1333,7 @@
starting_attachment_types = list(/obj/item/attachable/stock/sgstock, /obj/item/attachable/sgbarrel, /obj/item/attachable/magnetic_harness, /obj/item/attachable/lasersight)
/obj/item/weapon/gun/rifle/standard_smartmachinegun/patrol
- starting_attachment_types = list(/obj/item/attachable/stock/sgstock, /obj/item/attachable/sgbarrel, /obj/item/attachable/motiondetector, /obj/item/attachable/verticalgrip)
+ starting_attachment_types = list(/obj/item/attachable/stock/sgstock, /obj/item/attachable/sgbarrel, /obj/item/attachable/motiondetector, /obj/item/attachable/lasersight)
//-------------------------------------------------------
//SG Target Rifle, has underbarreled spotting rifle that applies effects.
@@ -1342,13 +1341,17 @@
/obj/item/weapon/gun/rifle/standard_smarttargetrifle
name = "\improper SG-62 Kauser-KT smart target rifle"
desc = "The Kauser-KT SG-62 is a IFF-capable rifle used by the TerraGov Marine Corps, coupled with a spotting rifle that is also IFF capable of applying various bullets with specialized ordnance, this is a gun with many answers to many situations... if you have the right ammo loaded. Requires special training and it cannot turn off IFF. It uses high velocity 10x27mm for the rifle and 12x66mm ammunition for the underslung rifle."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "sg62"
item_state = "sg62"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
caliber = CALIBER_10x27_CASELESS //codex
max_shells = 40 //codex
aim_slowdown = 0.85
- wield_delay = 0.65 SECONDS
+ wield_delay = 0.85 SECONDS
fire_sound = 'sound/weapons/guns/fire/t62.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
@@ -1365,10 +1368,9 @@
/obj/item/attachable/stock/strstock,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
gun_skill_category = SKILL_SMARTGUN //Uses SG skill for the penalties.
attachable_offset = list("muzzle_x" = 12, "muzzle_y" = 22, "rail_x" = 15, "rail_y" = 22, "under_x" = 28, "under_y" = 16, "stock_x" = 12, "stock_y" = 14)
@@ -1391,7 +1393,7 @@
name = "SG-153 spotting rifle"
desc = "An underslung spotting rifle, generally found ontop of another gun."
icon_state = "sg153"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
fire_sound = 'sound/weapons/guns/fire/spottingrifle.ogg'
caliber = CALIBER_12x7
slot = ATTACHMENT_SLOT_UNDER
@@ -1410,8 +1412,8 @@
attachable_allowed = list()
actions_types = list()
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
- flags_gun_features = GUN_IS_ATTACHMENT|GUN_WIELDED_FIRING_ONLY|GUN_ATTACHMENT_FIRE_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
- flags_attach_features = NONE
+ gun_features_flags = GUN_IS_ATTACHMENT|GUN_WIELDED_FIRING_ONLY|GUN_ATTACHMENT_FIRE_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ attach_features_flags = NONE
fire_delay = 1 SECONDS
accuracy_mult = 1.25
pixel_shift_x = 18
@@ -1423,21 +1425,26 @@
/obj/item/weapon/gun/rifle/sectoid_rifle
name = "alien rifle"
desc = "An unusual gun of alien origin. It is lacking a trigger or any obvious way to fire it."
+ icon = 'icons/obj/items/guns/energy.dmi'
icon_state = "alien_rifle"
item_state = "alien_rifle"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/energy_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/energy_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/alienplasma.ogg'
fire_rattle = 'sound/weapons/guns/fire/alienplasma.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/vp70_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/m41a_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/m4ra_reload.ogg'
max_shells = 20//codex stuff
- ammo_datum_type = /datum/ammo/energy/plasma
+ ammo_datum_type = /datum/ammo/energy/sectoid_plasma
muzzleflash_iconstate = "muzzle_flash_pulse"
default_ammo_type = /obj/item/ammo_magazine/rifle/sectoid_rifle
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/sectoid_rifle)
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_ENERGY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 23, "under_x" = 23, "under_y" = 15, "stock_x" = 22, "stock_y" = 12)
@@ -1472,16 +1479,12 @@
/obj/item/weapon/gun/rifle/chambered
name = "\improper SR-127 Bauer bolt action rifle"
desc = "The Bauer SR-127 is the standard issue bolt action rifle used by the TGMC. Known for its long range accuracy and use by marksmen despite its age and lack of IFF, though careful aim allows fire support from behind. It has an irremoveable scope. Uses 8.6×70mm box magazines."
- icon = 'icons/Marine/gun64.dmi'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
- greyscale_config = /datum/greyscale_config/gun/gun64/shotgun/tl127
- colorable_allowed = PRESET_COLORS_ALLOWED
+ icon = 'icons/obj/items/guns/marksman64.dmi'
+ icon_state = "tl127"
+ item_state = "tl127"
item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tl127,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tl127,
- slot_back_str = /datum/greyscale_config/worn_gun/tl127,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tl127,
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
@@ -1512,10 +1515,10 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_REQUIRES_UNIQUE_ACTION|AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_UNIQUE_ACTION_LOCKS|AMMO_RECIEVER_AUTO_EJECT
- cock_animation = GUN_ICONSTATE_PUMP
+ cock_animation = "tl127_cock"
cocked_message = "You rack the bolt!"
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
@@ -1537,7 +1540,7 @@
recoil = 0
recoil_unwielded = 4
aim_slowdown = 1
- wield_delay = 1.3 SECONDS
+ wield_delay = 1.5 SECONDS
cock_delay = 0.7 SECONDS
movement_acc_penalty_mult = 6
@@ -1550,8 +1553,8 @@
/obj/item/weapon/gun/rifle/standard_autosniper
name = "\improper SR-81 Kauser-KT automatic sniper rifle"
desc = "The Kauser-KT SR-81 is the TerraGov Marine Corps's automatic sniper rifle usually married to it's iconic NVG/KTLD scope combo. It is notable for its high rate of fire for its class, and has decent performance in any range. Uses 8.6x70mm caseless with specialized pressures for IFF fire."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "t81"
+ item_state = "t81"
fire_sound = 'sound/weapons/guns/fire/sniper.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/sniper_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/m41a_unload.ogg'
@@ -1560,15 +1563,8 @@
max_shells = 20 //codex
default_ammo_type = /obj/item/ammo_magazine/rifle/autosniper
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/autosniper)
- greyscale_config = /datum/greyscale_config/gun/gun64/t81
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t81,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t81,
- slot_back_str = /datum/greyscale_config/worn_gun/t81,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t81,
- )
attachable_allowed = list(
+ /obj/item/attachable/autosniperbarrel,
/obj/item/attachable/scope/nightvision,
/obj/item/attachable/extended_barrel,
/obj/item/attachable/suppressor,
@@ -1578,10 +1574,11 @@
/obj/item/attachable/compensator,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 48, "muzzle_y" = 18,"rail_x" = 23, "rail_y" = 23, "under_x" = 38, "under_y" = 16, "stock_x" = 9, "stock_y" = 12)
starting_attachment_types = list(
+ /obj/item/attachable/autosniperbarrel,
/obj/item/attachable/scope/nightvision,
)
@@ -1594,7 +1591,7 @@
recoil = 0
recoil_unwielded = 4
aim_slowdown = 1
- wield_delay = 1.3 SECONDS
+ wield_delay = 1.5 SECONDS
movement_acc_penalty_mult = 6
//-------------------------------------------------------
@@ -1603,25 +1600,17 @@
/obj/item/weapon/gun/rifle/tx11
name = "\improper AR-11 K&H combat rifle"
desc = "The Keckler and Hoch AR-11 is the former standard issue rifle of the TGMC. Most of them have been mothballed into storage long ago, but some still pop up in marine or mercenary hands. It is known for its large magazine size and great burst fire, but rather awkward to use, especially during combat. It uses 4.92×34mm caseless HV ammunition."
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "tx11"
+ item_state = "tx11"
caliber = CALIBER_492X34_CASELESS //codex
max_shells = 70 //codex
- wield_delay = 0.65 SECONDS
+ wield_delay = 0.85 SECONDS
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_ar11.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/T42_reload.ogg'
default_ammo_type = /obj/item/ammo_magazine/rifle/tx11
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/tx11)
- greyscale_config = /datum/greyscale_config/gun/tx11
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/tx11,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/tx11,
- slot_back_str = /datum/greyscale_config/worn_gun/tx11,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/tx11,
- )
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/flashlight,
@@ -1637,7 +1626,7 @@
/obj/item/attachable/scope/marine,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(/obj/item/attachable/stock/tx11, /obj/item/attachable/scope/mini/tx11)
attachable_offset = list("muzzle_x" = 31, "muzzle_y" = 17,"rail_x" = 6, "rail_y" = 20, "under_x" = 20, "under_y" = 12, "stock_x" = 17, "stock_y" = 14)
@@ -1673,14 +1662,12 @@
/obj/item/weapon/gun/rifle/standard_skirmishrifle
name = "\improper AR-21 Kauser skirmish rifle"
desc = "The Kauser AR-21 is a versatile rifle is developed to bridge a gap between higher caliber weaponry and a normal rifle. It fires a strong 10x25mm round, which has decent stopping power. It however suffers in magazine size and movement capablity compared to smaller peers."
- icon = 'icons/Marine/gun64.dmi'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon = 'icons/obj/items/guns/rifles64.dmi'
+ icon_state = "t21"
+ item_state = "t21"
item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t21,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t21,
- slot_back_str = /datum/greyscale_config/worn_gun/t21,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t21,
+ slot_l_hand_str = 'icons/mob/inhands/guns/rifles_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/rifles_right_64.dmi',
)
inhand_x_dimension = 64
@@ -1690,12 +1677,10 @@
unload_sound = 'sound/weapons/guns/interact/t21_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/t21_reload.ogg'
caliber = CALIBER_10X25_CASELESS //codex
- max_shells = 30 //codex
+ max_shells = 40 //codex
force = 20
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_skirmishrifle
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_skirmishrifle)
- greyscale_config = /datum/greyscale_config/gun/gun64/t21
- colorable_allowed = PRESET_COLORS_ALLOWED
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/verticalgrip,
@@ -1725,7 +1710,7 @@
/obj/item/weapon/gun/energy/lasgun/lasrifle/pocket_beam, //RUTGMC EDIT
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 46, "muzzle_y" = 16,"rail_x" = 18, "rail_y" = 19, "under_x" = 34, "under_y" = 13, "stock_x" = 0, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -1737,7 +1722,7 @@
burst_delay = 0.15 SECONDS
accuracy_mult = 1.2
scatter = -2
- wield_delay = 0.6 SECONDS
+ wield_delay = 0.8 SECONDS
aim_slowdown = 0.5
damage_falloff_mult = 0.5
@@ -1754,8 +1739,13 @@
/obj/item/weapon/gun/rifle/alf_machinecarbine
name = "\improper ALF-51B Kauser machinecarbine"
desc = "The Kauser ALF-51B is an unoffical modification of a ALF-51, or better known as the AR-18 carbine, modified to SMG length of barrel, rechambered for a stronger round, and belt based. Truly the peak of CQC. Useless past that. Aiming is impossible. Uses 10x25mm caseless ammunition."
+ icon = 'icons/obj/items/guns/machineguns.dmi'
icon_state = "alf51b"
item_state = "alf51b"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_1.dmi',
+ )
fire_animation = "alf51b_fire"
fire_sound = 'sound/weapons/guns/fire/t18b.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
@@ -1778,7 +1768,7 @@
/obj/item/attachable/bayonetknife/som,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
attachable_offset = list("muzzle_x" = 31, "muzzle_y" = 16,"rail_x" = 10, "rail_y" = 19, "under_x" = 21, "under_y" = 13, "stock_x" = 0, "stock_y" = 13)
@@ -1788,7 +1778,7 @@
scatter = 4
burst_amount = 4
aim_slowdown = 0.3
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
damage_falloff_mult = 3
movement_acc_penalty_mult = 4
@@ -1812,7 +1802,7 @@
/obj/item/weapon/gun/rifle/mkh
name = "\improper MKH-98 storm rifle"
desc = "A certified classic, this reproduction design was hailed as the first successful assault rifle concept, generally termed a 'storm rifle'. Has a higher than usual firerate for its class, but suffers in capacity. This version of it chambers 7.62x39mm."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "mkh98"
item_state = "mkh98"
caliber = CALIBER_762X39 //codex
@@ -1838,7 +1828,7 @@
/obj/item/attachable/bayonetknife/som,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 51, "muzzle_y" = 18,"rail_x" = 24, "rail_y" = 22, "under_x" = 36, "under_y" = 16, "stock_x" = 0, "stock_y" = 12)
@@ -1846,7 +1836,7 @@
burst_amount = 1
fire_delay = 0.2 SECONDS
scatter = 1
- wield_delay = 0.5 SECONDS
+ wield_delay = 0.7 SECONDS
movement_acc_penalty_mult = 4
//-------------------------------------------------------
@@ -1854,9 +1844,13 @@
/obj/item/weapon/gun/rifle/tx54
name = "\improper GL-54 grenade launcher"
desc = "A magazine fed, semi-automatic grenade launcher designed to shoot airbursting smart grenades. Requires a T49 scope for precision aiming."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "tx54"
item_state = "tx54" ///todo
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
max_shells = 5 //codex
max_chamber_items = 1
fire_delay = 1.2 SECONDS
@@ -1876,10 +1870,9 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/flashlight/under,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
starting_attachment_types = list(/obj/item/attachable/scope/optical)
default_ammo_type = null
allowed_ammo_types = list(
@@ -1889,18 +1882,23 @@
/obj/item/ammo_magazine/rifle/tx54/smoke,
/obj/item/ammo_magazine/rifle/tx54/smoke/dense,
/obj/item/ammo_magazine/rifle/tx54/smoke/tangle,
+ /obj/item/ammo_magazine/rifle/tx54/smoke/acid,
/obj/item/ammo_magazine/rifle/tx54/razor,
)
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
attachable_offset = list("muzzle_x" = 31, "muzzle_y" = 17,"rail_x" = 12, "rail_y" = 20, "under_x" = 28, "under_y" = 13, "stock_x" = -1, "stock_y" = 17)
aim_slowdown = 0.8
- wield_delay = 0.8 SECONDS
+ wield_delay = 1 SECONDS
burst_amount = 1
accuracy_mult = 1.15
scatter = -2
aim_fire_delay = 0.2 SECONDS
aim_speed_modifier = 2
+/obj/item/weapon/gun/rifle/tx54/motion_sensor
+ starting_attachment_types = list(/obj/item/attachable/motiondetector)
+ default_ammo_type = /obj/item/ammo_magazine/rifle/tx54
+
//-------------------------------------------------------
// AR-55 built in grenade launcher
@@ -1911,8 +1909,8 @@
icon_state = "tx55gl"
placed_overlay_iconstate = "tx55gl"
attachable_allowed = list()
- flags_gun_features = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
- flags_attach_features = NONE
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_IS_ATTACHMENT|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ attach_features_flags = NONE
slot = ATTACHMENT_SLOT_STOCK
default_ammo_type = /obj/item/ammo_magazine/rifle/tx54
attach_delay = 3 SECONDS
@@ -1934,7 +1932,7 @@
reload_sound = 'sound/weapons/guns/interact/t18_reload.ogg'
caliber = CALIBER_10X24_CASELESS //codex
max_shells = 36 //codex
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
default_ammo_type = /obj/item/ammo_magazine/rifle/standard_carbine
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/standard_carbine)
attachable_allowed = list(
@@ -1961,7 +1959,7 @@
/obj/item/attachable/motiondetector,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(
/obj/item/weapon/gun/rifle/tx54/mini,
@@ -2003,16 +2001,15 @@
/obj/item/weapon/gun/rifle/garand
name = "\improper CAU C1 Garand self loading rifle"
desc = "The Carlford-1 is a remastered classic made by Carlford Armories, made to fit in the modern day. Most of the noticeable differences are minor rail modifications. Other than that, it is a faithful recreation with the trademark ping sound and all. Uses .30-06 enbloc clips."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "garand"
item_state = "garand"
- item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
- )
-
inhand_x_dimension = 64
inhand_y_dimension = 32
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/garand.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/sniper_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/garand_ping.ogg'
@@ -2037,7 +2034,7 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
gun_firemode_list = list(GUN_FIREMODE_SEMIAUTO)
@@ -2058,7 +2055,7 @@
recoil = 0
recoil_unwielded = 4
aim_slowdown = 0.75
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
movement_acc_penalty_mult = 6
//-------------------------------------------------------
@@ -2068,7 +2065,7 @@
name = "\improper V-31 assault rifle"
desc = "The V-31 was the primary rifle of the Sons of Mars until the introduction of more advanced energy weapons. Nevertheless, the V-31 continues to see common use due to its comparative ease of production and maintenance, and due to the inbuilt low velocity railgun designed for so called 'micro' grenades. Has good handling due to its compact bullpup design, and is generally effective at all ranges. Uses 10x25mm caseless ammunition."
icon_state = "v31"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
item_state = "v31"
fire_sound = 'sound/weapons/guns/fire/som_rifle.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
@@ -2101,7 +2098,7 @@
/obj/item/attachable/motiondetector,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
starting_attachment_types = list(
/obj/item/weapon/gun/shotgun/micro_grenade,
@@ -2109,7 +2106,7 @@
attachable_offset = list("muzzle_x" = 45, "muzzle_y" = 16,"rail_x" = 23, "rail_y" = 24, "under_x" = 33, "under_y" = 11, "stock_x" = -1, "stock_y" = 17)
actions_types = list(/datum/action/item_action/aim_mode)
- wield_delay = 0.6 SECONDS
+ wield_delay = 0.8 SECONDS
aim_fire_delay = 0.1 SECONDS
aim_speed_modifier = 2
@@ -2136,6 +2133,14 @@
/obj/item/attachable/reddot,
)
+/obj/item/weapon/gun/rifle/som/suppressed
+ starting_attachment_types = list(
+ /obj/item/weapon/gun/shotgun/micro_grenade,
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/suppressor,
+ /obj/item/attachable/magnetic_harness,
+ )
+
/obj/item/weapon/gun/rifle/som/veteran
default_ammo_type = /obj/item/ammo_magazine/rifle/som/ap
starting_attachment_types = list(
@@ -2165,7 +2170,7 @@
/obj/item/weapon/gun/rifle/som_carbine
name = "\improper V-34 carbine"
desc = "An old but robust weapon that saw extensive use in the Martian uprising. A comparatively light and compact weapon, it still packs a considerable punch thanks to a good rate of fire and high calibre, although at range its effective drops off considerably. It is chambered in 7.62x39mm."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "v34"
item_state = "v34"
caliber = CALIBER_762X39
@@ -2192,7 +2197,7 @@
/obj/item/attachable/verticalgrip,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 18,"rail_x" = 8, "rail_y" = 20, "under_x" = 17, "under_y" = 13, "stock_x" = -6, "stock_y" = 16)
starting_attachment_types = list(/obj/item/attachable/foldable/som_carbine)
@@ -2203,8 +2208,8 @@
accuracy_mult = 0.75
scatter = 12
recoil = 1.5
- wield_delay = 0.4 SECONDS
- aim_slowdown = 0.3
+ wield_delay = 0.6 SECONDS
+ aim_slowdown = 0.4
movement_acc_penalty_mult = 4
damage_falloff_mult = 1.4
damage_mult = 0.9
@@ -2237,13 +2242,13 @@
/obj/item/weapon/gun/rifle/som_mg
name = "\improper V-41 machine gun"
desc = "The V-41 is a large man portable machine used by the SOM, allowing for sustained, accurate suppressive firepower at the cost of mobility and handling. Commonly seen where their preferred tactics of fast, mobile aggression is ill suited. Takes 10x26mm Caseless."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
icon_state = "v41"
item_state = "v41"
fire_animation = "v41_fire"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_64.dmi',
)
inhand_x_dimension = 64
@@ -2251,7 +2256,7 @@
caliber = CALIBER_10x26_CASELESS
max_shells = 200
force = 35
- wield_delay = 1.5 SECONDS
+ wield_delay = 1.7 SECONDS
fire_sound = 'sound/weapons/guns/fire/v41.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
@@ -2274,10 +2279,9 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
starting_attachment_types = list(/obj/item/attachable/stock/som_mg_stock)
gun_skill_category = SKILL_HEAVY_WEAPONS
@@ -2305,12 +2309,12 @@
/obj/item/weapon/gun/rifle/icc_sharpshooter
name = "\improper L-11 sharpshooter rifle"
desc = "The L-11 is a venerable and battle-tested rifle used by the ICCAF. Although rather heavy, long and unwieldy compared to most ICCAF rifles, which focus on getting up close and personal, it easily makes up with excellent long-range potential when compared to most of its peers, mostly seen in use by reserve troops who expect to fight at distance, rather than up close. Uses 10x27mm magazines."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "l11"
item_state = "l11"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
inhand_y_dimension = 32
@@ -2322,7 +2326,7 @@
reload_sound = 'sound/weapons/guns/interact/fal_reload.ogg'
caliber = CALIBER_10x27_CASELESS //codex
aim_slowdown = 0.8
- wield_delay = 0.85 SECONDS
+ wield_delay = 1.05 SECONDS
force = 20
max_shells = 20 //codex
default_ammo_type = /obj/item/ammo_magazine/rifle/icc_sharpshooter
@@ -2355,7 +2359,7 @@
)
starting_attachment_types = list(/obj/item/attachable/stock/icc_sharpshooter)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_CAN_POINTBLANK|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 40, "muzzle_y" = 14, "rail_x" = 15, "rail_y" = 17, "under_x" = 23, "under_y" = 10, "stock_x" = 17, "stock_y" = 10)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -2378,12 +2382,12 @@
/obj/item/weapon/gun/rifle/icc_battlecarbine
name = "\improper L-15 battlecarbine"
desc = "The L-15 battlecarbine is the standard rifle of the ICCAF, boasting a high caliber round and a menacing profile, it presents an excellent CQC firearm. However it struggles at range due to high dropoff from the short barrel, units that use it say that you need to close the gap at any cost to see the true efficacy of this weapon. Uses 10x25mm caseless ammunition."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "l15"
item_state = "l15"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/rifles_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/rifles_right_64.dmi',
)
inhand_x_dimension = 64
@@ -2425,7 +2429,7 @@
/obj/item/weapon/gun/rifle/pepperball/pepperball_mini,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 19,"rail_x" = 20, "rail_y" = 23, "under_x" = 33, "under_y" = 13, "stock_x" = 0, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -2436,7 +2440,7 @@
fire_delay = 0.2 SECONDS
scatter = 3
aim_slowdown = 0.35
- wield_delay = 0.35 SECONDS
+ wield_delay = 0.55 SECONDS
damage_falloff_mult = 2.5
movement_acc_penalty_mult = 4
@@ -2450,12 +2454,12 @@
/obj/item/weapon/gun/rifle/icc_confrontationrifle
name = "\improper ML-12 confrontation rifle"
desc = "The ML-12 confrontation rifle is an absolute beast of a weapon used by the ICCAF. Featuring a high caliber round in a short package, it will absolutely shred enemy targets at close quarters, a operator must mind the incredible recoil while making followup shots, however. Uses 10x28mm caseless ammunition."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "ml12"
item_state = "ml12"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
@@ -2488,7 +2492,7 @@
/obj/item/attachable/motiondetector,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 48, "muzzle_y" = 18,"rail_x" = 24, "rail_y" = 26, "under_x" = 36, "under_y" = 14, "stock_x" = 0, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -2498,7 +2502,7 @@
burst_amount = 1
fire_delay = 0.45 SECONDS
aim_slowdown = 0.55
- wield_delay = 0.65 SECONDS
+ wield_delay = 0.85 SECONDS
damage_falloff_mult = 2
movement_acc_penalty_mult = 6.5
@@ -2517,9 +2521,13 @@
/obj/item/weapon/gun/rifle/icc_autoshotgun
name = "\improper ML-41 autoshotgun"
desc = "The ML-41 Automatic Shotgun is used by the ICCAF in fast paced boarding assaults, fielding a wide variety of ammo for all situations. Takes 16-round 12 gauge drums."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
icon_state = "ml41"
item_state = "ml41"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/shotguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/shotguns_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/shotgun.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/shotgun_empty.ogg'
caliber = CALIBER_12G //codex
@@ -2547,7 +2555,7 @@
/obj/item/attachable/motiondetector,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES //Its a shotgun type weapon effectively, most shotgun type weapons shouldn't be able to point blank 1 handed.
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES //Its a shotgun type weapon effectively, most shotgun type weapons shouldn't be able to point blank 1 handed.
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 26,"rail_x" = 26, "rail_y" = 24, "under_x" = 40, "under_y" = 16, "stock_x" = 26, "stock_y" = 13)
gun_skill_category = SKILL_SHOTGUNS
@@ -2556,7 +2564,7 @@
accuracy_mult = 1.15
damage_mult = 0.5
aim_slowdown = 0.6
- wield_delay = 0.55 SECONDS
+ wield_delay = 0.75 SECONDS
burst_amount = 1
scatter = 8
movement_acc_penalty_mult = 2
@@ -2570,7 +2578,7 @@
/obj/item/weapon/gun/rifle/icc_assaultcarbine
name = "\improper L-88 assault carbine"
desc = "An aged, reliable but outdated bullpup rifle used by ICCAF reserve personnel it is best used in close quarters when you need to quickly clear corners at rapid pace, has an integral foregrip and unmagnified scope to increase accuracy and reduce drag. Chambered in 5.56x45mm NATO."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/rifles64.dmi'
icon_state = "l88"
item_state = "l88"
muzzleflash_iconstate = "muzzle_flash_medium"
@@ -2595,7 +2603,7 @@
/obj/item/attachable/magnetic_harness,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 19,"rail_x" = 8, "rail_y" = 21, "under_x" = 28, "under_y" = 12, "stock_x" = 19, "stock_y" = 13)
@@ -2605,7 +2613,7 @@
accuracy_mult = 1.15
damage_mult = 1.2
damage_falloff_mult = 1.5
- wield_delay = 0.65 SECONDS
+ wield_delay = 0.85 SECONDS
aim_slowdown = 0.2
scatter = 0
@@ -2615,3 +2623,68 @@
icon_state = "l88_export"
item_state = "l88_export"
default_ammo_type = /obj/item/ammo_magazine/rifle/icc_assaultcarbine/export
+
+//-------------------------------------------------------
+//MG-60 General Purpose Machine Gun
+
+/obj/item/weapon/gun/rifle/icc_mg
+ name = "\improper ML-41 assault machine gun"
+ desc = "The ML-41 is an incredibly lightweight machinegun used by ICCAF forces, being incredibly light for its class allows it to be used in rapid manuevers, at the cost of damage at range and generally high scatter. It uses 10x26mm boxes."
+ icon = 'icons/obj/items/guns/machineguns64.dmi'
+ icon_state = "minimi"
+ item_state = "minimi"
+ fire_animation = "minimi_fire"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/machineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/machineguns_right_64.dmi',
+ )
+ inhand_x_dimension = 64
+ inhand_y_dimension = 32
+
+ caliber = CALIBER_10x26_CASELESS //codex
+ max_shells = 200 //codex
+ force = 30
+ aim_slowdown = 0.85
+ wield_delay = 0.95 SECONDS
+ fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mg60.ogg'
+ dry_fire_sound = 'sound/weapons/guns/fire/m41a_empty.ogg'
+ unload_sound = 'sound/weapons/guns/interact/T42_unload.ogg'
+ reload_sound = 'sound/weapons/guns/interact/T42_reload.ogg'
+ default_ammo_type = /obj/item/ammo_magazine/icc_mg
+ allowed_ammo_types = list(/obj/item/ammo_magazine/icc_mg, /obj/item/ammo_magazine/icc_mg/belt)
+ attachable_allowed = list(
+ /obj/item/attachable/flashlight,
+ /obj/item/attachable/lasersight,
+ /obj/item/attachable/flashlight/under,
+ /obj/item/attachable/foldable/bipod,
+ /obj/item/attachable/extended_barrel,
+ /obj/item/attachable/heavy_barrel,
+ /obj/item/attachable/bayonet,
+ /obj/item/attachable/bayonetknife,
+ /obj/item/attachable/bayonetknife/som,
+ /obj/item/attachable/scope/mini,
+ /obj/item/attachable/stock/t60stock,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/motiondetector,
+ /obj/item/attachable/buildasentry,
+ )
+
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+ gun_skill_category = SKILL_HEAVY_WEAPONS
+ attachable_offset = list("muzzle_x" = 42, "muzzle_y" = 21,"rail_x" = 6, "rail_y" = 23, "under_x" = 26, "under_y" = 15, "stock_x" = 8, "stock_y" = 13)
+ actions_types = list(/datum/action/item_action/aim_mode)
+ aim_fire_delay = 0.15 SECONDS
+ aim_speed_modifier = 5
+
+ fire_delay = 0.15 SECONDS
+ damage_falloff_mult = 2.5
+ burst_amount = 1
+ accuracy_mult = 0.85
+ accuracy_mult_unwielded = 0.4
+ scatter = 5
+ scatter_unwielded = 45
+ movement_acc_penalty_mult = 6
+
+/obj/item/weapon/gun/rifle/icc_mg/guard
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/heavy_barrel)
diff --git a/code/modules/projectiles/guns/sentries.dm b/code/modules/projectiles/guns/sentries.dm
index 03489ffd340f9..e98da3b19c802 100644
--- a/code/modules/projectiles/guns/sentries.dm
+++ b/code/modules/projectiles/guns/sentries.dm
@@ -23,10 +23,10 @@
)
turret_flags = TURRET_HAS_CAMERA|TURRET_SAFETY|TURRET_ALERTS
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
deployable_item = /obj/machinery/deployable/mounted/sentry
- flags_item = IS_DEPLOYABLE|TWOHANDED
+ item_flags = IS_DEPLOYABLE|TWOHANDED
deploy_time = 5 SECONDS
allowed_ammo_types = list(/obj/item/ammo_magazine/sentry)
@@ -71,9 +71,9 @@
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_AUTOBURST)
- attachable_allowed = list(/obj/item/attachable/scope/unremovable/tl102)
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102)
starting_attachment_types = list(
- /obj/item/attachable/scope/unremovable/tl102,
+ /obj/item/attachable/scope/unremovable/hsg_102,
)
/obj/item/weapon/gun/sentry/pod_sentry
@@ -81,7 +81,7 @@
desc = "A fully automatic turret with AI targeting capabilities, designed specifically for deploying inside a paired drop pod shell. Armed with a M30 autocannon and a 500-round drum magazine. Designed to sweeping a landing area to support orbital assaults."
icon_state = "podsentry"
turret_flags = TURRET_HAS_CAMERA|TURRET_ALERTS|TURRET_RADIAL
- flags_item = IS_DEPLOYABLE|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
+ item_flags = IS_DEPLOYABLE|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
sentry_iff_signal = TGMC_LOYALIST_IFF
turret_range = 10
knockdown_threshold = 500
@@ -101,6 +101,10 @@
desc = "The Centurion Omnidirectional Point-defense Energy sentry is a man portable, automated weapon system utilised by the SOM. It is activated in hand then thrown into place before it deploys, where it's ground hugging profile makes it a difficult target to accurately hit. Equipped with a compact volkite weapon system, and a recharging battery to allow for prolonged use, but can take normal volkite cells in a pinch."
icon_state = "cope"
icon = 'icons/Marine/sentry.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/misc_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/misc_right_1.dmi',
+ )
max_integrity = 225
integrity_failure = 50
deploy_time = 1 SECONDS
@@ -118,10 +122,10 @@
/obj/machinery/miner,
)
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_ENERGY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNT_BY_SHOTS_REMAINING|GUN_ENERGY|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_DO_NOT_EJECT_HANDFULS|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE //doesn't autoeject its recharging battery
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
- flags_item = IS_DEPLOYABLE|TWOHANDED
+ item_flags = IS_DEPLOYABLE|TWOHANDED
max_shots = 150
rounds_per_shot = 12
@@ -182,28 +186,28 @@
deployed_machine.max_integrity = max_integrity //Syncs new machine or structure integrity with that of the item.
deployed_machine.obj_integrity = obj_integrity
- deployed_machine.update_icon_state()
+ deployed_machine.update_appearance()
forceMove(deployed_machine) //Moves the Item into the machine or structure
- ENABLE_BITFIELD(flags_item, IS_DEPLOYED)
+ ENABLE_BITFIELD(item_flags, IS_DEPLOYED)
/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/cope/predeployed
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
/obj/item/weapon/gun/sentry/big_sentry/premade
sentry_iff_signal = TGMC_LOYALIST_IFF
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE
/obj/item/weapon/gun/sentry/big_sentry/premade/radial
turret_range = 9
turret_flags = TURRET_HAS_CAMERA|TURRET_ALERTS|TURRET_RADIAL
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
/obj/item/weapon/gun/sentry/big_sentry/dropship
ammo_datum_type = /datum/ammo/bullet/turret/gauss
sentry_iff_signal = TGMC_LOYALIST_IFF
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
var/obj/structure/dropship_equipment/shuttle/sentry_holder/deployment_system
turret_flags = TURRET_HAS_CAMERA|TURRET_IMMOBILE
density = FALSE
@@ -213,7 +217,7 @@
fire_delay = 0.2 SECONDS
ammo_datum_type = /datum/ammo/bullet/turret/gauss
sentry_iff_signal = TGMC_LOYALIST_IFF
- flags_item = IS_DEPLOYABLE|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
+ item_flags = IS_DEPLOYABLE|DEPLOY_ON_INITIALIZE|DEPLOYED_NO_PICKUP
turret_flags = TURRET_IMMOBILE|TURRET_RADIAL|TURRET_LOCKED|TURRET_ON
default_ammo_type = /obj/item/ammo_magazine/sentry/fob_sentry
allowed_ammo_types = list(/obj/item/ammo_magazine/sentry/fob_sentry)
@@ -272,12 +276,12 @@
allowed_ammo_types = list(/obj/item/ammo_magazine/sentry)
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_AUTOBURST)
- flags_item = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
+ item_flags = IS_DEPLOYABLE|TWOHANDED|DEPLOYED_NO_PICKUP|DEPLOY_ON_INITIALIZE
/obj/item/weapon/gun/sentry/premade/dumb
name = "\improper Modified ST-571 sentry gun"
desc = "A deployable, semi-automated turret with AI targeting capabilities. Armed with an M30 Autocannon and a 500-round drum magazine. This one's IFF system has been disabled, and it will open fire on any targets within range."
- flags_gun_features = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
ammo_datum_type = /datum/ammo/bullet/turret/dumb
default_ammo_type = /obj/item/ammo_magazine/sentry_premade/dumb
allowed_ammo_types = list(/obj/item/ammo_magazine/sentry_premade/dumb)
@@ -295,4 +299,147 @@
ammo_datum_type = /datum/ammo/bullet/turret
sentry_iff_signal = TGMC_LOYALIST_IFF
+// Sniper Sentry
+
+/obj/item/weapon/gun/sentry/sniper_sentry
+ name = "\improper SRT-574 sentry gun"
+ desc = "A deployable, fully automatic turret with AI targeting capabilities. Armed with a heavy caliber AM-5 antimaterial rifle and a 75-round drum magazine."
+ icon_state = "snipersentry"
+
+ turret_range = 12
+ deploy_time = 10 SECONDS
+ max_shells = 75
+ fire_delay = 2 SECONDS
+ burst_amount = 1
+
+ scatter = 0
+
+ ammo_datum_type = /datum/ammo/bullet/turret/sniper
+ default_ammo_type = /obj/item/ammo_magazine/sentry/sniper
+ allowed_ammo_types = list(/obj/item/ammo_magazine/sentry/sniper)
+
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable)
+ starting_attachment_types = list(
+ /obj/item/attachable/scope/unremovable,
+ )
+
+/obj/item/storage/box/crate/sentry_sniper
+ name = "\improper SST-574 sentry crate"
+ desc = "A large case containing all you need to set up an automated sentry."
+ icon_state = "sentry_case"
+ w_class = WEIGHT_CLASS_HUGE
+ max_w_class = WEIGHT_CLASS_HUGE
+ storage_slots = 6
+ max_storage_space = 16
+ can_hold = list(
+ /obj/item/weapon/gun/sentry/sniper_sentry,
+ /obj/item/ammo_magazine/sentry/sniper,
+ )
+ bypass_w_limit = list(
+ /obj/item/weapon/gun/sentry/sniper_sentry,
+ /obj/item/ammo_magazine/sentry/sniper,
+ )
+
+/obj/item/storage/box/crate/sentry_sniper/Initialize(mapload)
+ . = ..()
+ new /obj/item/weapon/gun/sentry/sniper_sentry(src)
+ new /obj/item/ammo_magazine/sentry/sniper(src)
+
+// Shotgun Sentry
+
+/obj/item/weapon/gun/sentry/shotgun_sentry
+ name = "\improper SHT-573 sentry gun"
+ desc = "A deployable, fully automatic turret with AI targeting capabilities. Armed with a heavy caliber SM-10 shotgun and a 100-round drum magazine."
+ icon_state = "shotgunsentry"
+
+ turret_range = 8
+ deploy_time = 5 SECONDS
+ max_shells = 75
+ fire_delay = 1 SECONDS
+ burst_amount = 1
+
+ scatter = 5
+
+ ammo_datum_type = /datum/ammo/bullet/turret/buckshot
+ default_ammo_type = /obj/item/ammo_magazine/sentry/shotgun
+ allowed_ammo_types = list(/obj/item/ammo_magazine/sentry/shotgun)
+
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102)
+ starting_attachment_types = list(
+ /obj/item/attachable/scope/unremovable/hsg_102,
+ )
+
+/obj/item/storage/box/crate/sentry_shotgun
+ name = "\improper SHT-573 sentry crate"
+ desc = "A large case containing all you need to set up an automated sentry."
+ icon_state = "sentry_case"
+ w_class = WEIGHT_CLASS_HUGE
+ max_w_class = WEIGHT_CLASS_HUGE
+ storage_slots = 6
+ max_storage_space = 16
+ can_hold = list(
+ /obj/item/weapon/gun/sentry/shotgun_sentry,
+ /obj/item/ammo_magazine/sentry/shotgun,
+ )
+ bypass_w_limit = list(
+ /obj/item/weapon/gun/sentry/shotgun_sentry,
+ /obj/item/ammo_magazine/sentry/shotgun,
+ )
+
+/obj/item/storage/box/crate/sentry_shotgun/Initialize(mapload)
+ . = ..()
+ new /obj/item/weapon/gun/sentry/shotgun_sentry(src)
+ new /obj/item/ammo_magazine/sentry/shotgun(src)
+
+// Flamethrower Sentry
+
+/obj/item/weapon/gun/sentry/flamer_sentry
+ name = "\improper SFT-573 sentry gun"
+ desc = "A deployable, fully automatic turret with AI targeting capabilities. Armed with a heavy flamethrower and a 200-round drum magazine."
+ icon_state = "flamersentry"
+
+ turret_range = 8
+ deploy_time = 5 SECONDS
+ max_shells = 200
+ fire_delay = 2 SECONDS
+ burst_amount = 1
+
+ scatter = 5
+
+ ammo_datum_type = /datum/ammo/flamer
+ default_ammo_type = /obj/item/ammo_magazine/sentry/flamer
+ allowed_ammo_types = list(/obj/item/ammo_magazine/sentry/flamer)
+
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+
+ attachable_allowed = list(/obj/item/attachable/scope/unremovable/hsg_102)
+ starting_attachment_types = list(
+ /obj/item/attachable/scope/unremovable/hsg_102,
+ )
+
+/obj/item/storage/box/crate/sentry_flamer
+ name = "\improper SHT-573 sentry crate"
+ desc = "A large case containing all you need to set up an automated sentry."
+ icon_state = "sentry_case"
+ w_class = WEIGHT_CLASS_HUGE
+ max_w_class = WEIGHT_CLASS_HUGE
+ storage_slots = 6
+ max_storage_space = 16
+ can_hold = list(
+ /obj/item/weapon/gun/sentry/flamer_sentry,
+ /obj/item/ammo_magazine/sentry/flamer,
+ )
+ bypass_w_limit = list(
+ /obj/item/weapon/gun/sentry/flamer_sentry,
+ /obj/item/ammo_magazine/sentry/flamer,
+ )
+
+/obj/item/storage/box/crate/sentry_flamer/Initialize(mapload)
+ . = ..()
+ new /obj/item/weapon/gun/sentry/flamer_sentry(src)
+ new /obj/item/ammo_magazine/sentry/flamer(src)
diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm
index 422efb203c7b4..1c8be523a0ad4 100644
--- a/code/modules/projectiles/guns/shotguns.dm
+++ b/code/modules/projectiles/guns/shotguns.dm
@@ -4,20 +4,25 @@
caliber = CALIBER_12G //codex
max_chamber_items = 8 //codex
load_method = SINGLE_CASING //codex
+ icon = 'icons/obj/items/guns/shotguns.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/shotguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/shotguns_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/shotgun.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/shotgun_empty.ogg'
reload_sound = 'sound/weapons/guns/interact/shotgun_shell_insert.ogg'
hand_reload_sound = 'sound/weapons/guns/interact/shotgun_shell_insert.ogg'
cocked_sound = 'sound/weapons/guns/interact/shotgun_reload.ogg'
opened_sound = 'sound/weapons/guns/interact/shotgun_open.ogg'
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_HANDFULS
type_of_casings = "shell"
allowed_ammo_types = list()
aim_slowdown = 0.35
- wield_delay = 0.6 SECONDS //Shotguns are really easy to put up to fire, since they are designed for CQC (at least compared to a rifle)
+ wield_delay = 0.8 SECONDS //Shotguns are really easy to put up to fire, since they are designed for CQC (at least compared to a rifle)
gun_skill_category = SKILL_SHOTGUNS
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
fire_delay = 6
accuracy_mult = 1.15
@@ -27,8 +32,7 @@
recoil = 2
recoil_unwielded = 4
movement_acc_penalty_mult = 2
- lower_akimbo_accuracy = 3
- upper_akimbo_accuracy = 5
+ akimbo_scatter_mod = 8
placed_overlay_iconstate = "shotgun"
@@ -39,11 +43,11 @@
/obj/item/weapon/gun/shotgun/combat
name = "\improper SH-221 tactical shotgun"
desc = "The Nanotrasen SH-221 Shotgun, a quick-firing semi-automatic shotgun based on the centuries old Benelli M4 shotgun. Only issued to the TGMC in small numbers."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "mk221"
item_state = "mk221"
fire_sound = 'sound/weapons/guns/fire/shotgun_automatic.ogg'
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
max_chamber_items = 9
attachable_allowed = list(
@@ -74,12 +78,12 @@
name = "\improper SH-39 combat shotgun"
desc = "The Terran Armories SH-39 combat shotgun is a semi automatic shotgun used by breachers and pointmen within the TGMC squads. Uses 12 gauge shells."
force = 20 //Has a stock already
- flags_equip_slot = ITEM_SLOT_BACK
- icon = 'icons/Marine/gun64.dmi'
+ equip_slot_flags = ITEM_SLOT_BACK
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
icon_state = "t39"
item_state = "t39"
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_sh39.ogg'
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
attachable_allowed = list(
/obj/item/attachable/bayonet,
@@ -110,9 +114,13 @@
damage_mult = 0.7 //30% less damage. Faster firerate.
recoil = 2
recoil_unwielded = 4
- wield_delay = 0.8 SECONDS
+ wield_delay = 1 SECONDS
akimbo_additional_delay = 0.9
+/obj/item/weapon/gun/shotgun/combat/standardmarine/beginner
+ default_ammo_type = /datum/ammo/bullet/shotgun/slug
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/heavy_barrel, /obj/item/attachable/verticalgrip, /obj/item/attachable/stock/t39stock)
+
/obj/item/weapon/gun/shotgun/combat/masterkey
name = "masterkey shotgun"
desc = "A weapon-mounted, three-shot shotgun. Reloadable with any normal 12 gauge shell. The short barrel reduces the ammo's effectiveness drastically in exchange for fitting as a attachment.."
@@ -124,7 +132,7 @@
slot = ATTACHMENT_SLOT_UNDER
attach_delay = 3 SECONDS
detach_delay = 3 SECONDS
- flags_gun_features = GUN_IS_ATTACHMENT|GUN_AMMO_COUNTER|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_CAN_POINTBLANK|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_IS_ATTACHMENT|GUN_AMMO_COUNTER|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_CAN_POINTBLANK|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
damage_mult = 0.6 // 40% less damage, but MUCH higher falloff.
scatter = 3
@@ -140,7 +148,7 @@
/obj/item/weapon/gun/shotgun/double
name = "double barrel shotgun"
desc = "A double barreled over and under shotgun of archaic, but sturdy design. Uses 12 gauge shells, but can only hold 2 at a time."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "dshotgun"
item_state = "dshotgun"
max_chamber_items = 2 //codex
@@ -157,7 +165,7 @@
/obj/item/attachable/flashlight/under,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_TOGGLES_OPEN|AMMO_RECIEVER_TOGGLES_OPEN_EJECTS|AMMO_RECIEVER_HANDFULS
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 21,"rail_x" = 15, "rail_y" = 22, "under_x" = 21, "under_y" = 16, "stock_x" = 21, "stock_y" = 16)
@@ -168,15 +176,16 @@
recoil = 2
recoil_unwielded = 4
aim_slowdown = 0.6
+ damage_mult = 0.7
/obj/item/weapon/gun/shotgun/double/sawn
name = "sawn-off shotgun"
desc = "A double barreled shotgun whose barrel has been artificially shortened to reduce range for further CQC potiential."
icon_state = "sshotgun"
item_state = "sshotgun"
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
attachable_allowed = list()
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES|GUN_WIELDED_FIRING_ONLY
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES|GUN_WIELDED_FIRING_ONLY
attachable_offset = list("muzzle_x" = 30, "muzzle_y" = 20,"rail_x" = 11, "rail_y" = 22, "under_x" = 18, "under_y" = 16, "stock_x" = 18, "stock_y" = 16)
fire_delay = 2
@@ -192,7 +201,7 @@
/obj/item/weapon/gun/shotgun/double/marine
name = "\improper SH-34 double barrel shotgun"
desc = "A double barreled shotgun of archaic, but sturdy design used by the TGMC. Due to reports of barrel bursting, the abiility to fire both barrels has been disabled. Uses 12 gauge shells, but can only hold 2 at a time."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "ts34"
item_state = "ts34"
max_chamber_items = 2 //codex
@@ -214,7 +223,7 @@
/obj/item/attachable/scope/mini,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 17,"rail_x" = 15, "rail_y" = 19, "under_x" = 21, "under_y" = 13, "stock_x" = 13, "stock_y" = 16)
fire_delay = 0.65 SECONDS
@@ -232,7 +241,7 @@
/obj/item/weapon/gun/shotgun/pump
name = "\improper V10 pump shotgun"
desc = "A classic design, using the outdated shotgun frame. The V10 combines close-range firepower with long term reliability.\nRequires a pump, which is the Unique Action key."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "v10"
item_state = "v10"
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
@@ -257,7 +266,7 @@
/obj/item/attachable/magnetic_harness,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_HANDFULS|AMMO_RECIEVER_REQUIRES_UNIQUE_ACTION|AMMO_RECIEVER_UNIQUE_ACTION_LOCKS
cocked_message = "You rack the pump."
cock_locked_message = "The pump is locked! Fire it first!"
@@ -280,7 +289,7 @@
/obj/item/weapon/gun/shotgun/pump/cmb
name = "\improper SH-12 Paladin pump shotgun"
desc = "A nine-round pump action shotgun. A shotgun used for hunting, home defence and police work, many versions of it exist and are used by just about anyone."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
icon_state = "pal12"
item_state = "pal12"
fire_sound = 'sound/weapons/guns/fire/shotgun_cmb.ogg'
@@ -298,7 +307,7 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/stock/pal12,
)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
attachable_offset = list("muzzle_x" = 38, "muzzle_y" = 19,"rail_x" = 14, "rail_y" = 19, "under_x" = 37, "under_y" = 16, "stock_x" = 15, "stock_y" = 14)
starting_attachment_types = list(
/obj/item/attachable/stock/pal12,
@@ -325,9 +334,10 @@
/obj/item/weapon/gun/shotgun/pump/trenchgun
name = "\improper L-4034 trenchgun"
desc = "A six-round pump action shotgun. A shotgun used for hunting, home defence and police work, many versions of it exist and are used by just about anyone."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
icon_state = "trenchgun"
item_state = "trenchgun"
+ cock_animation = "trenchgun_pump"
fire_sound = 'sound/weapons/guns/fire/trenchgun.ogg'
reload_sound = 'sound/weapons/guns/interact/shotgun_cmb_insert.ogg'
cocked_sound = 'sound/weapons/guns/interact/trenchgun_pump.ogg'
@@ -343,7 +353,7 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/stock/trenchgun,
)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
attachable_offset = list("muzzle_x" = 34, "muzzle_y" = 19,"rail_x" = 12, "rail_y" = 21, "under_x" = 37, "under_y" = 16, "stock_x" = 0, "stock_y" = 12)
starting_attachment_types = list(
/obj/item/attachable/stock/trenchgun,
@@ -379,9 +389,13 @@
/obj/item/weapon/gun/shotgun/pump/bolt
name = "\improper Mosin Nagant rifle"
desc = "A mosin nagant rifle, even just looking at it you can feel the cosmoline already. Commonly known by its slang, \"Moist Nugget\", by downbrained colonists and outlaws."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "mosin"
item_state = "mosin"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mosin.ogg'
fire_rattle = 'sound/weapons/guns/fire/tgmc/kinetic/gun_mosin_low.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/sniper_empty.ogg'
@@ -408,10 +422,9 @@
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
/obj/item/attachable/stock/mosin,
- /obj/item/attachable/shoulder_mount,
)
- flags_item_map_variant = NONE
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ item_map_variant_flags = NONE
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 37, "muzzle_y" = 18,"rail_x" = 14, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 15, "stock_y" = 12)
starting_attachment_types = list(
/obj/item/attachable/scope/mosin,
@@ -431,7 +444,7 @@
recoil_unwielded = 4
cock_delay = 12
aim_slowdown = 1
- wield_delay = 1.2 SECONDS
+ wield_delay = 1.4 SECONDS
movement_acc_penalty_mult = 4.5
placed_overlay_iconstate = "wood"
@@ -445,10 +458,14 @@
/obj/item/weapon/gun/shotgun/double/martini
name = "\improper Martini Henry lever action rifle"
desc = "A lever action with room for a single round of .557/440 ball. Perfect for any kind of hunt, be it elephant or xeno with how quick to the draw it is."
- flags_equip_slot = ITEM_SLOT_BACK
- icon = 'icons/Marine/gun64.dmi'
+ equip_slot_flags = ITEM_SLOT_BACK
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "martini"
item_state = "martini"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
shell_eject_animation = "martini_flick"
caliber = CALIBER_557 //codex
muzzle_flash_lum = 7
@@ -472,10 +489,9 @@
/obj/item/attachable/scope/marine,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 45, "muzzle_y" = 23,"rail_x" = 17, "rail_y" = 25, "under_x" = 19, "under_y" = 14, "stock_x" = 15, "stock_y" = 12)
/* RU TGMC EDIT
actions_types = list(/datum/action/item_action/aim_mode) RU TGMC EDIT
@@ -492,10 +508,11 @@ RU TGMC EDIT */
recoil_unwielded = 4
aim_slowdown = 1
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
movement_acc_penalty_mult = 5
placed_overlay_iconstate = "wood"
+ damage_mult = 1
//***********************************************************
// Derringer
@@ -505,6 +522,7 @@ RU TGMC EDIT */
desc = "The R-2395 Derringer has been a classic for centuries. This latest iteration combines plasma propulsion powder with the classic design to make an assasination weapon that will leave little to chance."
icon_state = "derringer"
item_state = "tp17"
+ icon = 'icons/obj/items/guns/pistols.dmi'
gun_skill_category = SKILL_PISTOLS
w_class = WEIGHT_CLASS_TINY
caliber = CALIBER_41RIM //codex
@@ -517,7 +535,7 @@ RU TGMC EDIT */
cocked_sound = 'sound/weapons/guns/interact/martini_cocked.ogg'
opened_sound = 'sound/weapons/guns/interact/martini_open.ogg'
attachable_allowed = list()
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
fire_delay = 0.2 SECONDS
scatter = 0
@@ -525,7 +543,8 @@ RU TGMC EDIT */
recoil = 0
recoil_unwielded = 0
aim_slowdown = 0
- wield_delay = 0.1 SECONDS
+ wield_delay = 0.3 SECONDS
+ damage_mult = 1
/obj/item/weapon/gun/shotgun/double/derringer/Initialize(mapload)
. = ..()
@@ -540,7 +559,7 @@ RU TGMC EDIT */
/obj/item/weapon/gun/shotgun/pump/lever
name = "lever action rifle"
desc = "A .44 magnum lever action rifle with side loading port. It has a low fire rate, but it packs quite a punch in hunting."
- icon = 'icons/obj/items/gun.dmi'
+ icon = 'icons/obj/items/guns/shotguns.dmi'
icon_state = "mares_leg"
item_state = "mares_leg"
fire_sound = 'sound/weapons/guns/fire/leveraction.ogg'//I like how this one sounds.
@@ -553,7 +572,7 @@ RU TGMC EDIT */
gun_skill_category = SKILL_RIFLES
cocked_sound = 'sound/weapons/guns/interact/ak47_cocked.ogg'//good enough for now.
cocked_message = "You work the lever."
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/scope/mini,
@@ -563,7 +582,7 @@ RU TGMC EDIT */
/obj/item/attachable/bayonet,
)
attachable_offset = list("muzzle_x" = 50, "muzzle_y" = 21,"rail_x" = 8, "rail_y" = 21, "under_x" = 37, "under_y" = 16, "stock_x" = 20, "stock_y" = 14)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
fire_delay = 8
accuracy_mult = 1.2
@@ -581,9 +600,13 @@ RU TGMC EDIT */
/obj/item/weapon/gun/shotgun/pump/lever/repeater
name = "\improper Leicester Repeater"
desc = "The gun that won the west or so they say. But space is a very different kind of frontier all together, chambered for .45-70 Governemnt."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "leicrepeater"
item_state = "leicrepeater"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_repeater.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/sniper_empty.ogg'
reload_sound = 'sound/weapons/guns/interact/mosin_reload.ogg'
@@ -593,7 +616,7 @@ RU TGMC EDIT */
default_ammo_type = /datum/ammo/bullet/rifle/repeater
gun_skill_category = SKILL_RIFLES
cocked_sound = 'sound/weapons/guns/interact/ak47_cocked.ogg'//good enough for now.
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
attachable_allowed = list(
/obj/item/attachable/reddot,
/obj/item/attachable/scope/mini,
@@ -605,7 +628,7 @@ RU TGMC EDIT */
/obj/item/attachable/motiondetector,
)
attachable_offset = list ("muzzle_x" = 45, "muzzle_y" = 23,"rail_x" = 21, "rail_y" = 23, "under_x" = 19, "under_y" = 14, "stock_x" = 15, "stock_y" = 12)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
actions_types = list(/datum/action/item_action/aim_mode)
aim_fire_delay = 0.3 SECONDS
aim_speed_modifier = 2
@@ -622,6 +645,9 @@ RU TGMC EDIT */
aim_slowdown = 0.6
movement_acc_penalty_mult = 5
+/obj/item/weapon/gun/shotgun/pump/lever/repeater/beginner
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/bayonet)
+
//------------------------------------------------------
//MBX900 Lever Action Shotgun
/obj/item/weapon/gun/shotgun/pump/lever/mbx900
@@ -660,8 +686,9 @@ RU TGMC EDIT */
)
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 17,"rail_x" = 12, "rail_y" = 19, "under_x" = 27, "under_y" = 16, "stock_x" = 0, "stock_y" = 0)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
fire_delay = 0.6 SECONDS
accuracy_mult = 1.2
cock_delay = 0.2 SECONDS
@@ -671,22 +698,14 @@ RU TGMC EDIT */
/obj/item/weapon/gun/shotgun/pump/t35
name = "\improper SH-35 pump shotgun"
desc = "The Terran Armories SH-35 is the shotgun used by the TerraGov Marine Corps. It's used as a close quarters tool when someone wants something more suited for close range than most people, or as an odd sidearm on your back for emergencies. Uses 12 gauge shells.\nRequires a pump, which is the Unique Action key."
- flags_equip_slot = ITEM_SLOT_BACK
- icon = 'icons/Marine/gun64.dmi'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
- cock_animation = GUN_ICONSTATE_PUMP
+ equip_slot_flags = ITEM_SLOT_BACK
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
+ icon_state = "t35"
+ item_state = "t35"
+ cock_animation = "t35_pump"
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_sh35.ogg'
max_chamber_items = 8
- greyscale_config = /datum/greyscale_config/gun/gun64/shotgun
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t35,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t35,
- slot_back_str = /datum/greyscale_config/worn_gun/t35,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t35,
- )
attachable_allowed = list(
/obj/item/attachable/bayonet,
/obj/item/attachable/bayonetknife,
@@ -704,12 +723,11 @@ RU TGMC EDIT */
/obj/item/attachable/foldable/t35stock,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
starting_attachment_types = list(/obj/item/attachable/foldable/t35stock)
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 9, "rail_y" = 21, "under_x" = 18, "under_y" = 12, "stock_x" = -3, "stock_y" = 16)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
fire_delay = 20
scatter_unwielded = 10
@@ -733,16 +751,20 @@ RU TGMC EDIT */
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
starting_attachment_types = list(/obj/item/attachable/foldable/t35stock, /obj/item/attachable/angledgrip, /obj/item/attachable/magnetic_harness)
+/obj/item/weapon/gun/shotgun/pump/t35/beginner
+ default_ammo_type = /datum/ammo/bullet/shotgun/slug
+ starting_attachment_types = list(/obj/item/attachable/foldable/t35stock, /obj/item/attachable/gyro, /obj/item/attachable/magnetic_harness, /obj/item/attachable/bayonet)
+
//-------------------------------------------------------
//THE MYTH, THE GUN, THE LEGEND, THE DEATH, THE ZX
/obj/item/weapon/gun/shotgun/zx76
name = "\improper ZX-76 assault shotgun"
desc = "The ZX-76 Assault Shotgun, a incredibly rare, double barreled semi-automatic combat shotgun with a twin shot mode. Possibly the unrivaled master of CQC. Has a 9 round internal magazine."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
icon_state = "zx-76"
item_state = "zx-76"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
max_chamber_items = 9 //codex
caliber = CALIBER_12G //codex
load_method = SINGLE_CASING //codex
@@ -767,7 +789,7 @@ RU TGMC EDIT */
fire_delay = 1.75 SECONDS
damage_mult = 0.9
- wield_delay = 0.75 SECONDS
+ wield_delay = 0.95 SECONDS
burst_amount = 2
burst_delay = 0.01 SECONDS //basically instantaneous two shots
extra_delay = 0.5 SECONDS
@@ -785,15 +807,15 @@ RU TGMC EDIT */
/obj/item/weapon/gun/shotgun/som
name = "\improper V-51 combat shotgun"
desc = "The V-51 is the main shotgun utilised by the Sons of Mars. Slower firing than some other semi automatic shotguns, but packs more of a kick."
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
icon_state = "v51"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/shotguns64.dmi'
item_state = "v51"
fire_sound = "shotgun_som"
dry_fire_sound = 'sound/weapons/guns/fire/v51_empty.ogg'
reload_sound = 'sound/weapons/guns/interact/v51_load.ogg'
hand_reload_sound = 'sound/weapons/guns/interact/v51_load.ogg'
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SMOKE_PARTICLES
default_ammo_type = /datum/ammo/bullet/shotgun/buckshot
max_chamber_items = 9
attachable_allowed = list(
@@ -819,7 +841,7 @@ RU TGMC EDIT */
recoil = 1
recoil_unwielded = 4
aim_slowdown = 0.35
- wield_delay = 0.65 SECONDS
+ wield_delay = 0.85 SECONDS
/obj/item/weapon/gun/shotgun/som/pointman
starting_attachment_types = list(/obj/item/attachable/bayonet, /obj/item/attachable/motiondetector)
@@ -858,8 +880,8 @@ RU TGMC EDIT */
icon_state = "va61"
fire_sound = 'sound/weapons/guns/fire/pred_plasma_shot.ogg'
max_chamber_items = 2
- flags_gun_features = GUN_IS_ATTACHMENT|GUN_AMMO_COUNTER|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY
- flags_attach_features = NONE
+ gun_features_flags = GUN_IS_ATTACHMENT|GUN_AMMO_COUNTER|GUN_ATTACHMENT_FIRE_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_WIELDED_FIRING_ONLY
+ attach_features_flags = NONE
slot = ATTACHMENT_SLOT_STOCK
default_ammo_type = /datum/ammo/bullet/micro_rail/airburst
caliber = CALIBER_10G_RAIL
diff --git a/code/modules/projectiles/guns/smgs.dm b/code/modules/projectiles/guns/smgs.dm
index 9efce183ec928..d4602c0afa285 100644
--- a/code/modules/projectiles/guns/smgs.dm
+++ b/code/modules/projectiles/guns/smgs.dm
@@ -1,4 +1,9 @@
/obj/item/weapon/gun/smg
+ icon = 'icons/obj/items/guns/submachineguns.dmi'
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/submachineguns_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/submachineguns_right_1.dmi',
+ )
fire_sound = 'sound/weapons/guns/fire/smg_light.ogg'
unload_sound = 'sound/weapons/guns/interact/smg_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/smg_reload.ogg'
@@ -8,7 +13,7 @@
load_method = MAGAZINE //codex
force = 8
w_class = WEIGHT_CLASS_BULKY
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
attachable_allowed = list(
/obj/item/attachable/suppressor,
/obj/item/attachable/reddot,
@@ -16,7 +21,7 @@
/obj/item/attachable/magnetic_harness,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_BURSTFIRE, GUN_FIREMODE_AUTOBURST)
gun_skill_category = SKILL_SMGS
@@ -24,7 +29,7 @@
burst_amount = 3
recoil_unwielded = 0.5
akimbo_additional_delay = 0.2
- movement_acc_penalty_mult = 3
+ akimbo_scatter_mod = 8
//-------------------------------------------------------
// MP-19 Machinepistol. It fits here more.
@@ -38,7 +43,7 @@
caliber = CALIBER_10X20_CASELESS //codex
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_AUTOBURST)
max_shells = 30 //codex
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/standard_machinepistol
allowed_ammo_types = list(/obj/item/ammo_magazine/smg/standard_machinepistol)
@@ -75,14 +80,10 @@
aim_slowdown = 0.15
movement_acc_penalty_mult = 2
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
-
- burst_amount = 1
- autoburst_delay = 0.1 SECONDS
- autoburst_delay = 0.1 SECONDS //this makes it fuller auto
- burst_accuracy_bonus = -0.3
- burst_scatter_mult = 25
+ akimbo_scatter_mod = 24
+ burst_amount = 5
+ burst_delay = 0.1 SECONDS
+ akimbo_additional_delay = 20 // Literally do not even bother to try
/obj/item/weapon/gun/smg/standard_machinepistol/compact
starting_attachment_types = list(/obj/item/attachable/foldable/t19stock, /obj/item/attachable/reddot, /obj/item/attachable/compensator, /obj/item/attachable/lasersight)
@@ -100,24 +101,16 @@
name = "\improper SMG-90 submachinegun"
desc = "The SMG-90 is the TerraGov Marine Corps standard issue SMG. Its known for it's compact size and ease of use inside the field. It's usually carried by troops who want a lightweight firearm to rush with. It uses 10x20mm caseless rounds."
fire_sound = 'sound/weapons/guns/fire/tgmc/kinetic/gun_smg90.ogg'
- icon_state = GUN_ICONSTATE_LOADED
- item_state = GUN_ICONSTATE_LOADED
+ icon_state = "t90"
+ item_state = "t90"
caliber = CALIBER_10X20_CASELESS //codex
max_shells = 50 //codex
- flags_equip_slot = ITEM_SLOT_BACK
- wield_delay = 0.5 SECONDS
+ equip_slot_flags = ITEM_SLOT_BACK
+ wield_delay = 0.7 SECONDS
force = 20
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/standard_smg
allowed_ammo_types = list(/obj/item/ammo_magazine/smg/standard_smg)
- greyscale_config = /datum/greyscale_config/gun/t90
- colorable_allowed = PRESET_COLORS_ALLOWED
- item_icons = list(
- slot_l_hand_str = /datum/greyscale_config/gun_inhand/t90,
- slot_r_hand_str = /datum/greyscale_config/gun_inhand/r_hand/t90,
- slot_back_str = /datum/greyscale_config/worn_gun/t90,
- slot_s_store_str = /datum/greyscale_config/worn_gun/suit/t90,
- )
attachable_allowed = list(
/obj/item/attachable/suppressor,
/obj/item/attachable/reddot,
@@ -131,10 +124,9 @@
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/motiondetector,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 15,"rail_x" = 22, "rail_y" = 22, "under_x" = 17, "under_y" = 15, "stock_x" = 24, "stock_y" = 10)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -147,8 +139,6 @@
scatter_unwielded = 8
aim_slowdown = 0.2
burst_amount = 0
- upper_akimbo_accuracy = 4
- lower_akimbo_accuracy = 2
placed_overlay_iconstate = "t90"
@@ -161,13 +151,69 @@
/obj/item/weapon/gun/smg/standard_smg/tactical
starting_attachment_types = list(/obj/item/attachable/compensator, /obj/item/attachable/reddot, /obj/item/attachable/lasersight)
+//-------------------------------------------------------
+//Da slapper.
+
+/obj/item/weapon/gun/smg/standard_heavysmg
+ name = "\improper SMG-45 heavy submachinegun"
+ desc = "The SMG-45 is a heavier than usual subgun used by the TerraGov Marine Corps. Best known for carrying a punch within a small package. It's usually carried by troops who want a lightweight firearm to rush with while beating a mean punch, however it struggles at range. It uses 10x20mm caseless rounds."
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
+ icon_state = "t45"
+ item_state = "t45"
+ caliber = CALIBER_45ACP //codex
+ max_shells = 40 //codex
+ fire_sound = 'sound/weapons/guns/fire/skorpevo.ogg'
+ unload_sound = 'sound/weapons/guns/interact/mp5_unload.ogg'
+ reload_sound = 'sound/weapons/guns/interact/mp5_reload.ogg'
+ equip_slot_flags = ITEM_SLOT_BACK
+ type_of_casings = null
+ default_ammo_type = /obj/item/ammo_magazine/smg/standard_heavysmg
+ allowed_ammo_types = list(
+ /obj/item/ammo_magazine/smg/standard_heavysmg,
+ /obj/item/ammo_magazine/smg/standard_heavysmg/squashhead,
+ )
+ attachable_allowed = list(
+ /obj/item/attachable/suppressor,
+ /obj/item/attachable/reddot,
+ /obj/item/attachable/verticalgrip,
+ /obj/item/attachable/compensator,
+ /obj/item/attachable/lasersight,
+ /obj/item/attachable/flashlight,
+ /obj/item/attachable/motiondetector,
+ /obj/item/attachable/flashlight/under,
+ /obj/item/attachable/extended_barrel,
+ /obj/item/attachable/heavy_barrel,
+ /obj/item/attachable/scope/mini,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/burstfire_assembly,
+ /obj/item/weapon/gun/pistol/plasma_pistol,
+ /obj/item/weapon/gun/shotgun/combat/masterkey,
+ /obj/item/weapon/gun/flamer/mini_flamer,
+ /obj/item/weapon/gun/grenade_launcher/underslung,
+ /obj/item/attachable/gyro,
+ )
+
+ attachable_offset = list("muzzle_x" = 43, "muzzle_y" = 19,"rail_x" = 22, "rail_y" = 23, "under_x" = 32, "under_y" = 14, "stock_x" = 24, "stock_y" = 16)
+ actions_types = list(/datum/action/item_action/aim_mode)
+ aim_fire_delay = 0.1 SECONDS
+
+ aim_slowdown = 0.25
+ accuracy_mult = 1.15
+ accuracy_mult_unwielded = 0.85
+ fire_delay = 0.25 SECONDS
+ burst_delay = 0.2 SECONDS
+ burst_amount = 3
+ scatter = 2
+ scatter_unwielded = 11
+ akimbo_additional_delay = 0.4
+
//-------------------------------------------------------
//M-25 SMG
/obj/item/weapon/gun/smg/m25
name = "\improper SMG-25 submachinegun"
desc = "The RivArms SMG-25 submachinegun, an update to a classic design. A light firearm capable of effective one-handed use that is ideal for close to medium range engagements. Uses 10x20mm rounds in a high capacity magazine."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
icon_state = "m25"
item_state = "m25"
caliber = CALIBER_10X20_CASELESS //codex
@@ -175,7 +221,7 @@
fire_sound = 'sound/weapons/guns/fire/mp5.ogg'
unload_sound = 'sound/weapons/guns/interact/mp5_unload.ogg'
reload_sound = 'sound/weapons/guns/interact/mp5_reload.ogg'
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/m25
allowed_ammo_types = list(
@@ -213,8 +259,6 @@
aim_slowdown = 0.15
burst_amount = 3
akimbo_additional_delay = 0.4
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
damage_falloff_mult = 0.9
/obj/item/weapon/gun/smg/m25/holstered
@@ -223,6 +267,12 @@
/obj/item/weapon/gun/smg/m25/magharness
starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/compensator, /obj/item/attachable/gyro)
+/obj/item/weapon/gun/smg/m25/vgrip
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/compensator, /obj/item/attachable/verticalgrip)
+
+/obj/item/weapon/gun/smg/m25/plasma
+ starting_attachment_types = list(/obj/item/attachable/magnetic_harness, /obj/item/attachable/compensator, /obj/item/weapon/gun/pistol/plasma_pistol)
+
/obj/item/weapon/gun/smg/m25/elite
name = "\improper SMG-25B2 submachinegun"
desc = "The RivArms SMG-25 submachinegun, B2 variant. Has an integrated barrel charger. This reliable weapon fires armor piercing 10x20mm rounds and is used by elite troops."
@@ -244,7 +294,7 @@
/obj/item/attachable/gyro,
)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
burst_amount = 4
accuracy_mult = 1.1
@@ -301,12 +351,12 @@
/obj/item/weapon/gun/smg/skorpion
name = "\improper CZ-81 submachinegun"
desc = "A robust, 20th century firearm that's a combination of pistol and submachinegun. Fires .32ACP caliber rounds from a 20 round magazine."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
icon_state = "skorpion"
item_state = "skorpion"
caliber = CALIBER_32ACP //codex
max_shells = 20 //codex
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_NORMAL
fire_sound = 'sound/weapons/guns/fire/skorpion.ogg'
unload_sound = 'sound/weapons/guns/interact/skorpion_unload.ogg'
@@ -331,7 +381,7 @@
scatter_unwielded = 6
fire_delay = 0.1 SECONDS
aim_slowdown = 0.3
- wield_delay = 0.3 SECONDS
+ wield_delay = 0.5 SECONDS
/obj/item/weapon/gun/smg/skorpion/mag_harness
starting_attachment_types = list(/obj/item/attachable/foldable/skorpion_stock, /obj/item/attachable/magnetic_harness)
@@ -342,12 +392,12 @@
/obj/item/weapon/gun/smg/ppsh
name = "\improper PPSh-17b submachinegun"
desc = "The PPSh-17b or \"Papasha\" is replica of a 20th century USSR model submachinegun that many terrorist organizations had copied all over the years. Despite its small-hitting firepower, its reliablity, extreme longevity and high firepower rate proves useful for the hands of the user."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
icon_state = "ppsh"
item_state = "ppsh"
caliber = CALIBER_762X25 //codex
max_shells = 42 //codex
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
fire_sound = 'sound/weapons/guns/fire/ppsh.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/ppsh_empty.ogg'
unload_sound = 'sound/weapons/guns/interact/ppsh_unload.ogg'
@@ -374,7 +424,7 @@
/obj/item/attachable/foldable/bipod,
)
- flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 38, "muzzle_y" = 19,"rail_x" = 13, "rail_y" = 21, "under_x" = 26, "under_y" = 15, "stock_x" = 19, "stock_y" = 13)
actions_types = list(/datum/action/item_action/aim_mode)
aim_fire_delay = 0.15 SECONDS
@@ -423,7 +473,7 @@
scatter = 0
scatter_unwielded = 4
aim_slowdown = 0.15
- wield_delay = 0.2 SECONDS
+ wield_delay = 0.4 SECONDS
/obj/item/weapon/gun/smg/uzi/mag_harness
default_ammo_type = /obj/item/ammo_magazine/smg/uzi/extended
@@ -436,11 +486,11 @@
name = "\improper V-21 submachinegun"
desc = "The V-21 is the principal submachinegun used by the Sons of Mars, designed to be used effectively one or two handed with a variable rate of fire. When fired at full speed it's performance is severely degraded unless used properly wielded, while the lower rate of fire can still be effectively used one handed when necessary. It uses 10x20mm caseless rounds."
icon_state = "v21"
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
item_state = "v21"
caliber = CALIBER_10X20_CASELESS
max_shells = 50
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/som
allowed_ammo_types = list(
@@ -471,7 +521,7 @@
fire_delay = 0.15 SECONDS
aim_slowdown = 0.15
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
accuracy_mult = 1.05
accuracy_mult_unwielded = 0.9
@@ -490,8 +540,6 @@
burst_scatter_mult = 15
akimbo_additional_delay = 0.7
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
/obj/item/weapon/gun/smg/som/scout
starting_attachment_types = list(
@@ -534,12 +582,12 @@
/obj/item/weapon/gun/smg/icc_machinepistol
name = "\improper PL-38 machinepistol"
desc = "The PL-38 is a machinepistol used by rearline ICCAF personnel, it presents solid performance at longer ranges in a compact package, although suffers due to a slow rate of fire for its class. It uses 10x20mm caseless rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
icon_state = "pl38"
item_state = "pl38"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/submachineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/submachineguns_right_64.dmi',
)
inhand_x_dimension = 64
@@ -548,7 +596,7 @@
caliber = CALIBER_10X20_CASELESS //codex
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC, GUN_FIREMODE_AUTOBURST)
max_shells = 32 //codex
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/icc_machinepistol
allowed_ammo_types = list(/obj/item/ammo_magazine/smg/icc_machinepistol, /obj/item/ammo_magazine/smg/icc_machinepistol/hp)
@@ -587,10 +635,7 @@
scatter = 2
scatter_unwielded = 5
aim_slowdown = 0.2
- wield_delay = 0.35 SECONDS
-
- upper_akimbo_accuracy = 5
- lower_akimbo_accuracy = 3
+ wield_delay = 0.55 SECONDS
/obj/item/weapon/gun/smg/icc_machinepistol/medic
starting_attachment_types = list(/obj/item/attachable/foldable/icc_machinepistol, /obj/item/attachable/magnetic_harness, /obj/item/attachable/verticalgrip, /obj/item/attachable/extended_barrel)
@@ -601,12 +646,12 @@
/obj/item/weapon/gun/smg/icc_pdw
name = "\improper L-40 personal defense weapon"
desc = "The L-40 is the primer ICCAF submachinegun, generally termed as a 'PDW' due to its armor-piercing high velocity round, while it has adequate ranged performance, it is mostly tuned for at close quarters combat. It uses 4.6mm high velocity caseless rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/submachineguns64.dmi'
icon_state = "l40"
item_state = "l40"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/submachineguns_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/submachineguns_right_64.dmi',
)
inhand_x_dimension = 64
@@ -614,7 +659,7 @@
caliber = CALIBER_46X30
max_shells = 45
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
type_of_casings = null
default_ammo_type = /obj/item/ammo_magazine/smg/icc_pdw
allowed_ammo_types = list(/obj/item/ammo_magazine/smg/icc_pdw)
@@ -650,7 +695,7 @@
burst_amount = 1
fire_delay = 0.15 SECONDS
aim_slowdown = 0.25
- wield_delay = 0.4 SECONDS
+ wield_delay = 0.6 SECONDS
accuracy_mult = 1.05
accuracy_mult_unwielded = 0.9
diff --git a/code/modules/projectiles/guns/specialist.dm b/code/modules/projectiles/guns/specialist.dm
index 9d23e168cf874..f070a573539c0 100644
--- a/code/modules/projectiles/guns/specialist.dm
+++ b/code/modules/projectiles/guns/specialist.dm
@@ -17,18 +17,23 @@ Because this parent type did not exist
Note that this means that snipers will have a slowdown of 3, due to the scope
*/
/obj/item/weapon/gun/rifle/sniper
+ icon = 'icons/obj/items/guns/marksman.dmi'
aim_slowdown = 1
gun_skill_category = SKILL_RIFLES
- wield_delay = 1 SECONDS
+ wield_delay = 1.2 SECONDS
//Pow! Headshot
/obj/item/weapon/gun/rifle/sniper/antimaterial
name = "\improper SR-26 scoped rifle"
desc = "The SR-26 is an IFF capable sniper rifle which is mostly used by long range marksmen. It excels in long-range combat situations and support sniping. It has a laser designator installed, and the scope itself has IFF integrated into it. Uses specialized 10x28 caseless rounds made to work with the guns odd IFF-scope system. \nIt has an integrated Target Marker and a Laser Targeting system.\n\"Peace Through Superior Firepower\"."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "t26"
item_state = "t26"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
max_shells = 15 //codex
caliber = CALIBER_10X28
fire_sound = 'sound/weapons/guns/fire/sniper.ogg'
@@ -42,12 +47,11 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/ammo_magazine/sniper/flak,
)
force = 12
- wield_delay = 12 //Ends up being 1.6 seconds due to scope
+ wield_delay = 1.4 SECONDS
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 20, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
var/targetmarker_on = FALSE
var/targetmarker_primed = FALSE
var/mob/living/carbon/laser_target = null
- var/image/LT = null
var/obj/item/binoculars/tactical/integrated_laze = null
attachable_allowed = list(
/obj/item/attachable/foldable/bipod,
@@ -55,10 +59,8 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/attachable/scope/antimaterial,
/obj/item/attachable/buildasentry,
/obj/item/attachable/sniperbarrel,
- /obj/item/attachable/scope/pmc,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
starting_attachment_types = list(/obj/item/attachable/scope/antimaterial, /obj/item/attachable/sniperbarrel)
fire_delay = 2.5 SECONDS
@@ -74,7 +76,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/sniper/antimaterial/Initialize(mapload)
. = ..()
- LT = image("icon" = 'icons/obj/items/projectiles.dmi',"icon_state" = "sniper_laser", "layer" =-LASER_LAYER)
integrated_laze = new(src)
/obj/item/weapon/gun/rifle/sniper/antimaterial/do_fire(obj/object_to_fire)
@@ -89,7 +90,24 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
if(!QDELETED(laser_target))
target = laser_target
return ..()
+/*
+ * This override exists due to the fact the mouseup signal calls start_fire()
+ * which tries to get a turf from the clickcatcher, which ends up with the COMSIG_QDELETING signal
+ * getting registered on that turf, which we do not care about if we are lazing.
+ * The issue with this is that the signal gets registered to the turf and then gets overriden
+ * if the gun user ever clicks that turf again (also leaves hanging signals because they dont unregister)
+ * Shouldn't mess with reset_fire
+*/
+/obj/item/weapon/gun/rifle/sniper/antimaterial/set_target(atom/object)
+ if(laser_target)
+ return ..(laser_target)
+ return ..()
+/obj/item/weapon/gun/rifle/sniper/antimaterial/do_fire(obj/object_to_fire)
+ if(laser_target)
+ var/obj/projectile/projectile_to_fire = object_to_fire
+ projectile_to_fire.projectile_behavior_flags |= PROJECTILE_PRECISE_TARGET
+ return ..()
/obj/item/weapon/gun/rifle/sniper/antimaterial/InterceptClickOn(mob/user, params, atom/object)
var/list/pa = params2list(params)
@@ -102,27 +120,18 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/atom/proc/apply_laser()
return FALSE
-/mob/living/carbon/human/apply_laser()
- overlays_standing[LASER_LAYER] = image("icon" = 'icons/obj/items/projectiles.dmi',"icon_state" = "sniper_laser", "layer" =-LASER_LAYER)
+/mob/living/carbon/apply_laser()
+ overlays_standing[LASER_LAYER] = image('icons/obj/items/projectiles.dmi', icon_state = "sniper_laser", layer =-LASER_LAYER)
apply_overlay(LASER_LAYER)
return TRUE
-/mob/living/carbon/xenomorph/apply_laser()
- overlays_standing[X_LASER_LAYER] = image("icon" = 'icons/obj/items/projectiles.dmi',"icon_state" = "sniper_laser", "layer" =-X_LASER_LAYER)
- apply_overlay(X_LASER_LAYER)
- return TRUE
-
/mob/living/carbon/proc/remove_laser()
return FALSE
-/mob/living/carbon/human/remove_laser()
+/mob/living/carbon/remove_laser()
remove_overlay(LASER_LAYER)
return TRUE
-/mob/living/carbon/xenomorph/remove_laser()
- remove_overlay(X_LASER_LAYER)
- return TRUE
-
/obj/item/weapon/gun/rifle/sniper/antimaterial/unique_action(mob/user)
if(!targetmarker_primed && !targetmarker_on)
return laser_on(user)
@@ -135,7 +144,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/sniper/antimaterial/dropped()
laser_off()
- . = ..()
+ return ..()
/obj/item/weapon/gun/rifle/sniper/antimaterial/process()
var/obj/item/attachable/scope = LAZYACCESS(attachments_by_slot, ATTACHMENT_SLOT_RAIL)
@@ -146,11 +155,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
if(!istype(user))
laser_off()
return
- if(!laser_target)
- laser_off(user)
- playsound(user,'sound/machines/click.ogg', 25, 1)
- return
- if(!line_of_sight(user, laser_target, 24))
+ if(laser_target && !line_of_sight(user, laser_target, 24))
laser_off()
to_chat(user, span_danger("You lose sight of your target!"))
playsound(user,'sound/machines/click.ogg', 25, 1)
@@ -161,49 +166,31 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
if(!scope.zoom && (targetmarker_on || targetmarker_primed) )
laser_off(user)
-/atom/proc/sniper_target(atom/A)
- return FALSE
-
-/obj/item/weapon/gun/rifle/sniper/antimaterial/sniper_target(atom/A)
- if(!laser_target)
- return FALSE
- if(A == laser_target)
- return laser_target
- else
- return TRUE
+/obj/item/weapon/gun/rifle/sniper/antimaterial/on_unzoom(mob/user)
+ . = ..()
+ if(!targetmarker_primed && !laser_target)
+ return
+ laser_off(user)
/obj/item/weapon/gun/rifle/sniper/antimaterial/proc/activate_laser_target(atom/target, mob/living/user)
laser_target = target
to_chat(user, span_danger("You focus your target marker on [target]!"))
targetmarker_primed = FALSE
targetmarker_on = TRUE
- RegisterSignal(src, COMSIG_PROJ_SCANTURF, PROC_REF(scan_turf_for_target))
START_PROCESSING(SSobj, src)
accuracy_mult += 0.50 //We get a big accuracy bonus vs the lasered target
/obj/item/weapon/gun/rifle/sniper/antimaterial/proc/deactivate_laser_target()
- UnregisterSignal(src, COMSIG_PROJ_SCANTURF)
laser_target.remove_laser()
laser_target = null
-
-/obj/item/weapon/gun/rifle/sniper/antimaterial/proc/scan_turf_for_target(datum/source, turf/target_turf)
- SIGNAL_HANDLER
- if(QDELETED(laser_target) || !isturf(laser_target.loc))
- return NONE
- if(get_turf(laser_target) == target_turf)
- return COMPONENT_PROJ_SCANTURF_TARGETFOUND
- return COMPONENT_PROJ_SCANTURF_TURFCLEAR
-
-
/obj/item/weapon/gun/rifle/sniper/antimaterial/proc/laser_on(mob/user)
var/obj/item/attachable/scope = LAZYACCESS(attachments_by_slot, ATTACHMENT_SLOT_RAIL)
if(!scope.zoom) //Can only use and prime the laser targeter when zoomed.
to_chat(user, span_warning("You must be zoomed in to use your target marker!"))
return TRUE
targetmarker_primed = TRUE //We prime the target laser
- RegisterSignal(user, COMSIG_ITEM_UNZOOM, PROC_REF(laser_off))
if(user?.client)
user.client.click_intercept = src
to_chat(user, span_notice("You activate your target marker and take careful aim."))
@@ -219,8 +206,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
STOP_PROCESSING(SSobj, src)
targetmarker_on = FALSE
targetmarker_primed = FALSE
- if(user)
- UnregisterSignal(user, COMSIG_ITEM_UNZOOM)
if(user?.client)
user.client.click_intercept = null
to_chat(user, span_notice("You deactivate your target marker."))
@@ -233,6 +218,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
desc = "A high end mag-rail heavy sniper rifle from Nanotrasen chambered in the heaviest ammo available, 10x99mm Caseless."
icon_state = "m42c"
item_state = "m42c"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
max_shells = 6 //codex
caliber = CALIBER_10X99
fire_sound = 'sound/weapons/guns/fire/sniper_heavy.ogg'
@@ -244,9 +233,9 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
allowed_ammo_types = list(/obj/item/ammo_magazine/sniper/elite)
force = 17
attachable_allowed = list()
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 15, "rail_y" = 19, "under_x" = 20, "under_y" = 15, "stock_x" = 20, "stock_y" = 15)
- flags_item_map_variant = NONE
+ item_map_variant_flags = NONE
attachable_allowed = list(
/obj/item/attachable/foldable/bipod,
/obj/item/attachable/lasersight,
@@ -268,10 +257,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/sniper/svd
name = "\improper SR-33 Dragunov sniper rifle"
desc = "A semiautomatic sniper rifle, famed for it's marksmanship, and is built from the ground up for it. Fires 7.62x54mmR rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_64.dmi',
)
inhand_x_dimension = 64
@@ -297,7 +286,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/attachable/scope/slavic,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 17,"rail_x" = 22, "rail_y" = 21, "under_x" = 32, "under_y" = 14, "stock_x" = 20, "stock_y" = 14)
starting_attachment_types = list(/obj/item/attachable/scope/slavic)
actions_types = list(/datum/action/item_action/aim_mode)
@@ -309,7 +298,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
accuracy_mult = 1
scatter = -5
recoil = -1
- wield_delay = 1.8 SECONDS
+ wield_delay = 2 SECONDS
movement_acc_penalty_mult = 6
@@ -319,9 +308,13 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/tx8
name = "\improper BR-8 scout rifle"
desc ="The BR-8 is a light specialized scout rifle, mostly used by light infantry and scouts. It's designed to be useable at all ranges by being very adaptable to different situations due to the ability to use different ammo types. Has IFF. Takes specialized overpressured 10x28mm rounds."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/marksman64.dmi'
icon_state = "tx8"
item_state = "tx8"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/marksman_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/marksman_right_1.dmi',
+ )
max_shells = 25 //codex
muzzleflash_iconstate = "muzzle_flash_medium"
caliber = CALIBER_10X28_CASELESS //codex
@@ -362,9 +355,9 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/grenade_launcher/underslung,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_IFF|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
- gun_skill_category = SKILL_FIREARMS
+ gun_skill_category = SKILL_RIFLES
attachable_offset = list("muzzle_x" = 44, "muzzle_y" = 18,"rail_x" = 18, "rail_y" = 24, "under_x" = 31, "under_y" = 15, "stock_x" = 24, "stock_y" = 13)
@@ -372,7 +365,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
burst_amount = 1
accuracy_mult = 1.2
scatter = -3
- recoil = 2
/obj/item/weapon/gun/rifle/tx8/scout
starting_attachment_types = list(
@@ -387,9 +379,13 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/minigun
name = "\improper MG-100 Vindicator Minigun"
desc = "A six barreled rotary machine gun, The ultimate in man-portable firepower, capable of laying down high velocity armor piercing rounds this thing will no doubt pack a punch.. If you don't kill all your friends with it, you can use the stablizing system of the Powerpack to fire aimed fire, but you'll move incredibly slowly."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "minigun"
item_state = "minigun"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
fire_animation = "minigun_fire"
max_shells = 500 //codex
caliber = CALIBER_762X51 //codex
@@ -402,10 +398,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
allowed_ammo_types = list(/obj/item/ammo_magazine/minigun_powerpack)
w_class = WEIGHT_CLASS_HUGE
force = 20
- wield_delay = 12
- gun_skill_category = SKILL_FIREARMS
+ wield_delay = 1.2 SECONDS
+ gun_skill_category = SKILL_HEAVY_WEAPONS
aim_slowdown = 0.8
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
attachable_allowed = list(/obj/item/attachable/flashlight, /obj/item/attachable/magnetic_harness)
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 19,"rail_x" = 10, "rail_y" = 21, "under_x" = 24, "under_y" = 14, "stock_x" = 24, "stock_y" = 12)
@@ -417,20 +413,19 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
windup_delay = 0.4 SECONDS
windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg'
scatter = 5
- recoil = 2
recoil_unwielded = 4
damage_falloff_mult = 0.5
movement_acc_penalty_mult = 4
- obj_flags = AUTOBALANCE_CHECK
+ item_flags = TWOHANDED|AUTOBALANCE_CHECK
/obj/item/weapon/gun/minigun/Initialize(mapload)
. = ..()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.miniguns_in_use += src
/obj/item/weapon/gun/minigun/Destroy()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.miniguns_in_use -= src
return ..()
@@ -438,7 +433,33 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
starting_attachment_types = list(/obj/item/attachable/magnetic_harness)
/obj/item/weapon/gun/minigun/valhalla
- obj_flags = NONE
+ item_flags = TWOHANDED
+
+//A minigun that requires only one hand. Meant for use with vehicles
+/obj/item/weapon/gun/minigun/one_handed
+ name = "\improper Modified MG-100 Vindicator Minigun"
+ desc = "A minigun that's been modified to be used one handed. Intended for use mounted on a vehicle."
+
+ max_shells = 1000 //codex
+ reload_sound = 'sound/weapons/guns/interact/working_the_bolt.ogg'
+ default_ammo_type = /obj/item/ammo_magazine/minigun_wheelchair
+ allowed_ammo_types = list(/obj/item/ammo_magazine/minigun_wheelchair)
+ item_flags = NONE
+ equip_slot_flags = NONE
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ reciever_flags = AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE|AMMO_RECIEVER_MAGAZINES
+ gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
+ actions_types = list()
+ attachable_allowed = list()
+
+ recoil_unwielded = 0
+
+ windup_delay = 0.7 SECONDS
+ movement_acc_penalty_mult = 0
+
+//So that it displays the minigun on the mob as if always wielded
+/obj/item/weapon/gun/minigun/one_handed/update_item_state()
+ item_state = "[base_gun_icon]_w"
// SG minigun
@@ -451,8 +472,8 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
max_shells = 1000 //codex
caliber = CALIBER_10x26_CASELESS //codex
allowed_ammo_types = list(/obj/item/ammo_magazine/minigun_powerpack/smartgun)
- wield_delay = 1.5 SECONDS
- flags_gun_features = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
+ wield_delay = 1.7 SECONDS
+ gun_features_flags = GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_IFF|GUN_SMOKE_PARTICLES
gun_skill_category = SKILL_SMARTGUN
attachable_allowed = list(/obj/item/attachable/flashlight, /obj/item/attachable/magnetic_harness, /obj/item/attachable/motiondetector)
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 19,"rail_x" = 19, "rail_y" = 29, "under_x" = 24, "under_y" = 14, "stock_x" = 24, "stock_y" = 12) //Only has rail attachments so only the rail variables are properly aligned
@@ -461,10 +482,9 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
fire_delay = 0.1 SECONDS
scatter = -5
- recoil = 0
recoil_unwielded = 4
- obj_flags = NONE
+ item_flags = TWOHANDED
/obj/item/weapon/gun/minigun/smart_minigun/motion_detector
starting_attachment_types = list(/obj/item/attachable/motiondetector)
@@ -477,21 +497,23 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/pepperball
name = "\improper PB-12 pepperball gun"
desc = "The PB-12 is ostensibly riot control device used by the TGMC in spiffy colors, working through a SAN ball that sends a short acting neutralizing chemical to knock out it's target, or weaken them. Guranteed to work on just about everything. Uses SAN Ball Holders as magazines."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "pepperball"
item_state = "pepperball"
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
max_shells = 100 //codex
caliber = CALIBER_PEPPERBALL
fire_sound = "gun_fb12" // idk why i called it "fb-12", ah too late now
default_ammo_type = /obj/item/ammo_magazine/rifle/pepperball
allowed_ammo_types = list(/obj/item/ammo_magazine/rifle/pepperball)
force = 30 // two shots weeds as it has no bayonet
- wield_delay = 0.5 SECONDS // Very fast to put up.
+ wield_delay = 0.7 SECONDS // Very fast to put up.
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 20, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
attachable_allowed = list(
- /obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/flashlight,
/obj/item/weapon/gun/flamer/hydro_cannon/pepperball,
/obj/item/attachable/magnetic_harness,
@@ -504,12 +526,11 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
aim_fire_delay = 0.1 SECONDS
aim_speed_modifier = 0.1
- flags_gun_features = GUN_AMMO_COUNTER
+ gun_features_flags = GUN_AMMO_COUNTER
fire_delay = 0.1 SECONDS
burst_amount = 1
accuracy_mult = 1
- recoil = 0
accuracy_mult_unwielded = 0.75
scatter = -1
scatter_unwielded = 2
@@ -536,7 +557,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
starting_attachment_types = list()
actions_types = list()
gun_firemode_list = list(GUN_FIREMODE_AUTOMATIC)
- flags_gun_features = GUN_IS_ATTACHMENT | GUN_WIELDED_FIRING_ONLY | GUN_ATTACHMENT_FIRE_ONLY | GUN_AMMO_COUNTER
+ gun_features_flags = GUN_IS_ATTACHMENT | GUN_WIELDED_FIRING_ONLY | GUN_ATTACHMENT_FIRE_ONLY | GUN_AMMO_COUNTER
fire_delay = 0.2 SECONDS
attach_delay = 3 SECONDS
detach_delay = 3 SECONDS
@@ -567,37 +588,40 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket
name = "\improper RL-5 rocket launcher"
desc = "The RL-5 is the primary anti-armor used around the galaxy. Used to take out light-tanks and enemy structures, the RL-5 rocket launcher is a dangerous weapon with a variety of combat uses. Uses a variety of 84mm rockets."
+ icon = 'icons/obj/items/guns/special.dmi'
icon_state = "m5"
item_state = "m5"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
max_shells = 1 //codex
caliber = CALIBER_84MM //codex
load_method = SINGLE_CASING //codex
default_ammo_type = /obj/item/ammo_magazine/rocket
allowed_ammo_types = list(/obj/item/ammo_magazine/rocket)
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
w_class = WEIGHT_CLASS_HUGE
force = 15
- wield_delay = 12
+ wield_delay = 1.2 SECONDS
wield_penalty = 1.6 SECONDS
aim_slowdown = 1.75
general_codex_key = "explosive weapons"
attachable_allowed = list(
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/scope/mini,
- /obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SMOKE_PARTICLES
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_AUTO_EJECT_LOCKED
- gun_skill_category = SKILL_FIREARMS
+ gun_skill_category = SKILL_HEAVY_WEAPONS
fire_sound = 'sound/weapons/guns/fire/launcher.ogg'
dry_fire_sound = 'sound/weapons/guns/fire/launcher_empty.ogg'
reload_sound = 'sound/weapons/guns/interact/launcher_reload.ogg'
unload_sound = 'sound/weapons/guns/interact/launcher_reload.ogg'
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
fire_delay = 1 SECONDS
- recoil = 3
+ recoil = 1
scatter = -100
placed_overlay_iconstate = "sadar"
windup_delay = 0.4 SECONDS
@@ -635,12 +659,12 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/sadar
name = "\improper RL-152 sadar rocket launcher"
desc = "The RL-152 is the primary anti-armor weapon of the TGMC. Used to take out light-tanks and enemy structures, the RL-152 rocket launcher is a dangerous weapon with a variety of combat uses. Uses a variety of 84mm rockets."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "sadar"
item_state = "sadar"
item_icons = list(
- slot_l_hand_str = 'icons/mob/items_lefthand_64.dmi',
- slot_r_hand_str = 'icons/mob/items_righthand_64.dmi',
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_64.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_64.dmi',
slot_s_store_str = 'icons/mob/items_suit_slot_64.dmi',
)
inhand_x_dimension = 64
@@ -657,10 +681,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/ammo_magazine/rocket/sadar/wp,
/obj/item/ammo_magazine/rocket/sadar/wp/unguided,
)
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
w_class = WEIGHT_CLASS_HUGE
force = 15
- wield_delay = 12
+ wield_delay = 1.2 SECONDS
wield_penalty = 1.6 SECONDS
aim_slowdown = 1.75
general_codex_key = "explosive weapons"
@@ -669,27 +693,26 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/attachable/buildasentry,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
- gun_skill_category = SKILL_FIREARMS
+ gun_skill_category = SKILL_HEAVY_WEAPONS
dry_fire_sound = 'sound/weapons/guns/fire/launcher_empty.ogg'
reload_sound = 'sound/weapons/guns/interact/launcher_reload.ogg'
unload_sound = 'sound/weapons/guns/interact/launcher_reload.ogg'
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 14, "rail_y" = 21, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
fire_delay = 1 SECONDS
- recoil = 3
scatter = -100
- obj_flags = AUTOBALANCE_CHECK
+ item_flags = TWOHANDED|AUTOBALANCE_CHECK
/obj/item/weapon/gun/launcher/rocket/sadar/Initialize(mapload, spawn_empty)
. = ..()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.sadar_in_use += src
/obj/item/weapon/gun/launcher/rocket/sadar/Destroy()
- if(obj_flags & AUTOBALANCE_CHECK)
+ if(item_flags & AUTOBALANCE_CHECK)
SSmonitor.stats.sadar_in_use -= src
return ..()
@@ -700,7 +723,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
gun_user?.record_war_crime()
/obj/item/weapon/gun/launcher/rocket/sadar/valhalla
- obj_flags = NONE
+ item_flags = TWOHANDED
//-------------------------------------------------------
//M5 RPG'S MEAN FUCKING COUSIN
@@ -718,7 +741,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
aim_slowdown = 2.75
attachable_allowed = list(
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
general_codex_key = "explosive weapons"
@@ -737,8 +759,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/m57a4/deathsquad
attachable_allowed = list(
- /obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
/obj/item/attachable/magnetic_harness,
)
starting_attachment_types = list(/obj/item/attachable/magnetic_harness)
@@ -760,7 +780,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/recoillessrifle
name = "\improper RL-160 recoilless rifle"
desc = "The RL-160 recoilless rifle is a long range explosive ordanance device used by the TGMC used to fire explosive shells at far distances. Uses a variety of 67mm shells designed for various purposes."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "t160"
item_state = "t160"
max_shells = 1 //codex
@@ -777,25 +797,21 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/ammo_magazine/rocket/recoilless/heat,
/obj/item/ammo_magazine/rocket/recoilless/heam,
)
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
w_class = WEIGHT_CLASS_HUGE
force = 15
wield_delay = 1 SECONDS
- recoil = 1
wield_penalty = 1.6 SECONDS
aim_slowdown = 1
general_codex_key = "explosive weapons"
attachable_allowed = list(
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/buildasentry,
- /obj/item/attachable/shoulder_mount,
)
- gun_skill_category = SKILL_FIREARMS
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 15, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
fire_delay = 1 SECONDS
- recoil = 3
scatter = -100
/obj/item/weapon/gun/launcher/rocket/recoillessrifle/low_impact
@@ -810,7 +826,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/oneuse
name = "\improper RL-72 disposable rocket launcher"
desc = "This is the premier disposable rocket launcher used throughout the galaxy, it cannot be reloaded or unloaded on the field. This one fires an 84mm explosive rocket. Spacebar to shorten or extend it to make it storeable or fireable, respectively."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "t72"
item_state = "t72"
max_shells = 1 //codex
@@ -820,8 +836,8 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
default_ammo_type = /obj/item/ammo_magazine/rocket/oneuse
allowed_ammo_types = list(/obj/item/ammo_magazine/rocket/oneuse)
reciever_flags = AMMO_RECIEVER_CLOSED|AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT_LOCKED
- flags_equip_slot = ITEM_SLOT_BELT
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_SMOKE_PARTICLES
+ equip_slot_flags = ITEM_SLOT_BELT
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_DEPLOYED_FIRE_ONLY|GUN_SMOKE_PARTICLES
attachable_allowed = list(/obj/item/attachable/magnetic_harness)
/// Indicates extension state of the launcher. True: Fireable and unable to fit in storage. False: Able to fit in storage but must be extended to fire.
var/extended = FALSE
@@ -831,7 +847,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
unload_sound = 'sound/weapons/guns/interact/launcher_reload.ogg'
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
fire_delay = 1 SECONDS
- recoil = 3
scatter = -100
/obj/item/weapon/gun/launcher/rocket/oneuse/Initialize(mapload, spawn_empty)
@@ -845,13 +860,14 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
extended = !extended
if(!extended)
w_class = WEIGHT_CLASS_NORMAL
- flags_gun_features |= GUN_DEPLOYED_FIRE_ONLY
+ gun_features_flags |= GUN_DEPLOYED_FIRE_ONLY
else
w_class = WEIGHT_CLASS_BULKY
- flags_gun_features &= ~GUN_DEPLOYED_FIRE_ONLY
+ gun_features_flags &= ~GUN_DEPLOYED_FIRE_ONLY
update_icon()
/obj/item/weapon/gun/launcher/rocket/oneuse/update_icon_state()
+ . = ..()
if(extended)
icon_state = "[base_gun_icon]_extended"
else
@@ -860,7 +876,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/oneuse/update_item_state()
var/current_state = item_state
- item_state = "[base_gun_icon][extended ? "_extended" : ""][flags_item & WIELDED ? "_w" : ""]"
+ item_state = "[base_gun_icon][extended ? "_extended" : ""][item_flags & WIELDED ? "_w" : ""]"
if(current_state != item_state && ishuman(gun_user))
var/mob/living/carbon/human/human_user = gun_user
@@ -873,10 +889,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/som
name = "\improper V-71 rocket launcher"
desc = "The V-71 is a man portable rocket propelled grenade launcher employed by the SOM. It's design has changed little over centuries and is light weight and cheap to manufacture, while capable of firing a wide variety of 84mm rockets to provide excellent tactical flexibility."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "rpg"
item_state = "rpg"
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
caliber = CALIBER_84MM //codex
load_method = MAGAZINE //codex
default_ammo_type = /obj/item/ammo_magazine/rocket/som
@@ -898,7 +914,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
windup_delay = 0.6 SECONDS
- recoil = 2
scatter = -1
movement_acc_penalty_mult = 5 //You shouldn't fire this on the move
@@ -919,10 +934,10 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/launcher/rocket/icc
name = "\improper MP-IRL rocket launcher"
desc = "The Man Portable-Infantry Rocket Launcher is a man portable warhead launcher employed by the ICC. Being capable of firing a wide variety of 83m rear-mounted rockets to provide excellent tactical flexibility in a compact package."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "iccrpg"
item_state = "iccrpg"
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_SHOWS_LOADED|GUN_SMOKE_PARTICLES
caliber = CALIBER_84MM //codex
load_method = MAGAZINE //codex
default_ammo_type = /obj/item/ammo_magazine/rocket/icc
@@ -942,7 +957,6 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 6, "rail_y" = 19, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
windup_delay = 0.6 SECONDS
- recoil = 2
scatter = -1
movement_acc_penalty_mult = 5 //You shouldn't fire this on the move
@@ -959,9 +973,13 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/railgun
name = "\improper RG-220 railgun"
desc = "The RG-220 is a specialized heavy duty railgun made to shred through hard armor to allow for follow up attacks. Uses specialized canisters to reload."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "railgun"
item_state = "railgun"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
max_shells = 3 //codex
caliber = CALIBER_RAILGUN
fire_sound = 'sound/weapons/guns/fire/railgun.ogg'
@@ -976,14 +994,14 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/ammo_magazine/railgun/hvap,
)
force = 40
- wield_delay = 1 SECONDS //You're not quick drawing this.
+ wield_delay = 1.2 SECONDS
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 31, "rail_y" = 23, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
attachable_allowed = list(
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/scope/marine,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_WIELDED_STABLE_FIRING_ONLY|GUN_AMMO_COUNTER
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
fire_delay = 3 SECONDS
@@ -1002,9 +1020,13 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/weapon/gun/rifle/icc_coilgun
name = "\improper ML-120 coilgun"
desc = "The ML-120 coilgun is the most commonly seen coilgun in ICCAF use, firing magnetic projecitles at a incredibly high velocity. It requires some windup but will penetrate walls, your foes, and your friendlies too. So watch out... Uses specialized canisters to reload."
- icon = 'icons/Marine/gun64.dmi'
+ icon = 'icons/obj/items/guns/special64.dmi'
icon_state = "ml120"
item_state = "ml120"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/inhands/guns/special_left_1.dmi',
+ slot_r_hand_str = 'icons/mob/inhands/guns/special_right_1.dmi',
+ )
max_shells = 5 //codex
caliber = CALIBER_RAILGUN
fire_sound = 'sound/weapons/guns/fire/railgun.ogg'
@@ -1017,14 +1039,14 @@ Note that this means that snipers will have a slowdown of 3, due to the scope
/obj/item/ammo_magazine/rifle/icc_coilgun,
)
force = 40
- wield_delay = 1 SECONDS //You're not quick drawing this.
+ wield_delay = 1.2 SECONDS
attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 18,"rail_x" = 31, "rail_y" = 23, "under_x" = 19, "under_y" = 14, "stock_x" = 19, "stock_y" = 14)
attachable_allowed = list(
/obj/item/attachable/magnetic_harness,
/obj/item/attachable/reddot,
)
- flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
+ gun_features_flags = GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
reciever_flags = AMMO_RECIEVER_MAGAZINES|AMMO_RECIEVER_AUTO_EJECT|AMMO_RECIEVER_CYCLE_ONLY_BEFORE_FIRE
fire_delay = 1 SECONDS
diff --git a/code/modules/projectiles/magazines/energy.dm b/code/modules/projectiles/magazines/energy.dm
index a05455d7cd64c..46c4b0c7d93ea 100644
--- a/code/modules/projectiles/magazines/energy.dm
+++ b/code/modules/projectiles/magazines/energy.dm
@@ -16,7 +16,7 @@
charge_overlay = "m43"
var/reload_delay = 0
///Magazine flags.
- var/flags_magazine_features = MAGAZINE_REFUND_IN_CHAMBER
+ var/magazine_features_flags = MAGAZINE_REFUND_IN_CHAMBER
///if the magazine has a special overlay associated with it, i.e. extended mags etc
var/bonus_overlay = null
@@ -68,38 +68,39 @@
/obj/item/cell/lasgun/fob_sentry/cell
maxcharge = INFINITY
+/obj/item/cell/lasgun/plasma
+ name = "\improper WML plasma energy cell"
+ desc = "A plasma containment cell used by the TerraGov Marine Corps for plasma guns. It doesn't seem to have an expiry date on it."
+ icon_state = "plasma"
+ maxcharge = 900
+ icon_state_mini = "mag_plasma"
+ charge_overlay = "plasma"
+
//volkite
/obj/item/cell/lasgun/volkite
- name = "\improper volkite energy cell"
+ name = "volkite energy cell"
desc = "A specialized high density battery used to power volkite weaponry."
- icon = 'icons/obj/items/ammo.dmi'
icon_state = "volkite"
maxcharge = 1440
- w_class = WEIGHT_CLASS_NORMAL
icon_state_mini = "mag_cell"
charge_overlay = "volkite"
- reload_delay = 0
/obj/item/cell/lasgun/volkite/small
- name = "\improper compact volkite energy cell"
+ name = "compact volkite energy cell"
desc = "A specialized compact battery used to power the smallest volkite weaponry."
- icon = 'icons/obj/items/ammo.dmi'
icon_state = "volkite_small"
maxcharge = 540
w_class = WEIGHT_CLASS_SMALL
icon_state_mini = "mag_cell"
/obj/item/cell/lasgun/volkite/turret
- name = "\improper volkite nuclear energy cell"
+ name = "volkite nuclear energy cell"
desc = "A nuclear powered battery designed for certain heavy SOM machinery like sentries. Slowly charges over time."
- icon = 'icons/obj/items/ammo.dmi'
icon_state = "volkite_turret"
maxcharge = 1800
- w_class = WEIGHT_CLASS_NORMAL
icon_state_mini = "mag_cell"
charge_overlay = "volkite_big"
- reload_delay = 0
self_recharge = TRUE
charge_amount = 24
charge_delay = 2 SECONDS
@@ -114,9 +115,9 @@
)
icon_state = "volkite_powerpack"
charge_overlay = null
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BACK
- flags_magazine_features = MAGAZINE_REFUND_IN_CHAMBER|MAGAZINE_WORN
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
+ magazine_features_flags = MAGAZINE_REFUND_IN_CHAMBER|MAGAZINE_WORN
w_class = WEIGHT_CLASS_HUGE
slowdown = 0.2
maxcharge = 3000
@@ -126,6 +127,8 @@
light_range = 0.1
light_power = 0.1
light_color = LIGHT_COLOR_ORANGE
+ ///The kind of cells we like to accept around here to charge from us.
+ var/cell_type = /obj/item/cell
/obj/item/cell/lasgun/volkite/powerpack/Initialize(mapload)
. = ..()
@@ -162,6 +165,8 @@
/obj/item/cell/lasgun/volkite/powerpack/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/weapon/gun) && loc == user)
var/obj/item/weapon/gun/gun = I
if(!CHECK_BITFIELD(gun.reciever_flags, AMMO_RECIEVER_MAGAZINES))
@@ -169,7 +174,7 @@
gun.reload(src, user)
return
- if(!istype(I, /obj/item/cell))
+ if(!istype(I, cell_type))
return
if(I != user.r_hand && I != user.l_hand)
to_chat(user, span_warning("[I] must be in your hand to do that."))
@@ -189,10 +194,11 @@
icon = 'icons/obj/items/storage/storage.dmi'
icon_state = "lasgun_pouch"
charge_overlay = "lasgun_cell"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_POCKET
- flags_magazine_features = MAGAZINE_REFUND_IN_CHAMBER|MAGAZINE_WORN
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_POCKET
+ magazine_features_flags = MAGAZINE_REFUND_IN_CHAMBER|MAGAZINE_WORN
w_class = WEIGHT_CLASS_BULKY
slowdown = 0
maxcharge = 2400
+ cell_type = /obj/item/cell/lasgun/lasrifle
self_recharge = FALSE
diff --git a/code/modules/projectiles/magazines/flamer.dm b/code/modules/projectiles/magazines/flamer.dm
index 5da294ba2a55b..1aeb777acad41 100644
--- a/code/modules/projectiles/magazines/flamer.dm
+++ b/code/modules/projectiles/magazines/flamer.dm
@@ -11,7 +11,7 @@
reload_delay = 2 SECONDS
w_class = WEIGHT_CLASS_NORMAL //making sure you can't sneak this onto your belt.
caliber = CALIBER_FUEL_THICK //Ultra Thick Napthal Fuel, from the lore book.
- flags_magazine = NONE
+ magazine_flags = NONE
icon_state_mini = "tank_light"
default_ammo = /datum/ammo/flamethrower
@@ -54,9 +54,6 @@
to_chat(user, span_notice("You refill [src] with [lowertext(caliber)]."))
update_icon()
-/obj/item/ammo_magazine/flamer_tank/update_icon()
- return
-
/obj/item/ammo_magazine/flamer_tank/large // Extra thicc tank
name = "large flamerthrower tank"
desc = "A large fuel tank of ultra thick napthal, a sticky combustable liquid chemical, for use in the FL-84 flamethrower."
@@ -83,6 +80,10 @@
icon_state_mini = "tank_blue"
dispenser_type = /obj/structure/reagent_dispensers/fueltank/xfuel
+/obj/item/ammo_magazine/flamer_tank/large/X/som
+ desc = "A large fuel tank of ultra thick napthal Fuel type X, a sticky combustable liquid chemical, for use in the V-62 flamethrower."
+ icon_state = "flametank_som_x"
+
/obj/item/ammo_magazine/flamer_tank/large/X/deathsquad
name = "Gargantuan flamethrower X-tank"
desc = "Using Bluespace technology, Nanotrasen has managed to fit in way more x-fuel than you would ever hope to need in a single lifetime into this specialized tank."
@@ -94,13 +95,13 @@
name = "back fuel tank"
desc = "A specialized fuel tank for use with the FL-84 flamethrower and FL-240 incinerator unit."
icon_state = "flamethrower_tank"
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
max_rounds = 500
current_rounds = 500
reload_delay = 1 SECONDS
caliber = CALIBER_FUEL_THICK
- flags_magazine = MAGAZINE_WORN
+ magazine_flags = MAGAZINE_WORN
icon_state_mini = "tank"
default_ammo = /datum/ammo/flamethrower
@@ -121,7 +122,7 @@
reload_delay = 0 SECONDS
w_class = WEIGHT_CLASS_NORMAL
caliber = CALIBER_WATER //Deep lore
- flags_magazine = NONE
+ magazine_flags = NONE
icon_state_mini = "tank_water"
default_ammo = /datum/ammo/water
diff --git a/code/modules/projectiles/magazines/misc.dm b/code/modules/projectiles/magazines/misc.dm
index f0f6a015591ae..e7478bfd1b86d 100644
--- a/code/modules/projectiles/magazines/misc.dm
+++ b/code/modules/projectiles/magazines/misc.dm
@@ -95,9 +95,18 @@
max_rounds = 500
w_class = WEIGHT_CLASS_NORMAL
+/obj/item/ammo_magazine/packet/smart_targetrifle
+ name = "box of 10x27mm HV"
+ desc = "A box containing 200 rounds of 10x27mm smart rounds."
+ icon_state = "box_smarttargetrifle"
+ default_ammo = /datum/ammo/bullet/smarttargetrifle
+ caliber = CALIBER_10x27_CASELESS
+ current_rounds = 200
+ max_rounds = 200
+
/obj/item/ammo_magazine/packet/scout_rifle
name = "Box of A19 high velocity bullets"
- desc = "A box containing 150 rounds of A19 overpressuered high velocity."
+ desc = "A box containing 150 rounds of A19 overpressured high velocity."
icon_state = "box_tx8"
default_ammo = /datum/ammo/bullet/rifle/tx8
caliber = CALIBER_10X28_CASELESS
@@ -158,7 +167,7 @@
max_rounds = 42
/obj/item/ammo_magazine/packet/acp
- name = "packet of .45 ACP"
+ name = "packet of pistol .45 ACP"
icon_state = "box_45acp"
default_ammo = /datum/ammo/bullet/pistol/heavy
w_class = WEIGHT_CLASS_SMALL
diff --git a/code/modules/projectiles/magazines/mounted.dm b/code/modules/projectiles/magazines/mounted.dm
index f860a37a4dbd0..647176fbeacdc 100644
--- a/code/modules/projectiles/magazines/mounted.dm
+++ b/code/modules/projectiles/magazines/mounted.dm
@@ -1,11 +1,11 @@
///Default ammo for the HSG-102.
-/obj/item/ammo_magazine/tl102
+/obj/item/ammo_magazine/hsg_102
name = "HSG-102 drum magazine (10x30mm Caseless)"
desc = "A box of 300, 10x30mm caseless tungsten rounds for the HSG-102 mounted heavy smartgun."
w_class = WEIGHT_CLASS_NORMAL
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "mag"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_10X30
max_rounds = 300
default_ammo = /datum/ammo/bullet/machinegun
@@ -13,18 +13,18 @@
icon_state_mini = "mag_hmg"
///This is the one that comes in the mapbound and dropship mounted version of the HSG-102, it has a stupid amount of ammo. Even more than the ammo counter can display.
-/obj/item/ammo_magazine/tl102/hsg_nest
+/obj/item/ammo_magazine/hsg_102/hsg_nest
max_rounds = 500
/obj/item/ammo_magazine/heavymachinegun
name = "HMG-08 drum magazine (10x30mm Caseless)"
desc = "A box of 500, 10x28mm caseless tungsten rounds for the HMG-08 mounted heavy machinegun. Is probably not going to fit in your backpack. Put it on your belt or back."
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "mg08_mag"
icon_state_mini = "mag_drum_big_green"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_10X28
max_rounds = 500
default_ammo = /datum/ammo/bullet/machinegun
@@ -34,7 +34,7 @@
name = "HMG-08 box magazine (10x30mm Caseless)"
desc = "A box of 250 10x28mm caseless tungsten rounds for the HMG-08 mounted heavy machinegun."
w_class = WEIGHT_CLASS_NORMAL
- flags_equip_slot = ITEM_SLOT_BELT
+ equip_slot_flags = ITEM_SLOT_BELT
icon_state = "mg08_mag_small"
icon_state_mini = "mag_hmg"
max_rounds = 250
@@ -47,7 +47,7 @@
icon = 'icons/Marine/marine-mmg.dmi'
icon_state = "mag"
icon_state_mini = "mag_drum_big_armygreen"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_10x27_CASELESS
max_rounds = 150
default_ammo = /datum/ammo/bullet/rifle/heavy
@@ -59,7 +59,7 @@
w_class = WEIGHT_CLASS_NORMAL
icon = 'icons/Marine/marine-hmg.dmi'
icon_state = "ags_mag"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_40MM
max_rounds = 30
default_ammo = /datum/ammo/grenade_container/ags_grenade
@@ -103,7 +103,7 @@
icon = 'icons/Marine/marine-atgun.dmi'
icon_state = "tat36_shell"
item_state = "tat36"
- flags_magazine = MAGAZINE_REFUND_IN_CHAMBER
+ magazine_flags = MAGAZINE_REFUND_IN_CHAMBER
caliber = CALIBER_37MM
max_rounds = 1
default_ammo = /datum/ammo/rocket/atgun_shell
@@ -143,7 +143,7 @@
w_class = WEIGHT_CLASS_BULKY
icon = 'icons/obj/items/ammo.dmi'
icon_state = "minigun"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_762X51
max_rounds = 1000
default_ammo = /datum/ammo/bullet/minigun
@@ -156,7 +156,7 @@
icon = 'icons/Marine/marine-ac.dmi'
icon_state = "ac_mag"
item_state = "ac"
- flags_magazine = NONE
+ magazine_flags = NONE
caliber = CALIBER_20
max_rounds = 100
default_ammo = /datum/ammo/bullet/auto_cannon
@@ -185,7 +185,7 @@
icon_state = "isg_ammo"
item_state = "isg_ammo"
w_class = WEIGHT_CLASS_BULKY
- flags_magazine = MAGAZINE_REFUND_IN_CHAMBER
+ magazine_flags = MAGAZINE_REFUND_IN_CHAMBER
caliber = CALIBER_15CM
max_rounds = 1
reload_delay = 8 SECONDS
@@ -212,3 +212,17 @@
desc = "A 15cm APFDS shell for the FK-88 mounted flak gun containing a large metal dart fired at hypersonic speeds, will pierce through basically anything and onto the other side with ease. Requires a minimum range before it stabilizes to properly hit anything, will rip a clean hole through basically anything."
icon_state = "isg_ammo_sabot"
default_ammo = /datum/ammo/bullet/heavy_isg_apfds
+
+///Default ammo for the ML-91 and its export variants.
+/obj/item/ammo_magazine/icc_hmg
+ name = "KRD-61ES magazine (10x30mm Caseless)"
+ desc = "A box of 300, 10x30mm caseless tungsten rounds for the KRD-61ESmounted heavy smartgun."
+ w_class = WEIGHT_CLASS_NORMAL
+ icon = 'icons/Marine/marine-mmg.dmi'
+ icon_state = "kord_mag"
+ magazine_flags = NONE
+ caliber = CALIBER_10X30
+ max_rounds = 300
+ default_ammo = /datum/ammo/bullet/machinegun
+ reload_delay = 5 SECONDS
+ icon_state_mini = "mag_hmg"
diff --git a/code/modules/projectiles/magazines/pistols.dm b/code/modules/projectiles/magazines/pistols.dm
index 3b95ebafd4ad5..3010c2c9024d8 100644
--- a/code/modules/projectiles/magazines/pistols.dm
+++ b/code/modules/projectiles/magazines/pistols.dm
@@ -22,7 +22,7 @@
max_rounds = 10
w_class = WEIGHT_CLASS_SMALL
default_ammo = /datum/ammo/energy/plasma_pistol
- flags_magazine = NONE
+ magazine_flags = NONE
icon_state_mini = "mag_tx7"
//-------------------------------------------------------
diff --git a/code/modules/projectiles/magazines/revolvers.dm b/code/modules/projectiles/magazines/revolvers.dm
index 4abcdb37b64ac..fd6793c381a1f 100644
--- a/code/modules/projectiles/magazines/revolvers.dm
+++ b/code/modules/projectiles/magazines/revolvers.dm
@@ -5,7 +5,7 @@
name = "\improper R-44 magnum speed loader (.44)"
desc = "A revolver speed loader."
default_ammo = /datum/ammo/bullet/revolver
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
caliber = CALIBER_44
icon_state = "m44"
icon_state_mini = "mag_revolver_bronze"
@@ -30,7 +30,7 @@
name = "\improper R-44 magnum speed loader (.44)"
desc = "A revolver speed loader."
default_ammo = /datum/ammo/bullet/revolver/tp44
- flags_equip_slot = NONE
+ equip_slot_flags = NONE
caliber = CALIBER_44
icon_state = "tp44"
icon_state_mini = "mag_revolver"
diff --git a/code/modules/projectiles/magazines/rifles.dm b/code/modules/projectiles/magazines/rifles.dm
index b5dbbfdf2f7e8..9719c5d49c05a 100644
--- a/code/modules/projectiles/magazines/rifles.dm
+++ b/code/modules/projectiles/magazines/rifles.dm
@@ -51,6 +51,13 @@
default_ammo = /datum/ammo/bullet/rifle
max_rounds = 36
+/obj/item/ammo_magazine/rifle/standard_carbine/ap
+ name = "\improper AR-18 AP magazine (10x24mm)"
+ desc = "A 10mm assault carbine magazine, loaded with light armor piercing rounds."
+ icon_state = "t18_ap"
+ default_ammo = /datum/ammo/bullet/rifle/hv
+ bonus_overlay = "t18_ap"
+
//-------------------------------------------------------
//T12 Assault Rifle
@@ -64,6 +71,13 @@
default_ammo = /datum/ammo/bullet/rifle
max_rounds = 50
+/obj/item/ammo_magazine/rifle/standard_assaultrifle/ap
+ name = "\improper AR-12 AP magazine (10x24mm)"
+ desc = "A 10mm assault rifle magazine, loaded with light armor piercing rounds."
+ icon_state = "t12_ap"
+ default_ammo = /datum/ammo/bullet/rifle/hv
+ bonus_overlay = "t12_ap"
+
//-------------------------------------------------------
//T37 DMR
@@ -370,7 +384,7 @@
caliber = CALIBER_ALIEN
icon_state = "alien_rifle"
icon_state_mini = "mag_rifle_purple"
- default_ammo = /datum/ammo/energy/plasma
+ default_ammo = /datum/ammo/energy/sectoid_plasma
max_rounds = 20
//-------------------------------------------------------
@@ -424,7 +438,7 @@
icon_state = "t21"
icon_state_mini = "mag_rifle"
default_ammo = /datum/ammo/bullet/rifle/heavy
- max_rounds = 30
+ max_rounds = 40
//ALF-51B
@@ -505,6 +519,14 @@
icon_state_mini = "mag_sniper_purple"
greyscale_colors = COLOR_AMMO_TANGLEFOOT
+/obj/item/ammo_magazine/rifle/tx54/smoke/acid
+ name = "\improper 20mm acid smoke grenade magazine"
+ desc = "A 20mm magazine loaded with acid grenades. For use with the GL-54 or AR-55."
+ default_ammo = /datum/ammo/tx54/smoke/acid
+ icon_state = "tx54_airburst"
+ icon_state_mini = "mag_sniper_purple"
+ greyscale_colors = COLOR_AMMO_ACID
+
/obj/item/ammo_magazine/rifle/tx54/razor
name = "\improper 20mm razorburn grenade magazine"
desc = "A 20mm magazine loaded with razorburn grenades. For use with the GL-54 or AR-55."
@@ -637,3 +659,33 @@
/obj/item/ammo_magazine/rifle/icc_assaultcarbine/export
name = "\improper EM-88 assault carbine magazine (5.56x45mm)"
desc = "A magazine filled with 5.56x45mm rifle rounds for the EM-88 series of firearms."
+
+//-------------------------------------------------------
+//ML-41 Assault Machiengun
+/obj/item/ammo_magazine/icc_mg
+ name = "\improper ML-41 GPMG box magazine (10x26mm)"
+ desc = "A belt box for the ML-41 assault machinegun."
+ icon_state = "minimi"
+ icon_state_mini = "mag_gpmg"
+ caliber = CALIBER_10x26_CASELESS
+ default_ammo = /datum/ammo/bullet/rifle/machinegun
+ w_class = WEIGHT_CLASS_NORMAL
+ max_rounds = 150
+ reload_delay = 2 SECONDS
+
+// This is a 'belt'.
+/obj/item/ammo_magazine/icc_mg/belt
+ name = "\improper ML-41 GPMG buttpack magazine (10x26mm)"
+ desc = "A buttpack for the ML-41 which carries the ammo inside."
+ icon_state = "minimi_belt"
+ equip_slot_flags = ITEM_SLOT_BELT
+ magazine_flags = MAGAZINE_WORN
+ w_class = WEIGHT_CLASS_HUGE
+ max_rounds = 750
+
+/obj/item/ammo_magazine/icc_mg/packet
+ name = "box of 10x26mm"
+ desc = "A box containing 500 rounds of 10x26mm caseless."
+ icon_state = "box_minimi"
+ current_rounds = 500
+ max_rounds = 500
diff --git a/code/modules/projectiles/magazines/sentries.dm b/code/modules/projectiles/magazines/sentries.dm
index 904351da6b5e6..d21183d818e34 100644
--- a/code/modules/projectiles/magazines/sentries.dm
+++ b/code/modules/projectiles/magazines/sentries.dm
@@ -3,7 +3,7 @@
desc = "A drum of 50 10x28mm caseless rounds for the ST-571 sentry gun. Just feed it into the sentry gun's ammo port when its ammo is depleted."
w_class = WEIGHT_CLASS_NORMAL
icon_state = "ua571c"
- flags_magazine = NONE //can't be refilled or emptied by hand
+ magazine_flags = NONE //can't be refilled or emptied by hand
caliber = CALIBER_10X28
max_rounds = 500
default_ammo = /datum/ammo/bullet/turret
@@ -13,7 +13,7 @@
desc = "A box of 100 10x20mm caseless rounds for the ST-580 point defense sentry. Just feed it into the sentry gun's ammo port when its ammo is depleted."
w_class = WEIGHT_CLASS_NORMAL
icon_state = "ua580"
- flags_magazine = NONE //can't be refilled or emptied by hand
+ magazine_flags = NONE //can't be refilled or emptied by hand
caliber = CALIBER_10X20
max_rounds = 300
default_ammo = /datum/ammo/bullet/turret/mini
@@ -22,10 +22,40 @@
name = "M30 box magazine (10x28mm Caseless)"
desc = "A box of 50 10x28mm caseless rounds for the ST-571 Sentry Gun. Just feed it into the sentry gun's ammo port when its ammo is depleted."
w_class = WEIGHT_CLASS_NORMAL
- flags_magazine = NONE //can't be refilled or emptied by hand
+ magazine_flags = NONE //can't be refilled or emptied by hand
caliber = CALIBER_10X28
max_rounds = 500
default_ammo = /datum/ammo/bullet/turret/dumb
/obj/item/ammo_magazine/sentry/fob_sentry
max_rounds = INFINITY
+
+// Sniper Sentry
+
+/obj/item/ammo_magazine/sentry/sniper
+ name = "\improper AM-5 box magazine (10x28mm Caseless)"
+ desc = "A drum of 50 10x28mm caseless rounds for the SST-574 sentry gun. Just feed it into the sentry gun's ammo port when its ammo is depleted."
+ icon_state = "snipersentry"
+ max_rounds = 75
+ default_ammo = /datum/ammo/bullet/turret/sniper
+
+// Shotgun Sentry
+
+/obj/item/ammo_magazine/sentry/shotgun
+ name = "\improper SM-10 box magazine (12G Caseless)"
+ desc = "A drum of 200 specialized telescopic 12G rounds for the SST-573 sentry gun. Just feed it into the sentry gun's ammo port when its ammo is depleted."
+ caliber = CALIBER_12G
+ icon_state = "shotgunsentry"
+ max_rounds = 100
+ default_ammo = /datum/ammo/bullet/turret/buckshot
+
+// Flamer Sentry
+
+/obj/item/ammo_magazine/sentry/flamer
+ name = "\improper SM-10 box magazine (12G Caseless)"
+ desc = "A drum of 200 specialized telescopic 12G rounds for the SST-573 sentry gun. Just feed it into the sentry gun's ammo port when its ammo is depleted."
+ caliber = CALIBER_12G
+ icon_state = "flamersentry"
+ max_rounds = 100
+ default_ammo = /datum/ammo/flamer
+
diff --git a/code/modules/projectiles/magazines/smgs.dm b/code/modules/projectiles/magazines/smgs.dm
index 03b8f0e2453c0..54a0ddad339fd 100644
--- a/code/modules/projectiles/magazines/smgs.dm
+++ b/code/modules/projectiles/magazines/smgs.dm
@@ -54,6 +54,27 @@
w_class = WEIGHT_CLASS_SMALL
icon_state_mini = "mag_t90"
+//-------------------------------------------------------
+//SMG-45 SMG ammo
+
+/obj/item/ammo_magazine/smg/standard_heavysmg
+ name = "\improper SMG-45 magazine (.45 ACP)"
+ desc = "A .45 ACP caseless submachinegun magazine."
+ default_ammo = /datum/ammo/bullet/smg/heavy
+ caliber = CALIBER_45ACP
+ icon_state = "t45"
+ max_rounds = 40
+ w_class = WEIGHT_CLASS_SMALL
+ icon_state_mini = "mag_heavy_smg"
+ bonus_overlay = "t45_mag"
+
+/obj/item/ammo_magazine/smg/standard_heavysmg/squashhead
+ name = "\improper SMG-45 squash-head magazine (.45 ACP)"
+ desc = "A .45 ACP caseless submachinegun magazine that does a minituare explosion upon contact, will shred the armor off of basically anything."
+ default_ammo = /datum/ammo/bullet/smg/squash
+ icon_state = "t45_sh"
+ bonus_overlay = "t45_mag_sh"
+
//-------------------------------------------------------
//SMG-27, based on the SMG-27, based on the M7.
diff --git a/code/modules/projectiles/magazines/specialist.dm b/code/modules/projectiles/magazines/specialist.dm
index d27699b2903f4..ccbd0e95fcfff 100644
--- a/code/modules/projectiles/magazines/specialist.dm
+++ b/code/modules/projectiles/magazines/specialist.dm
@@ -56,7 +56,7 @@
/obj/item/ammo_magazine/rifle/tx8
name = "\improper high velocity magazine (10x28mm)"
- desc = "A magazine of overpressuered high velocity rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
+ desc = "A magazine of overpressured high velocity rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
icon_state = "tx8"
caliber = CALIBER_10X28_CASELESS
default_ammo = /datum/ammo/bullet/rifle/tx8
@@ -65,7 +65,7 @@
/obj/item/ammo_magazine/rifle/tx8/incendiary
name = "\improper high velocity incendiary magazine (10x28mm)"
- desc = "A magazine of overpressuered high velocity incendiary rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
+ desc = "A magazine of overpressured high velocity incendiary rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
caliber = CALIBER_10X28_CASELESS
icon_state = "tx8_incend"
default_ammo = /datum/ammo/bullet/rifle/tx8/incendiary
@@ -74,7 +74,7 @@
/obj/item/ammo_magazine/rifle/tx8/impact
name = "\improper high velocity impact magazine (10x28mm)"
- desc = "A magazine of overpressuered high velocity impact rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
+ desc = "A magazine of overpressured high velocity impact rounds for use in the BR-8 battle rifle. The BR-8 battle rifle is the only gun that can chamber these rounds."
icon_state = "tx8_impact"
default_ammo = /datum/ammo/bullet/rifle/tx8/impact
icon_state_mini = "mag_rifle_big_blue"
@@ -90,7 +90,7 @@
caliber = CALIBER_84MM
icon_state = "rocket"
w_class = WEIGHT_CLASS_NORMAL
- flags_magazine = MAGAZINE_REFUND_IN_CHAMBER
+ magazine_flags = MAGAZINE_REFUND_IN_CHAMBER
max_rounds = 1
default_ammo = /datum/ammo/rocket
reload_delay = 60
@@ -108,12 +108,22 @@
user.drop_held_item()
qdel(src)
-/obj/item/ammo_magazine/rocket/update_icon()
- overlays.Cut()
+/obj/item/ammo_magazine/rocket/update_name(updates)
+ . = ..()
if(current_rounds > 0)
return
name = "empty rocket frame"
+
+/obj/item/ammo_magazine/rocket/update_desc(updates)
+ . = ..()
+ if(current_rounds > 0)
+ return
desc = "A spent rocket rube. Activate it to deconstruct it and receive some materials."
+
+/obj/item/ammo_magazine/rocket/update_icon_state()
+ . = ..()
+ if(current_rounds > 0)
+ return
icon_state = istype(src, /obj/item/ammo_magazine/rocket/m57a4) ? "quad_rocket_e" : "rocket_e"
//-------------------------------------------------------
@@ -391,41 +401,55 @@
/obj/item/ammo_magazine/minigun_powerpack
name = "\improper MG-100 Vindicator powerpack"
- desc = "A heavy reinforced backpack with support equipment, power cells, and spare rounds for the MG-100 Minigun System.\nClick the icon in the top left to reload your M56."
+ desc = "A heavy reinforced backpack with support equipment, power cells, and spare rounds for the MG-100 Minigun System.\nClick the icon in the top left to reload your MG-100."
icon = 'icons/obj/items/storage/storage.dmi'
icon_state = "powerpack"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BACK
- flags_magazine = MAGAZINE_WORN
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BACK
+ magazine_flags = MAGAZINE_WORN
w_class = WEIGHT_CLASS_HUGE
default_ammo = /datum/ammo/bullet/minigun
current_rounds = 500
max_rounds = 500
- flags_item_map_variant = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
+ item_map_variant_flags = (ITEM_JUNGLE_VARIANT|ITEM_ICE_VARIANT|ITEM_PRISON_VARIANT)
/obj/item/ammo_magazine/minigun_powerpack/snow
icon_state = "s_powerpack"
- flags_item_map_variant = null
+ item_map_variant_flags = null
/obj/item/ammo_magazine/minigun_powerpack/fancy
icon_state = "powerpackw"
- flags_item_map_variant = null
+ item_map_variant_flags = null
/obj/item/ammo_magazine/minigun_powerpack/merc
icon_state = "powerpackp"
- flags_item_map_variant = null
+ item_map_variant_flags = null
/obj/item/ammo_magazine/minigun_powerpack/smartgun
name = "\improper SG-85 powerpack"
desc = "A reinforced backpack heavy with the IFF altered ammunition, onboard micro generator, and extensive cooling system which enables the SG-85 gatling gun to operate. \nUse the SG-85 on the backpack itself to connect them."
icon_state = "powerpacksg"
- flags_magazine = MAGAZINE_WORN|MAGAZINE_REFILLABLE
+ magazine_flags = MAGAZINE_WORN|MAGAZINE_REFILLABLE
default_ammo = /datum/ammo/bullet/smart_minigun
current_rounds = 1000
max_rounds = 1000
caliber = CALIBER_10x26_CASELESS
- flags_item_map_variant = null
-
+ item_map_variant_flags = null
+
+//"External magazine" for the wheelchair-mounted minigun
+/obj/item/ammo_magazine/minigun_wheelchair
+ name = "\improper Mounted MG-100 Vindicator ammo rack"
+ desc = "A case filled to the brim with ammunition. Appears custom made to be slotted into a feeding system."
+ icon = 'icons/obj/items/ammo.dmi'
+ icon_state = "minigun"
+ atom_flags = CONDUCT
+ magazine_flags = MAGAZINE_REFILLABLE
+ equip_slot_flags = ITEM_SLOT_BACK
+ w_class = WEIGHT_CLASS_HUGE
+ default_ammo = /datum/ammo/bullet/minigun
+ current_rounds = 1000
+ max_rounds = 1000
+ reload_delay = 0.75 SECONDS
// ICC coilgun
diff --git a/code/modules/projectiles/mounted.dm b/code/modules/projectiles/mounted.dm
index a025719eb7fb6..e2055942df231 100644
--- a/code/modules/projectiles/mounted.dm
+++ b/code/modules/projectiles/mounted.dm
@@ -4,10 +4,10 @@
anchored = TRUE
resistance_flags = XENO_DAMAGEABLE
density = TRUE
- layer = TANK_BARREL_LAYER
+ layer = ABOVE_MOB_PROP_LAYER
use_power = FALSE
hud_possible = list(MACHINE_HEALTH_HUD, MACHINE_AMMO_HUD)
- allow_pass_flags = PASSABLE
+ allow_pass_flags = PASSABLE|PASS_LOW_STRUCTURE
///Store user old pixel x
var/user_old_x = 0
///Store user old pixel y
@@ -18,7 +18,7 @@
var/has_anchored_sprite = FALSE
///generates the icon based on how much ammo it has.
-/obj/machinery/deployable/mounted/update_icon_state(mob/user)
+/obj/machinery/deployable/mounted/update_icon_state()
. = ..()
var/obj/item/weapon/gun/gun = get_internal_item()
if(gun && (!length(gun.chamber_items) || !gun.chamber_items[gun.current_chamber_position]))
@@ -71,6 +71,8 @@
/obj/machinery/deployable/mounted/attackby(obj/item/I, mob/user, params) //This handles reloading the gun, if its in acid cant touch it.
. = ..()
+ if(.)
+ return
if(!ishuman(user))
return
@@ -97,10 +99,10 @@
var/obj/item/weapon/gun/gun = get_internal_item()
if(length(gun?.chamber_items))
gun.unload(user)
- update_icon_state()
+ update_appearance()
gun?.reload(ammo_magazine, user)
- update_icon_state()
+ update_appearance()
REMOVE_TRAIT(src, TRAIT_GUN_RELOADING, GUN_TRAIT)
@@ -238,18 +240,18 @@
var/obj/item/weapon/gun/gun = get_internal_item()
//we can only fire in a 90 degree cone
if((dir & angle) && target.loc != loc && target.loc != operator.loc)
- if(CHECK_BITFIELD(gun.flags_item, DEPLOYED_ANCHORED_FIRING_ONLY) && !anchored)
+ if(CHECK_BITFIELD(gun.item_flags, DEPLOYED_ANCHORED_FIRING_ONLY) && !anchored)
to_chat(operator, "[src] cannot be fired without it being anchored.")
return FALSE
operator.setDir(dir)
gun?.set_target(target)
- update_icon_state()
+ update_appearance()
return TRUE
- if(CHECK_BITFIELD(gun?.flags_item, DEPLOYED_NO_ROTATE))
+ if(CHECK_BITFIELD(gun?.item_flags, DEPLOYED_NO_ROTATE))
to_chat(operator, "This one is anchored in place and cannot be rotated.")
return FALSE
- if(CHECK_BITFIELD(gun?.flags_item, DEPLOYED_NO_ROTATE_ANCHORED) && anchored)
+ if(CHECK_BITFIELD(gun?.item_flags, DEPLOYED_NO_ROTATE_ANCHORED) && anchored)
to_chat(operator, "[src] cannot be rotated while anchored.")
return FALSE
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 2147dd66ac433..873e7b92287b5 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -30,7 +30,7 @@
resistance_flags = RESIST_ALL
anchored = TRUE //You will not have me, space wind!
move_resist = INFINITY
- flags_atom = NOINTERACT //No real need for this, but whatever. Maybe this flag will do something useful in the future.
+ atom_flags = NOINTERACT //No real need for this, but whatever. Maybe this flag will do something useful in the future.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
invisibility = INVISIBILITY_MAXIMUM // We want this thing to be invisible when it drops on a turf because it will be on the user's turf. We then want to make it visible as it travels.
layer = FLY_LAYER
@@ -41,59 +41,76 @@
light_color = COLOR_VERY_SOFT_YELLOW
///greyscale support
- greyscale_config = null
- greyscale_colors = null
-
+ greyscale_config
+ greyscale_colors
///Any special effects applied to this projectile
- var/flags_projectile_behavior = NONE
-
- var/hitsound = null
- var/datum/ammo/ammo //The ammo data which holds most of the actual info.
-
- var/def_zone = BODY_ZONE_CHEST //So we're not getting empty strings.
-
+ var/projectile_behavior_flags = NONE
+ ///Hit impact sound
+ var/hitsound
+ ///The ammo data which holds most of the actual info
+ var/datum/ammo/ammo
+ ///The bodypart you're trying to hit
+ var/def_zone = BODY_ZONE_CHEST
+ ///the pixel X location of the tile that the player clicked. Default is the center
var/p_x = 16
- var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
- var/apx //Pixel location in absolute coordinates. This is (((x - 1) * 32) + 16 + pixel_x)
- var/apy //These values are floats, not integers. They need to be converted through CEILING or such when translated to relative pixel coordinates.
-
- var/atom/shot_from = null // the object which shot us
- var/turf/starting_turf = null // the projectile's starting turf
- var/atom/original_target = null // the original target clicked
- var/turf/original_target_turf = null // the original target's starting turf
- var/atom/firer = null // Who shot it
-
- var/list/atom/movable/uncross_scheduled = list() // List of border movable atoms to check for when exiting a turf.
-
+ ///the pixel y location of the tile that the player clicked. Default is the center
+ var/p_y = 16
+ /**
+ *Pixel location in absolute coordinates. This is (((x - 1) * 32) + 16 + pixel_x)
+ *These values are floats, not integers. They need to be converted through CEILING or such when translated to relative pixel coordinates.
+ */
+ var/apx
+ /**
+ *Pixel location in absolute coordinates. This is (((y - 1) * 32) + 16 + pixel_y)
+ *These values are floats, not integers. They need to be converted through CEILING or such when translated to relative pixel coordinates.
+ */
+ var/apy
+
+ ///The atom which shot us i.e. a gun or xeno
+ var/atom/shot_from
+ ///the projectile's starting turf
+ var/turf/starting_turf
+ ///the original target clicked
+ var/atom/original_target
+ ///the original target's starting turf
+ var/turf/original_target_turf
+ ///The mob responsible for firing this projectile, if any
+ var/mob/living/firer
+ ///List of border movable atoms to check for when exiting a turf.
+ var/list/atom/movable/uncross_scheduled = list()
+ ///Actual projectile damage
var/damage = 0
///ammo sundering value
var/sundering = 0
- var/accuracy = 90 //Base projectile accuracy. Can maybe be later taken from the mob if desired.
+ ///Base projectile accuracy
+ var/accuracy = 90
///how many damage points the projectile loses per tiles travelled
var/damage_falloff = 0
///Modifies projectile damage by a % when a marine gets passed, but not hit
var/damage_marine_falloff = 0
- var/scatter = 0 //Chance of scattering, also maximum amount scattered. High variance.
- ///damage airburst inflicts, as a multiplier of proj.damage
- var/airburst_multiplier = 0
-
/// The iff signal that will be compared to the target's one, to apply iff if needed
var/iff_signal = NONE
-
+ ///How far the projectile has currently travelled
var/distance_travelled = 0
-
- var/projectile_speed = 1 //Tiles travelled per full tick.
- var/armor_type = null
+ ///Tiles travelled per full tick
+ var/projectile_speed = 1
+ ///armour type this projectile is checked against
+ var/armor_type = BULLET
//Fired processing vars
+ ///Last movement time
var/last_projectile_move = 0
+ ///How many movements it needs to make in the next tick
var/stored_moves = 0
- var/dir_angle //0 is north, 90 is east, 180 is south, 270 is west. BYOND angles and all.
- var/x_offset //Float, not integer.
+ //0 is north, 90 is east, 180 is south, 270 is west. BYOND angles and all
+ var/dir_angle
+ ///Float X_offset for calculating turf movements
+ var/x_offset
+ ///Float Y_offset for calculating turf movements
var/y_offset
-
+ ///Max range the projectile can travel
var/proj_max_range = 30
///A damage multiplier applied when a mob from the same faction as the projectile firer is hit
var/friendly_fire_multiplier = 0.5
@@ -127,7 +144,7 @@
if(!PROJECTILE_HIT_CHECK(AM, src, get_dir(loc, oldloc), FALSE, hit_atoms))
return
AM.do_projectile_hit(src)
- if((!(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE)) || (!(ismob(AM) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB))) )
+ if((!(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE)) || (!(ismob(AM) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB))) )
qdel(src)
return
hit_atoms += AM
@@ -136,7 +153,7 @@
. = ..()
if(!.)
return
- if(CHECK_BITFIELD(S.smoke_traits, SMOKE_NERF_BEAM) && ammo.flags_ammo_behavior & AMMO_ENERGY)
+ if(CHECK_BITFIELD(S.smoke_traits, SMOKE_NERF_BEAM) && ammo.ammo_behavior_flags & AMMO_ENERGY)
damage -= max(damage - ammo.damage * 0.5, 0)
/obj/projectile/proc/generate_bullet(ammo_datum, bonus_damage = 0, reagent_multiplier = 0)
@@ -153,15 +170,13 @@
damage = ammo.damage + bonus_damage //Mainly for emitters.
penetration = ammo.penetration
sundering = ammo.sundering
- scatter = ammo.scatter
- airburst_multiplier = ammo.airburst_multiplier
accuracy += ammo.accuracy
accuracy *= rand(95 - ammo.accuracy_var_low, 105 + ammo.accuracy_var_high) * 0.01 //Rand only works with integers.
damage_falloff = ammo.damage_falloff
armor_type = ammo.armor_type
//Target, firer, shot from. Ie the gun
-/obj/projectile/proc/fire_at(atom/target, atom/shooter, atom/source, range, speed, angle, recursivity, suppress_light = FALSE, atom/loc_override = shooter)
+/obj/projectile/proc/fire_at(atom/target, mob/living/shooter, atom/source, range, speed, angle, recursivity, suppress_light = FALSE, atom/loc_override = source, scan_loc = FALSE)
if(!isnull(speed))
projectile_speed = speed
@@ -194,11 +209,6 @@
if(target)
original_target = target
original_target_turf = get_turf(target)
- if(original_target_turf == loc) //Shooting from and towards the same tile. Why not?
- distance_travelled++
- scan_a_turf(loc)
- qdel(src)
- return
apx = ABS_COOR(x) //Set the absolute coordinates. Center of a tile is assumed to be (16,16)
apy = ABS_COOR(y)
@@ -285,23 +295,33 @@
apx += pixel_x //Update the absolute pixels with the offset.
apy += pixel_y
- if(ismob(firer) && !recursivity)
- var/mob/mob_firer = firer
- record_projectile_fire(mob_firer)
- GLOB.round_statistics.total_projectiles_fired[mob_firer.faction]++
- SSblackbox.record_feedback("tally", "round_statistics", 1, "total_projectiles_fired[mob_firer.faction]")
+ if(firer && !recursivity)
+ record_projectile_fire(firer)
+ GLOB.round_statistics.total_projectiles_fired[firer.faction]++
+ SSblackbox.record_feedback("tally", "round_statistics", 1, "total_projectiles_fired[firer.faction]")
if(ammo.bonus_projectiles_amount)
- GLOB.round_statistics.total_projectiles_fired[mob_firer.faction] += ammo.bonus_projectiles_amount
- SSblackbox.record_feedback("tally", "round_statistics", ammo.bonus_projectiles_amount, "total_projectiles_fired[mob_firer.faction]")
+ GLOB.round_statistics.total_projectiles_fired[firer.faction] += ammo.bonus_projectiles_amount
+ SSblackbox.record_feedback("tally", "round_statistics", ammo.bonus_projectiles_amount, "total_projectiles_fired[firer.faction]")
//If we have the the right kind of ammo, we can fire several projectiles at once.
if(ammo.bonus_projectiles_amount && !recursivity) //Recursivity check in case the bonus projectiles have bonus projectiles of their own. Let's not loop infinitely.
ammo.fire_bonus_projectiles(src, shooter, source, range, speed, dir_angle, target)
- //if(shooter.Adjacent(target) && PROJECTILE_HIT_CHECK(target, src, null, FALSE, null)) //todo: doesn't take into account piercing projectiles // RUTGMC DELETION
- if(shooter?.Adjacent(target) && PROJECTILE_HIT_CHECK(target, src, null, FALSE, null)) //RUTGMC ADDITION
+ if(source.Adjacent(target) && PROJECTILE_HIT_CHECK(target, src, null, FALSE, null))
target.do_projectile_hit(src)
+ if((!ismob(target) || !(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOB)) && !(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE))
+ qdel(src)
+ return
+ hit_atoms += target
+
+ if(original_target_turf == loc) //Shooting from and towards the same tile. Why not?
+ distance_travelled++
+ scan_a_turf(loc)
+ qdel(src)
+ return
+
+ if(scan_loc && scan_a_turf(loc))
qdel(src)
return
@@ -313,7 +333,7 @@
var/first_moves = projectile_speed
switch(projectile_batch_move(first_move))
if(PROJECTILE_HIT) //Hit on first movement.
- if(!(flags_projectile_behavior & PROJECTILE_FROZEN))
+ if(!(projectile_behavior_flags & PROJECTILE_FROZEN))
qdel(src)
return
if(PROJECTILE_FROZEN)
@@ -323,7 +343,7 @@
first_moves -= first_move
switch(first_moves && projectile_batch_move(first_moves))
if(PROJECTILE_HIT) //First movement batch happens on the same tick.
- if(!(flags_projectile_behavior & PROJECTILE_FROZEN))
+ if(!(projectile_behavior_flags & PROJECTILE_FROZEN))
qdel(src)
return
if(PROJECTILE_FROZEN)
@@ -349,7 +369,7 @@
switch(projectile_batch_move(required_moves))
if(PROJECTILE_HIT) //Hit on first movement.
- if(!(flags_projectile_behavior & PROJECTILE_FROZEN))
+ if(!(projectile_behavior_flags & PROJECTILE_FROZEN))
qdel(src)
return PROCESS_KILL
if(PROJECTILE_FROZEN)
@@ -358,7 +378,7 @@
if(QDELETED(src))
return PROCESS_KILL
- if(ammo.flags_ammo_behavior & AMMO_SPECIAL_PROCESS)
+ if(ammo.ammo_behavior_flags & AMMO_SPECIAL_PROCESS)
ammo.ammo_process(src, damage)
/obj/projectile/proc/required_moves_calc()
@@ -461,9 +481,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if((ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if((ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = i
@@ -493,7 +513,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
return
RegisterSignal(turf_crossed_by, COMSIG_TURF_RESUME_PROJECTILE_MOVE, PROC_REF(resume_move))
return PROJECTILE_FROZEN
- if(turf_crossed_by == original_target_turf && ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
+ if(turf_crossed_by == original_target_turf && ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
last_processed_turf = turf_crossed_by
ammo.do_at_max_range(turf_crossed_by, src)
if(border_escaped_through & (NORTH|SOUTH))
@@ -513,9 +533,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if( (ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if( (ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = i
@@ -529,8 +549,8 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
x_pixel_dist_travelled += pixel_moves_until_crossing_x_border * x_offset
y_pixel_dist_travelled += pixel_moves_until_crossing_x_border * y_offset
break
- if(ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
- ammo.on_leave_turf(turf_crossed_by, firer, src)
+ if(ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
+ ammo.on_leave_turf(turf_crossed_by, src)
if(length(uncross_scheduled)) //Time to exit the last turf entered, if the diagonal movement didn't handle it already.
for(var/j in uncross_scheduled)
var/atom/movable/thing_to_uncross = j
@@ -541,9 +561,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue //We act as if we were entering the tile through the opposite direction, to check for barricade blockage.
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if( (ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if( (ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = i
@@ -551,8 +571,8 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
uncross_scheduled.len = 0
if(end_of_movement)
break
- if(ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
- ammo.on_leave_turf(last_processed_turf, firer, src)
+ if(ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
+ ammo.on_leave_turf(last_processed_turf, src)
x_pixel_dist_travelled += 32 * x_offset
y_pixel_dist_travelled += 32 * y_offset
last_processed_turf = next_turf
@@ -565,7 +585,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
return
RegisterSignal(next_turf, COMSIG_TURF_RESUME_PROJECTILE_MOVE, PROC_REF(resume_move))
return PROJECTILE_FROZEN
- if(next_turf == original_target_turf && ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
+ if(next_turf == original_target_turf && ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
ammo.do_at_max_range(next_turf, src)
end_of_movement = i
break
@@ -605,15 +625,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
if(turf_to_scan.density) //Handle wall hit.
ammo.on_hit_turf(turf_to_scan, src)
turf_to_scan.bullet_act(src)
- return !(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_TURF)
-
- if(shot_from)
- switch(SEND_SIGNAL(shot_from, COMSIG_PROJ_SCANTURF, turf_to_scan))
- if(COMPONENT_PROJ_SCANTURF_TURFCLEAR)
- return FALSE
- if(COMPONENT_PROJ_SCANTURF_TARGETFOUND)
- original_target.do_projectile_hit(src)
- return TRUE
+ return !(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_TURF)
for(var/atom/movable/thing_to_hit in turf_to_scan)
@@ -623,9 +635,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
thing_to_hit.do_projectile_hit(src)
/* RUTGMC DELETION START
- if((ismob(thing_to_hit) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) || CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOVABLE))
+ if((ismob(thing_to_hit) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) || CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOVABLE))
RUTGMC DELETION END */
- if(ismob(thing_to_hit) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB) || CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOVABLE) && !iscontainmentshutter(thing_to_hit)) // RUTGMC ADDITION
+ if(ismob(thing_to_hit) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB) || CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOVABLE) && !iscontainmentshutter(thing_to_hit)) // RUTGMC ADDITION
hit_atoms += thing_to_hit
return FALSE
@@ -656,27 +668,28 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/atom/proc/do_projectile_hit(obj/projectile/proj)
return
-
/obj/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing)
+ if(proj.shot_from == src)
+ return FALSE
if(!density && !(obj_flags & PROJ_IGNORE_DENSITY)) //structure is passable
return FALSE
if(src == proj.original_target) //clicking on the structure itself hits the structure
return TRUE
- if((allow_pass_flags & PASS_GLASS) && (proj.ammo.flags_ammo_behavior & AMMO_ENERGY))
+ if((allow_pass_flags & PASS_GLASS) && (proj.ammo.ammo_behavior_flags & AMMO_ENERGY))
return FALSE
if(!(allow_pass_flags & PASS_PROJECTILE))
return TRUE
if(proj.distance_travelled <= proj.ammo.barricade_clear_distance)
return FALSE
var/hit_chance = coverage //base chance for the projectile to hit the object instead of bypassing it
- if(flags_atom & ON_BORDER)
+ if(atom_flags & ON_BORDER)
if(!(cardinal_move & REVERSE_DIR(dir))) //The bullet will only hit if the barricade and its movement are facing opposite directions.
if(!uncrossing)
proj.uncross_scheduled += src
return FALSE //No effect now, but we save the reference to check on exiting the tile.
if (uncrossing)
return FALSE //you don't hit the cade from behind.
- if(proj.ammo.flags_ammo_behavior & AMMO_SNIPER || proj.iff_signal || proj.ammo.flags_ammo_behavior & AMMO_ROCKET) //sniper, rockets and IFF rounds are better at getting past cover
+ if(proj.ammo.ammo_behavior_flags & AMMO_SNIPER || proj.iff_signal) //sniper and IFF rounds are better at getting past cover
hit_chance *= 0.8
///50% better protection when shooting from outside accurate range.
if(proj.distance_travelled > proj.ammo.accurate_range)
@@ -721,7 +734,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
return src == proj.original_target
/obj/vehicle/unmanned/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing)
- if(proj.firer == src)
+ if(proj.shot_from == src)
return FALSE
if(iff_signal & proj.iff_signal)
proj.damage -= proj.damage*proj.damage_marine_falloff
@@ -741,25 +754,23 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
return FALSE
if(lying_angle && src != proj.original_target)
return FALSE
- if((proj.ammo.flags_ammo_behavior & AMMO_XENO) && (isnestedhost(src) || stat == DEAD))
+ if((proj.ammo.ammo_behavior_flags & AMMO_XENO) && (isnestedhost(src) || stat == DEAD))
return FALSE
if(pass_flags & PASS_PROJECTILE) //he's beginning to believe
return FALSE
//We want a temporary variable so accuracy doesn't change every time the bullet misses.
var/hit_chance = proj.accuracy
- BULLET_DEBUG("Base accuracy is [hit_chance]; scatter:[proj.scatter]; distance:[proj.distance_travelled]")
+ BULLET_DEBUG("Base accuracy is [hit_chance]; distance:[proj.distance_travelled]")
hit_chance += (mob_size - 1) * 20 //You're easy to hit when you're swoll, hard to hit when you're a manlet
///Is the shooter a living mob. Defined before the check as used later as well
- var/mob/living/shooter_living
- if(isliving(proj.firer))
- shooter_living = proj.firer
- if(shooter_living.faction == faction)
+ if(proj.firer)
+ if(proj.firer.faction == faction)
hit_chance = round(hit_chance*0.85) //You (presumably) aren't trying to shoot your friends
var/obj/item/shot_source = proj.shot_from
- if(!line_of_sight(shooter_living, src, 9) && (!istype(shot_source) || !shot_source.zoom)) //if you can't draw LOS within 9 tiles (to accomodate wide screen), AND the source was either not zoomed or not an item(like a xeno)
+ if((!istype(shot_source) || !shot_source.zoom) && !line_of_sight(proj.starting_turf, src, 9)) //if you can't draw LOS within 9 tiles (to accomodate wide screen), AND the source was either not zoomed or not an item(like a xeno)
BULLET_DEBUG("Can't see target ([round(hit_chance*0.8)]).")
hit_chance = round(hit_chance*0.8) //Can't see the target (Opaque thing between shooter and target), or out of view range
@@ -790,7 +801,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
BULLET_DEBUG("Moving (*[evasion_bonus]).")
hit_chance = round(hit_chance * evasion_bonus)
- if(proj.ammo.flags_ammo_behavior & AMMO_UNWIELDY)
+ if(proj.ammo.ammo_behavior_flags & AMMO_UNWIELDY)
hit_chance *= 0.5
hit_chance = max(5, hit_chance) //It's never impossible to hit
@@ -800,9 +811,6 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
var/hit_roll = rand(0, 99) //Our randomly generated roll
if(hit_chance > hit_roll) //Hit
- //friendly fire reduces the damage of the projectile, so only applies the multiplier if a hit is confirmed
- if(shooter_living?.faction == faction)
- proj.damage *= proj.friendly_fire_multiplier
if(hit_roll > (hit_chance-25)) //if you hit by a small margin, you hit a random bodypart instead of what you were aiming for
proj.def_zone = pick(GLOB.base_miss_chance)
return TRUE
@@ -811,7 +819,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
animatation_displace_reset(src)
if(proj.ammo.sound_miss)
var/pitch = 0
- if(proj.ammo.flags_ammo_behavior & AMMO_SOUND_PITCH)
+ if(proj.ammo.ammo_behavior_flags & AMMO_SOUND_PITCH)
pitch = 55000
playsound_local(get_turf(src), proj.ammo.sound_miss, 75, 1, frequency = pitch)
@@ -824,11 +832,16 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/mob/living/carbon/do_projectile_hit(obj/projectile/proj)
. = ..()
- if(!(species?.species_flags & NO_BLOOD) && proj.ammo.flags_ammo_behavior & AMMO_BALLISTIC)
+ if(!(species?.species_flags & NO_BLOOD) && proj.ammo.ammo_behavior_flags & AMMO_BALLISTIC)
var/angle = !isnull(proj.dir_angle) ? proj.dir_angle : round(Get_Angle(proj.starting_turf, src), 1)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(loc, angle, get_blood_color())
+/mob/living/carbon/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing)
+ if(proj.projectile_behavior_flags & PROJECTILE_PRECISE_TARGET)
+ return proj.original_target == src ? TRUE : FALSE
+ return ..()
+
/mob/living/carbon/human/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing)
if(wear_id?.iff_signal & proj.iff_signal)
proj.damage -= proj.damage*proj.damage_marine_falloff
@@ -843,7 +856,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
return FALSE
if(HAS_TRAIT(src, TRAIT_BURROWED))
return FALSE
- if(proj.ammo.flags_ammo_behavior & AMMO_SKIPS_ALIENS)
+ if(proj.ammo.ammo_behavior_flags & AMMO_SKIPS_ALIENS)
return FALSE
return ..()
*/ //RUTGMC EDIT END
@@ -879,21 +892,29 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
if(!damage)
return
+ if(proj.projectile_behavior_flags & PROJECTILE_PRECISE_TARGET)
+ damage *= SNIPER_LASER_DAMAGE_MULTIPLIER
+ add_slowdown(SNIPER_LASER_SLOWDOWN_STACKS)
+
+ //friendly fire reduces the damage of the projectile, so only applies the multiplier if a hit is confirmed
+ if(proj.firer)
+ if(proj.firer?.faction == faction)
+ damage *= proj.friendly_fire_multiplier
+
+ if(iscarbon(proj.firer))
+ var/mob/living/carbon/shooter_carbon = proj.firer
+ if(shooter_carbon.IsStaggered())
+ damage *= STAGGER_DAMAGE_MULTIPLIER //Since we hate RNG, stagger reduces damage by a % instead of reducing accuracy; consider it a 'glancing' hit due to being disoriented.
+
damage = check_shields(COMBAT_PROJ_ATTACK, damage, proj.ammo.armor_type, FALSE, proj.penetration)
if(!damage)
proj.ammo.on_shield_block(src, proj)
return
- if(!damage)
- return
-
flash_weak_pain()
var/feedback_flags = NONE
- if(proj.shot_from && src == proj.shot_from.sniper_target(src))
- damage *= SNIPER_LASER_DAMAGE_MULTIPLIER
-
if(iscarbon(proj.firer))
var/mob/living/carbon/shooter_carbon = proj.firer
if(shooter_carbon.IsStaggered())
@@ -912,17 +933,17 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
feedback_flags |= BULLET_FEEDBACK_SOAK
bullet_soak_effect(proj)
- if(proj.ammo.flags_ammo_behavior & AMMO_INCENDIARY)
+ if(proj.ammo.ammo_behavior_flags & AMMO_INCENDIARY)
adjust_fire_stacks(proj.ammo.incendiary_strength)
if(IgniteMob())
feedback_flags |= (BULLET_FEEDBACK_FIRE)
- if((proj.ammo.flags_ammo_behavior & AMMO_SUNDERING) && proj.sundering >= 20) // RUTGMC EDIT
+ if(proj.sundering >= 20) // RUTGMC EDIT
adjust_sunder(proj.sundering) // RUTGMC EDIT
- if(stat != DEAD && ismob(proj.firer))
- record_projectile_damage(proj.firer, damage) //Tally up whoever the shooter was
+ if(stat != DEAD && proj.firer)
+ proj.firer.record_projectile_damage(damage, src) //Tally up whoever the shooter was
if(damage)
if(do_shrapnel_roll(proj, damage))
@@ -956,7 +977,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
if(effect_icon)
src.effect_icon = effect_icon
-/obj/projectile/hitscan/fire_at(atom/target, atom/shooter, atom/source, range, speed, angle, recursivity, suppress_light, atom/loc_override = shooter)
+/obj/projectile/hitscan/fire_at(atom/target, mob/living/shooter, atom/source, range, speed, angle, recursivity, suppress_light, atom/loc_override = source, scan_loc = FALSE)
if(!isnull(range))
proj_max_range = range
if(shooter)
@@ -986,16 +1007,26 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
if(ammo.bonus_projectiles_amount)
ammo.fire_bonus_projectiles(src, shooter, source, range, speed, dir_angle, target)
- if(shooter.Adjacent(target) && ismob(target))
- var/mob/mob_to_hit = target
- ammo.on_hit_mob(mob_to_hit, src)
- mob_to_hit.bullet_act(src)
+ if(source.Adjacent(target) && PROJECTILE_HIT_CHECK(target, src, null, FALSE, null))
+ target.do_projectile_hit(src)
+ if((!ismob(target) || !(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOB)) && !(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE))
+ qdel(src)
+ return
+ hit_atoms += target
+
+ if(original_target_turf == loc) //Shooting from and towards the same tile. Why not?
+ distance_travelled++
+ scan_a_turf(loc)
+ qdel(src)
+ return
+
+ if(scan_loc && scan_a_turf(loc))
qdel(src)
return
x_offset = round(sin(dir_angle), 0.01)
y_offset = round(cos(dir_angle), 0.01)
- if(projectile_batch_move(!recursivity) == PROJECTILE_FROZEN || (flags_projectile_behavior & PROJECTILE_FROZEN))
+ if(projectile_batch_move(!recursivity) == PROJECTILE_FROZEN || (projectile_behavior_flags & PROJECTILE_FROZEN))
var/atom/movable/hitscan_projectile_effect/laser_effect = new /atom/movable/hitscan_projectile_effect(PROJ_ABS_PIXEL_TO_TURF(apx, apy, z), dir_angle, apx % 32 - 16, apy % 32 - 16, 1.01, effect_icon, ammo.bullet_color)
RegisterSignal(loc, COMSIG_TURF_RESUME_PROJECTILE_MOVE, PROC_REF(resume_move))
laser_effect.RegisterSignal(loc, COMSIG_TURF_RESUME_PROJECTILE_MOVE, TYPE_PROC_REF(/atom/movable/hitscan_projectile_effect, remove_effect))
@@ -1080,9 +1111,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if( (ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if( (ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = TRUE
@@ -1092,7 +1123,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
break
if(scan_a_turf(turf_crossed_by, border_escaped_through))
break
- if(turf_crossed_by == original_target_turf && ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
+ if(turf_crossed_by == original_target_turf && ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
last_processed_turf = turf_crossed_by
ammo.do_at_max_range(turf_crossed_by, src)
end_of_movement = TRUE
@@ -1111,9 +1142,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if( (ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if( (ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = TRUE
@@ -1121,8 +1152,8 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
uncross_scheduled.Cut()
if(end_of_movement)
break
- if(ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
- ammo.on_leave_turf(turf_crossed_by, firer, src)
+ if(ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
+ ammo.on_leave_turf(turf_crossed_by, src)
if(length(uncross_scheduled)) //Time to exit the last turf entered, if the diagonal movement didn't handle it already.
for(var/atom/movable/thing_to_uncross AS in uncross_scheduled)
if(QDELETED(thing_to_uncross))
@@ -1131,9 +1162,9 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
continue //We act as if we were entering the tile through the opposite direction, to check for barricade blockage.
thing_to_uncross.do_projectile_hit(src)
/* RUTGMC DELETION START
- if( (ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) )
+ if( (ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE) || (ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) )
RUTGMC DELETION END */
- if(ammo.flags_ammo_behavior & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.flags_ammo_behavior, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
+ if(ammo.ammo_behavior_flags & AMMO_PASS_THROUGH_MOVABLE && !iscontainmentshutter(thing_to_uncross) || ismob(thing_to_uncross) && CHECK_BITFIELD(ammo.ammo_behavior_flags, AMMO_PASS_THROUGH_MOB)) // RUTGMC ADDITION
hit_atoms += thing_to_uncross
continue
end_of_movement = TRUE
@@ -1141,13 +1172,13 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
uncross_scheduled.len = 0
if(end_of_movement)
break
- if(ammo.flags_ammo_behavior & AMMO_LEAVE_TURF)
- ammo.on_leave_turf(last_processed_turf, firer, src)
+ if(ammo.ammo_behavior_flags & AMMO_LEAVE_TURF)
+ ammo.on_leave_turf(last_processed_turf, src)
last_processed_turf = next_turf
if(scan_a_turf(next_turf, movement_dir))
end_of_movement = TRUE
break
- if(next_turf == original_target_turf && ammo.flags_ammo_behavior & AMMO_EXPLOSIVE)
+ if(next_turf == original_target_turf && ammo.ammo_behavior_flags & AMMO_TARGET_TURF)
ammo.do_at_max_range(next_turf, src)
end_of_movement = TRUE
break
@@ -1211,7 +1242,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/mob/living/carbon/human/do_shrapnel_roll(obj/projectile/proj, damage)
- return (!(SSticker.mode?.flags_round_type & MODE_NO_PERMANENT_WOUNDS) && proj.ammo.shrapnel_chance && prob(proj.ammo.shrapnel_chance + damage * 0.1))
+ return (!(SSticker.mode?.round_type_flags & MODE_NO_PERMANENT_WOUNDS) && proj.ammo.shrapnel_chance && prob(proj.ammo.shrapnel_chance + damage * 0.1))
//Turf handling.
@@ -1249,7 +1280,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
if(damage < 1)
return FALSE
- if(proj.ammo.flags_ammo_behavior & AMMO_BALLISTIC)
+ if(proj.ammo.ammo_behavior_flags & AMMO_BALLISTIC)
current_bulletholes++
if(prob(30))
@@ -1283,7 +1314,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/mob/living/carbon/human/bullet_message(obj/projectile/proj, feedback_flags, damage)
. = ..()
var/list/victim_feedback = list()
- if(proj.ammo.flags_ammo_behavior & AMMO_IS_SILENCED)
+ if(proj.shot_from && HAS_TRAIT(proj.shot_from, TRAIT_GUN_SILENCED))
victim_feedback += "You've been shot in the [parse_zone(proj.def_zone)] by [proj]!"
else
victim_feedback += "You are hit by [proj] in the [parse_zone(proj.def_zone)]!"
@@ -1320,7 +1351,7 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/mob/living/carbon/xenomorph/bullet_message(obj/projectile/proj, feedback_flags, damage)
. = ..()
var/list/victim_feedback
- if(proj.ammo.flags_ammo_behavior & AMMO_IS_SILENCED)
+ if(proj.shot_from && HAS_TRAIT(proj.shot_from, TRAIT_GUN_SILENCED))
victim_feedback = list("We've been shot in the [parse_zone(proj.def_zone)] by [proj]!")
else
victim_feedback = list("We are hit by the [proj] in the [parse_zone(proj.def_zone)]!")
@@ -1351,6 +1382,50 @@ So if we are on the 32th absolute pixel coordinate we are on tile 1, but if we a
/mob/living/proc/get_sunder()
return 0
+
+/**
+ * Fires a list of projectile objects in a circle around an atom
+ * Arguments:
+ * * source: [mandatory] atom the bullets are emitting from
+ * * bullets: [mandatory] list of bullets (in order, clockwise) to fire
+ * * firer: atom that "shot" these bullets
+ * * fire_sound: sound to play while the bullets are firing
+ * * range: bullet range
+ * * speed: bullet speed
+ * * randomized: bool, if true we randomly pick where we're firing instead of evenly seperated
+ * * rotations: how many times to "spin" the rotation. if 0 or less, instead bursts all the bullets at once
+ */
+/proc/bullet_burst(atom/source, list/obj/projectile/bullets, mob/living/firer, fire_sound, range, speed, randomized = FALSE, rotations = -1)
+ var/angle_between_bullets = 0
+ var/current_angle = 0
+
+ //fire in an instant burst, no shrapnel
+ if(rotations < 1)
+ angle_between_bullets = 360 / length(bullets)
+ for(var/obj/projectile/proj in bullets)
+ if(randomized)
+ current_angle = rand(1, 360)
+ else
+ current_angle += angle_between_bullets
+
+ proj.fire_at(null, firer, source, range, speed, current_angle, scan_loc = TRUE)
+ if(fire_sound)
+ playsound(source, fire_sound, 60, TRUE)
+ return
+
+ angle_between_bullets = 360 / (length(bullets) / rotations)
+ var/play_sound
+ for(var/obj/projectile/proj in bullets)
+ if(randomized)
+ current_angle = rand(1, 360)
+ else
+ current_angle += angle_between_bullets
+
+ proj.fire_at(null, firer, source, range, speed, current_angle, scan_loc = TRUE)
+ if(play_sound % 3 && fire_sound)
+ playsound(source, fire_sound, 60, FALSE)
+ stoplag(1)
+
#undef BULLET_FEEDBACK_PEN
#undef BULLET_FEEDBACK_SOAK
#undef BULLET_FEEDBACK_FIRE
diff --git a/code/modules/projectiles/sentries.dm b/code/modules/projectiles/sentries.dm
index 254023554f049..e067e21adece7 100644
--- a/code/modules/projectiles/sentries.dm
+++ b/code/modules/projectiles/sentries.dm
@@ -4,6 +4,7 @@
use_power = 0
req_one_access = list(ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_ENGPREP, ACCESS_MARINE_LEADER)
hud_possible = list(MACHINE_HEALTH_HUD, MACHINE_AMMO_HUD)
+ allow_pass_flags = PASSABLE
///Spark system for making sparks
var/datum/effect_system/spark_spread/spark_system
@@ -301,7 +302,7 @@
set_on(FALSE)
update_icon()
-/obj/machinery/deployable/mounted/sentry/take_damage(damage_amount, damage_type, damage_flag, effects, attack_dir, armour_penetration)
+/obj/machinery/deployable/mounted/sentry/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
if(damage_amount <= 0)
return
if(prob(10))
@@ -374,7 +375,7 @@
var/obj/item/weapon/gun/gun = get_internal_item()
potential_targets.Cut()
if(!gun)
- return length(potential_targets)
+ return FALSE
for(var/mob/living/carbon/human/nearby_human AS in cheap_get_humans_near(src, range))
if(nearby_human.stat == DEAD || CHECK_BITFIELD(nearby_human.status_flags, INCORPOREAL) || (CHECK_BITFIELD(gun.turret_flags, TURRET_SAFETY) || nearby_human.wear_id?.iff_signal & iff_signal) || HAS_TRAIT(nearby_human, TRAIT_TURRET_HIDDEN)) //RU TGMC EDIT
continue
@@ -400,7 +401,7 @@
return
if(CHECK_BITFIELD(internal_gun.reciever_flags, AMMO_RECIEVER_REQUIRES_UNIQUE_ACTION) && length(internal_gun.chamber_items))
INVOKE_ASYNC(internal_gun, TYPE_PROC_REF(/obj/item/weapon/gun, do_unique_action))
- if(!CHECK_BITFIELD(internal_gun.flags_item, IS_DEPLOYED) || get_dist(src, gun_target) > range || (!CHECK_BITFIELD(get_dir(src, gun_target), dir) && !CHECK_BITFIELD(internal_gun.turret_flags, TURRET_RADIAL)) || !check_target_path(gun_target))
+ if(!CHECK_BITFIELD(internal_gun.item_flags, IS_DEPLOYED) || get_dist(src, gun_target) > range || (!CHECK_BITFIELD(get_dir(src, gun_target), dir) && !CHECK_BITFIELD(internal_gun.turret_flags, TURRET_RADIAL)) || !check_target_path(gun_target))
internal_gun.stop_fire()
firing = FALSE
update_minimap_icon()
@@ -412,9 +413,10 @@
///Sees if theres a target to shoot, then handles firing.
/obj/machinery/deployable/mounted/sentry/proc/sentry_start_fire()
var/obj/item/weapon/gun/gun = get_internal_item()
- var/mob/living/target = get_target()
+ var/atom/target = get_target()
+ sentry_alert(SENTRY_ALERT_HOSTILE, target)
update_icon()
- if(!target || get_dist(src, target) > range)
+ if(!target)
gun.stop_fire()
firing = FALSE
update_minimap_icon()
@@ -437,6 +439,8 @@
///Checks the path to the target for obstructions. Returns TRUE if the path is clear, FALSE if not.
/obj/machinery/deployable/mounted/sentry/proc/check_target_path(atom/target)
+ if(target.loc == loc)
+ return TRUE
var/list/turf/path = getline(src, target)
var/turf/starting_turf = get_turf(src)
var/turf/target_turf = path[length(path)-1]
@@ -452,6 +456,8 @@
break
if(i==2)
return FALSE
+
+ var/obj/item/weapon/gun/gun = get_internal_item()
for(var/turf/T AS in path)
var/obj/effect/particle_effect/smoke/smoke = locate() in T
if(smoke?.opacity)
@@ -460,36 +466,29 @@
if(IS_OPAQUE_TURF(T) || T.density && !(T.allow_pass_flags & PASS_PROJECTILE) && !(T.type in ignored_terrains))
return FALSE
- for(var/obj/machinery/MA in T)
- if(MA.density && !(MA.allow_pass_flags & PASS_PROJECTILE) && !(MA.type in ignored_terrains))
+ for(var/atom/movable/AM AS in T)
+ if(AM.opacity)
return FALSE
-
- for(var/obj/structure/S in T)
- if(S.density && !(S.allow_pass_flags & PASS_PROJECTILE) && !(S.type in ignored_terrains))
+ if(!AM.density)
+ continue
+ if(ismob(AM))
+ continue
+ if(!(AM.allow_pass_flags & (gun.ammo_datum_type::ammo_behavior_flags & AMMO_ENERGY ? (PASS_GLASS|PASS_PROJECTILE) : PASS_PROJECTILE) && !(AM.type in ignored_terrains))) //todo:accurately populate ignored_terrains
return FALSE
return TRUE
///Works through potential targets. First checks if they are in range, and if they are friend/foe. Then checks the path to them. Returns the first eligable target.
/obj/machinery/deployable/mounted/sentry/proc/get_target()
- var/distance = range + 0.5 //we add 0.5 so if a potential target is at range, it is accepted by the system
- var/buffer_distance
var/obj/item/weapon/gun/gun = get_internal_item()
- for (var/atom/nearby_target AS in potential_targets)
- if(!(get_dir(src, nearby_target) & dir) && !CHECK_BITFIELD(gun.turret_flags, TURRET_RADIAL))
- continue
-
- buffer_distance = get_dist(nearby_target, src)
+ for(var/atom/nearby_target AS in potential_targets)
+ if(nearby_target.loc == loc)
+ return nearby_target
- if (distance <= buffer_distance)
+ if(!(get_dir(src, nearby_target) & dir) && !CHECK_BITFIELD(gun.turret_flags, TURRET_RADIAL))
continue
-
if(!check_target_path(nearby_target))
continue
-
- sentry_alert(SENTRY_ALERT_HOSTILE, nearby_target)
-
- distance = buffer_distance
return nearby_target
/obj/machinery/deployable/mounted/sentry/disassemble(mob/user)
@@ -546,8 +545,8 @@
var/obj/item/item = get_internal_item()
if(!item)
return
- if(CHECK_BITFIELD(item.flags_item, DEPLOYED_NO_PICKUP))
- to_chat(user, span_notice("[src] is anchored in place and cannot be disassembled."))
+ if(CHECK_BITFIELD(item.item_flags, DEPLOYED_NO_PICKUP))
+ balloon_alert(user, "Cannot disassemble")
return
if(!match_iff(user)) //You can't steal other faction's turrets
to_chat(user, span_notice("Access denied."))
@@ -564,7 +563,7 @@
set_on(TRUE)
return
- DISABLE_BITFIELD(attached_item.flags_item, IS_DEPLOYED)
+ DISABLE_BITFIELD(attached_item.item_flags, IS_DEPLOYED)
attached_item.reset()
user.unset_interaction()
@@ -576,4 +575,4 @@
internal_item = null
QDEL_NULL(src)
- attached_item.update_icon_state()
+ attached_item.update_appearance()
diff --git a/code/modules/reagents/machinery/chem_dispenser.dm b/code/modules/reagents/machinery/chem_dispenser.dm
index 67114d765de9b..ea850995071f3 100644
--- a/code/modules/reagents/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/machinery/chem_dispenser.dm
@@ -332,6 +332,8 @@
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isreagentcontainer(I))
if(beaker)
@@ -408,6 +410,7 @@
. += image(icon, "[initial(icon_state)]_nobat")
/obj/machinery/chem_dispenser/update_icon_state()
+ . = ..()
if(machine_stat & NOPOWER)
icon_state = "dispenser_nopower"
return
@@ -470,6 +473,7 @@
/obj/machinery/chem_dispenser/soda/update_icon_state()
return
+
/obj/machinery/chem_dispenser/beer
icon_state = "booze_dispenser"
name = "booze dispenser"
diff --git a/code/modules/reagents/machinery/chem_master.dm b/code/modules/reagents/machinery/chem_master.dm
index 8f6b53ccc3ccf..af92541a0658c 100644
--- a/code/modules/reagents/machinery/chem_master.dm
+++ b/code/modules/reagents/machinery/chem_master.dm
@@ -64,6 +64,8 @@
/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I,/obj/item/reagent_containers) && I.is_open_container())
for(var/datum/reagent/X in I.reagents.reagent_list)
@@ -415,7 +417,8 @@
popup.set_content(dat)
popup.open()
-/obj/machinery/chem_master/update_icon()
+/obj/machinery/chem_master/update_icon_state()
+ . = ..()
if(machine_stat & BROKEN)
icon_state = (beaker?"mixer1_b":"mixer0_b")
else if(machine_stat & NOPOWER)
diff --git a/code/modules/reagents/machinery/reagentgrinder.dm b/code/modules/reagents/machinery/reagentgrinder.dm
index 8127b8113fb6c..3768c5d20fe7e 100644
--- a/code/modules/reagents/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/machinery/reagentgrinder.dm
@@ -66,12 +66,15 @@
/obj/machinery/reagentgrinder/update_icon_state()
+ . = ..()
icon_state = "juicer"+num2text(!isnull(beaker))
/obj/machinery/reagentgrinder/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers) && I.is_open_container())
if(beaker)
diff --git a/code/modules/reagents/reactions/medical.dm b/code/modules/reagents/reactions/medical.dm
index 435ac7e8e7305..399d920e97d4d 100644
--- a/code/modules/reagents/reactions/medical.dm
+++ b/code/modules/reagents/reactions/medical.dm
@@ -22,7 +22,7 @@
/datum/chemical_reaction/dermalime
name = "Dermaline"
- results = list(/datum/reagent/medicine/dermaline = 3)
+ results = list(/datum/reagent/medicine/dermaline = 4)
required_reagents = list(/datum/reagent/oxygen = 1, /datum/reagent/phosphorus = 1, /datum/reagent/medicine/kelotane = 1, /datum/reagent/medicine/lemoline = 1)
/datum/chemical_reaction/dexalinplus
@@ -37,12 +37,12 @@
/datum/chemical_reaction/meralyne
name = "Meralyne"
- results = list(/datum/reagent/medicine/meralyne = 3)
+ results = list(/datum/reagent/medicine/meralyne = 4)
required_reagents = list(/datum/reagent/medicine/inaprovaline = 1, /datum/reagent/medicine/bicaridine = 1, /datum/reagent/iron = 1, /datum/reagent/medicine/lemoline = 1)
/* RU TGMC EDIT
/datum/chemical_reaction/ryetalyn
name = "Ryetalyn"
- results = list(/datum/reagent/medicine/ryetalyn = 2)
+ results = list(/datum/reagent/medicine/ryetalyn = 3)
required_reagents = list(/datum/reagent/medicine/arithrazine = 1, /datum/reagent/carbon = 1, /datum/reagent/medicine/lemoline = 1)
RU TGMC EDIT */
/datum/chemical_reaction/cryoxadone
@@ -120,7 +120,7 @@ RU TGMC EDIT */
/datum/chemical_reaction/synaptizine
name = "Synaptizine"
- results = list(/datum/reagent/medicine/synaptizine = 3)
+ results = list(/datum/reagent/medicine/synaptizine = 4)
required_reagents = list(/datum/reagent/consumable/sugar = 1, /datum/reagent/lithium = 1, /datum/reagent/water = 1, /datum/reagent/medicine/lemoline = 1)
/datum/chemical_reaction/leporazine
@@ -131,7 +131,7 @@ RU TGMC EDIT */
/datum/chemical_reaction/hyronalin
name = "Hyronalin"
- results = list(/datum/reagent/medicine/hyronalin = 2)
+ results = list(/datum/reagent/medicine/hyronalin = 3)
required_reagents = list(/datum/reagent/radium = 1, /datum/reagent/medicine/dylovene = 1, /datum/reagent/medicine/lemoline = 1)
/datum/chemical_reaction/arithrazine
@@ -215,9 +215,9 @@ RU TGMC EDIT */
/datum/chemical_reaction/medicalnanites
name = "Medical Nanites"
- results = list(/datum/reagent/medicine/research/medicalnanites = 9)
+ results = list(/datum/reagent/medicalnanites = 9)
required_reagents = list(/datum/reagent/iron = 10, /datum/reagent/medicine/lemoline = 1)
- required_catalysts = list(/datum/reagent/medicine/research/medicalnanites = 1)
+ required_catalysts = list(/datum/reagent/medicalnanites = 1)
/datum/chemical_reaction/stimulum
name = "Stimulum"
diff --git a/code/modules/reagents/reagents.dm b/code/modules/reagents/reagents.dm
index bdfc9d7e5f21b..1b9c22354464e 100644
--- a/code/modules/reagents/reagents.dm
+++ b/code/modules/reagents/reagents.dm
@@ -48,7 +48,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
/// increases as addiction gets worse
var/addiction_stage = 0
/// does this show up on health analyzers
- var/scannable = FALSE
+ var/scannable = TRUE
/// if false stops metab in liverless mobs
var/self_consuming = FALSE
/// List of reagents removed by this chemical
diff --git a/code/modules/reagents/reagents/alcohol.dm b/code/modules/reagents/reagents/alcohol.dm
index 35572bfb82fca..ec99287b8562a 100644
--- a/code/modules/reagents/reagents/alcohol.dm
+++ b/code/modules/reagents/reagents/alcohol.dm
@@ -400,7 +400,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bloody_mary/on_mob_life(mob/living/L, metabolism)
if(L.blood_volume < BLOOD_VOLUME_NORMAL)
- L.blood_volume += 0.3 //Bloody Mary slowly restores blood loss.
+ L.adjust_blood_volume(0.3) //Bloody Mary slowly restores blood loss.
return ..()
/datum/reagent/consumable/ethanol/brave_bull
diff --git a/code/modules/reagents/reagents/food.dm b/code/modules/reagents/reagents/food.dm
index fe156088ab262..3473b5458b1ad 100644
--- a/code/modules/reagents/reagents/food.dm
+++ b/code/modules/reagents/reagents/food.dm
@@ -37,7 +37,7 @@
if(iscarbon(L))
var/mob/living/carbon/C = L
if(C.blood_volume < BLOOD_VOLUME_NORMAL)
- C.blood_volume += blood_gain
+ C.adjust_blood_volume(blood_gain)
return ..()
@@ -156,17 +156,17 @@
var/eyes_covered = 0
var/obj/item/safe_thing = null
if( victim.wear_mask )
- if( victim.wear_mask.flags_inventory & COVEREYES )
+ if( victim.wear_mask.inventory_flags & COVEREYES )
eyes_covered = 1
safe_thing = victim.wear_mask
- if( victim.wear_mask.flags_inventory & COVERMOUTH )
+ if( victim.wear_mask.inventory_flags & COVERMOUTH )
mouth_covered = 1
safe_thing = victim.wear_mask
if( victim.head )
- if( victim.head.flags_inventory & COVEREYES )
+ if( victim.head.inventory_flags & COVEREYES )
eyes_covered = 1
safe_thing = victim.head
- if( victim.head.flags_inventory & COVERMOUTH )
+ if( victim.head.inventory_flags & COVERMOUTH )
mouth_covered = 1
safe_thing = victim.head
if(victim.glasses)
diff --git a/code/modules/reagents/reagents/medical.dm b/code/modules/reagents/reagents/medical.dm
index 7db937e5cd0f5..262f05ebefcf7 100644
--- a/code/modules/reagents/reagents/medical.dm
+++ b/code/modules/reagents/reagents/medical.dm
@@ -13,7 +13,6 @@
color = COLOR_REAGENT_INAPROVALINE
overdose_threshold = REAGENTS_OVERDOSE*2
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL*2
- scannable = TRUE
trait_flags = TACHYCARDIC
/datum/reagent/medicine/inaprovaline/on_mob_add(mob/living/L, metabolism)
@@ -54,7 +53,6 @@
description = "Ryetalyn is a long-duration shield against toxic chemicals."
reagent_state = SOLID
color = COLOR_REAGENT_RYETALYN
- scannable = TRUE
custom_metabolism = REAGENTS_METABOLISM * 0.125
purge_list = list(/datum/reagent/toxin, /datum/reagent/zombium)
purge_rate = 5
@@ -87,7 +85,6 @@
name = "Paracetamol"
description = "Most probably know this as Tylenol, but this chemical is a mild, simple painkiller, good for enduring heavy labor."
color = COLOR_REAGENT_PARACETAMOL
- scannable = TRUE
custom_metabolism = REAGENTS_METABOLISM * 0.125
purge_list = list(/datum/reagent/medicine/kelotane, /datum/reagent/medicine/bicaridine)
purge_rate = 1
@@ -115,7 +112,6 @@
name = "Tramadol"
description = "A simple, yet effective painkiller."
color = COLOR_REAGENT_TRAMADOL
- scannable = TRUE
custom_metabolism = REAGENTS_METABOLISM * 0.5
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
@@ -141,7 +137,6 @@
custom_metabolism = REAGENTS_METABOLISM * 1.25
overdose_threshold = REAGENTS_OVERDOSE * 0.5
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL * 0.5
- scannable = TRUE
/datum/reagent/medicine/oxycodone/on_mob_add(mob/living/L, metabolism)
if(TIMER_COOLDOWN_CHECK(L, name))
@@ -183,7 +178,6 @@
custom_metabolism = REAGENTS_METABOLISM * 2
overdose_threshold = REAGENTS_OVERDOSE*0.6 //You aren't using this out of combat. And only the B18 makes it.
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL*0.5
- scannable = TRUE
/datum/reagent/medicine/hydrocodone/on_mob_life(mob/living/L, metabolism)
L.reagent_pain_modifier += PAIN_REDUCTION_VERY_HEAVY
@@ -202,7 +196,6 @@
name = "Leporazine"
description = "Leporazine can be use to stabilize an individuals body temperature."
color = COLOR_REAGENT_LEPORAZINE
- scannable = TRUE
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
@@ -225,7 +218,6 @@
name = "Kelotane"
description = "Kelotane is a drug used to treat burns."
color = COLOR_REAGENT_KELOTANE
- scannable = TRUE
purge_list = list(/datum/reagent/medicine/ryetalyn)
purge_rate = 1
overdose_threshold = REAGENTS_OVERDOSE
@@ -255,7 +247,6 @@
color = COLOR_REAGENT_DERMALINE
overdose_threshold = REAGENTS_OVERDOSE*0.5
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL*0.5
- scannable = TRUE
purge_list = list(/datum/reagent/medicine/oxycodone)
purge_rate = 0.2
@@ -285,11 +276,10 @@
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
taste_description = "salty water"
- scannable = TRUE
/datum/reagent/medicine/saline_glucose/on_mob_life(mob/living/L, metabolism)
if(L.blood_volume < BLOOD_VOLUME_NORMAL)
- L.blood_volume += 1.2
+ L.adjust_blood_volume(1.2)
return ..()
/datum/reagent/medicine/saline_glucose/overdose_process(mob/living/L, metabolism)
@@ -304,7 +294,6 @@
color = COLOR_REAGENT_DEXALIN
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/dexalin/on_mob_life(mob/living/L,metabolism)
L.adjustOxyLoss(-3*effect_str)
@@ -325,7 +314,6 @@
color = COLOR_REAGENT_DEXALINPLUS
overdose_threshold = REAGENTS_OVERDOSE/2
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/2
- scannable = TRUE
/datum/reagent/medicine/dexalinplus/on_mob_life(mob/living/L,metabolism)
L.adjustOxyLoss(-L.getOxyLoss())
@@ -342,7 +330,6 @@
name = "Tricordrazine"
description = "Tricordrazine is a highly potent stimulant, originally derived from cordrazine. Can be used to treat a wide range of injuries."
color = COLOR_REAGENT_TRICORDRAZINE
- scannable = TRUE
purge_list = list(/datum/reagent/medicine/ryetalyn)
purge_rate = 1
overdose_threshold = REAGENTS_OVERDOSE
@@ -371,7 +358,6 @@
name = "Dylovene"
description = "Dylovene is a broad-spectrum antitoxin."
color = COLOR_REAGENT_DYLOVENE
- scannable = TRUE
purge_list = list(/datum/reagent/toxin, /datum/reagent/medicine/research/stimulon, /datum/reagent/consumable/drink/atomiccoffee, /datum/reagent/medicine/paracetamol, /datum/reagent/medicine/larvaway)
purge_rate = 1
overdose_threshold = REAGENTS_OVERDOSE
@@ -446,7 +432,6 @@
color = COLOR_REAGENT_SYNAPTIZINE
overdose_threshold = REAGENTS_OVERDOSE/5
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/5
- scannable = TRUE
custom_metabolism = REAGENTS_METABOLISM * 0.5
purge_list = list(/datum/reagent/toxin/mindbreaker)
purge_rate = 5
@@ -541,7 +526,6 @@
custom_metabolism = REAGENTS_METABOLISM
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/hyronalin/on_mob_life(mob/living/L)
L.adjustToxLoss(-effect_str)
@@ -560,7 +544,6 @@
custom_metabolism = REAGENTS_METABOLISM
overdose_threshold = REAGENTS_OVERDOSE/2
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/2
- scannable = TRUE
/datum/reagent/medicine/arithrazine/on_mob_life(mob/living/L)
L.adjustToxLoss(-0.5*effect_str)
@@ -581,7 +564,6 @@
custom_metabolism = REAGENTS_METABOLISM * 5
overdose_threshold = REAGENTS_OVERDOSE/2 //so it makes the OD threshold effectively 15 so two pills is too much but one is fine
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/2.5 //and this makes the Critical OD 20
- scannable = TRUE
/datum/reagent/medicine/russian_red/on_mob_add(mob/living/L, metabolism)
var/mob/living/carbon/human/H = L
@@ -617,7 +599,6 @@
custom_metabolism = REAGENTS_METABOLISM * 0.25
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/alkysine/on_mob_life(mob/living/L, metabolism)
L.reagent_shock_modifier += PAIN_REDUCTION_VERY_LIGHT
@@ -637,7 +618,6 @@
color = COLOR_REAGENT_IMIDAZOLINE
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
taste_description = "dull toxin"
/datum/reagent/medicine/imidazoline/on_mob_life(mob/living/L, metabolism)
@@ -663,10 +643,9 @@
overdose_threshold = REAGENTS_OVERDOSE/30
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/25
custom_metabolism = REAGENTS_METABOLISM * 0.5
- scannable = TRUE
/datum/reagent/medicine/peridaxon_plus/on_mob_life(mob/living/L, metabolism)
- L.reagents.add_reagent(/datum/reagent/toxin,5)
+ L.reagents.add_reagent(/datum/reagent/toxin/scannable,5)
L.adjustStaminaLoss(10*effect_str)
if(!ishuman(L))
return ..()
@@ -692,7 +671,6 @@
purge_rate = 1
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/bicaridine/on_mob_life(mob/living/L, metabolism)
L.heal_overall_damage(effect_str, 0)
@@ -716,7 +694,6 @@
color = COLOR_REAGENT_MERALYNE
overdose_threshold = REAGENTS_OVERDOSE*0.5
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL*0.5
- scannable = TRUE
purge_list = list(/datum/reagent/medicine/oxycodone)
purge_rate = 0.2
@@ -742,11 +719,10 @@
color = COLOR_REAGENT_QUICKCLOT
overdose_threshold = REAGENTS_OVERDOSE/2 //Was 4, now 6 //Now 15
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/2
- scannable = TRUE //scannable now. HUZZAH.
custom_metabolism = REAGENTS_METABOLISM * 0.25
/datum/reagent/medicine/quickclot/on_mob_life(mob/living/L, metabolism)
- L.blood_volume += 0.2
+ L.adjust_blood_volume(0.2)
if(!ishuman(L) || L.bodytemperature > 169) //only heals IB at cryogenic temperatures.
return ..()
var/mob/living/carbon/human/H = L
@@ -769,7 +745,6 @@
color = COLOR_REAGENT_QUICKCLOTPLUS
overdose_threshold = REAGENTS_OVERDOSE/5 //6u
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/5 //12u
- scannable = TRUE
custom_metabolism = REAGENTS_METABOLISM * 2.5
///The IB wound this dose of QCP will cure, if it lasts long enough
var/datum/wound/internal_bleeding/target_IB
@@ -788,7 +763,7 @@
target_IB = null
/datum/reagent/medicine/quickclotplus/on_mob_life(mob/living/L, metabolism)
- L.reagents.add_reagent(/datum/reagent/toxin,5)
+ L.reagents.add_reagent(/datum/reagent/toxin/scannable,5)
L.reagent_shock_modifier -= PAIN_REDUCTION_VERY_HEAVY
L.adjustStaminaLoss(15*effect_str)
if(!target_IB)
@@ -832,10 +807,10 @@
/datum/reagent/medicine/quickclotplus/overdose_process(mob/living/L, metabolism)
L.apply_damage(1.5*effect_str, TOX)
- L.blood_volume -= 4
+ L.adjust_blood_volume(-4)
/datum/reagent/medicine/quickclotplus/overdose_crit_process(mob/living/L, metabolism)
- L.blood_volume -= 20
+ L.adjust_blood_volume(-20)
/datum/reagent/medicine/nanoblood
name = "Nanoblood"
@@ -843,17 +818,16 @@
color = COLOR_REAGENT_NANOBLOOD
overdose_threshold = REAGENTS_OVERDOSE/5 //6u
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL/5 //10u
- scannable = TRUE
/datum/reagent/medicine/nanoblood/on_mob_life(mob/living/L, metabolism)
- L.blood_volume += 2.4
+ L.adjust_blood_volume(2.4)
L.adjustToxLoss(effect_str)
L.adjustStaminaLoss(6*effect_str)
if(L.blood_volume < BLOOD_VOLUME_OKAY)
- L.blood_volume += 2.4
+ L.adjust_blood_volume(2.4)
if(L.blood_volume < BLOOD_VOLUME_BAD)
- L.blood_volume = (BLOOD_VOLUME_BAD+1)
- L.reagents.add_reagent(/datum/reagent/toxin,25)
+ L.set_blood_volume(BLOOD_VOLUME_BAD+1)
+ L.reagents.add_reagent(/datum/reagent/toxin/scannable,25)
L.AdjustSleeping(10 SECONDS)
return ..()
@@ -967,7 +941,6 @@
description = "A chemical mixture with almost magical healing powers. Its main limitation is that the targets body temperature must be under 170K for it to metabolise correctly."
reagent_state = LIQUID
color = COLOR_REAGENT_CRYOXADONE
- scannable = TRUE
taste_description = "sludge"
trait_flags = BRADYCARDICS
@@ -983,7 +956,6 @@
name = "Clonexadone"
description = "A liquid compound similar to that used in the cloning process. Can be used to 'finish' the cloning process when used in conjunction with a cryo tube."
color = COLOR_REAGENT_CLONEXADONE
- scannable = TRUE
taste_description = "muscle"
trait_flags = BRADYCARDICS
@@ -1003,7 +975,6 @@
color = COLOR_REAGENT_REZADONE
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
taste_description = "fish"
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/L, metabolism)
@@ -1038,7 +1009,6 @@
custom_metabolism = REAGENTS_METABOLISM * 0.05
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/spaceacillin/overdose_process(mob/living/L, metabolism)
L.apply_damage(effect_str, TOX)
@@ -1052,7 +1022,6 @@
color = COLOR_REAGENT_POLYHEXANIDE
custom_metabolism = REAGENTS_METABOLISM * 2
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
/datum/reagent/medicine/polyhexanide/on_mob_life(mob/living/L, metabolism)
switch(current_cycle)
@@ -1076,7 +1045,6 @@
custom_metabolism = REAGENTS_METABOLISM * 0.5
overdose_threshold = REAGENTS_OVERDOSE * 0.5
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL * 0.5
- scannable = TRUE
/datum/reagent/medicine/larvaway/on_mob_life(mob/living/L, metabolism)
switch(current_cycle)
@@ -1132,7 +1100,6 @@
custom_metabolism = REAGENTS_METABOLISM * 5
purge_list = list(/datum/reagent/medicine, /datum/reagent/toxin, /datum/reagent/zombium)
purge_rate = 5
- scannable = TRUE
taste_description = "punishment"
taste_multi = 8
@@ -1183,7 +1150,6 @@
description = "Accelerates natural bone repair in a low temperature environment. Causes severe pain."
color = COLOR_REAGENT_BIHEXAJULINE
taste_description = "skim milk"
- scannable = TRUE
overdose_threshold = REAGENTS_OVERDOSE
/datum/reagent/medicine/bihexajuline/on_mob_life(mob/living/L, metabolism)
@@ -1224,7 +1190,6 @@
description = "This is a latent poison, designed to quickly and painlessly kill you in the event that you become unable to fight. Never washes out on it's own, must be purged."
color = COLOR_REAGENT_QUIETUS
custom_metabolism = 0
- scannable = TRUE
taste_description = "Victory"
/datum/reagent/medicine/research/quietus/on_mob_add(mob/living/L, metabolism)
@@ -1256,7 +1221,6 @@
name = "Somolent"
description = "This is a highly potent regenerative drug, designed to heal critically injured personnel. Only functions on unconscious or sleeping people."
color = COLOR_REAGENT_SOMOLENT
- scannable = TRUE
overdose_threshold = REAGENTS_OVERDOSE
taste_description = "naptime"
@@ -1281,57 +1245,71 @@
/datum/reagent/medicine/research/somolent/overdose_process(mob/living/L, metabolism)
holder.remove_reagent(/datum/reagent/medicine/research/somolent, 1)
-/datum/reagent/medicine/research/medicalnanites
+/datum/reagent/medicalnanites
name = "Medical nanites"
description = "These are a batch of construction nanites altered for in-vivo replication. They can heal wounds using the iron present in the bloodstream. Medical care is recommended during injection."
color = COLOR_REAGENT_MEDICALNANITES
custom_metabolism = 0
- scannable = TRUE
taste_description = "metal, followed by mild burning"
overdose_threshold = REAGENTS_OVERDOSE * 1.2 //slight buffer to keep you safe
+ purge_list = list(
+ /datum/reagent/medicine/bicaridine,
+ /datum/reagent/medicine/kelotane,
+ /datum/reagent/medicine/tramadol,
+ /datum/reagent/medicine/oxycodone,
+ /datum/reagent/medicine/tricordrazine,
+ /datum/reagent/medicine/meralyne,
+ /datum/reagent/medicine/dermaline,
+ /datum/reagent/medicine/paracetamol,
+ /datum/reagent/medicine/russian_red,
+ /datum/reagent/consumable/drink/doctor_delight,
+ )
+ purge_rate = 5
-/datum/reagent/medicine/research/medicalnanites/on_mob_add(mob/living/L, metabolism)
+/datum/reagent/medicalnanites/on_mob_add(mob/living/L, metabolism)
to_chat(L, span_userdanger("You feel like you should stay near medical help until this shot settles in."))
-/datum/reagent/medicine/research/medicalnanites/on_mob_life(mob/living/L, metabolism)
+/datum/reagent/medicalnanites/on_mob_life(mob/living/L, metabolism)
switch(current_cycle)
if(1 to 75)
- L.take_limb_damage(0.015*current_cycle*effect_str, 0.015*current_cycle*effect_str)
- L.adjustToxLoss(1*effect_str)
- L.adjustStaminaLoss((1.5)*effect_str)
- L.reagents.add_reagent(/datum/reagent/medicine/research/medicalnanites, 0.40)
+ L.take_limb_damage(0.015 * current_cycle * effect_str, 0.015 * current_cycle * effect_str)
+ L.adjustToxLoss(1 * effect_str)
+ L.adjustStaminaLoss(1.5 * effect_str)
+ L.reagents.add_reagent(/datum/reagent/medicalnanites, 0.4)
if(prob(5))
to_chat(L, span_notice("You feel intense itching!"))
if(76)
to_chat(L, span_warning("The pain rapidly subsides. Looks like they've adapted to you."))
if(77 to INFINITY)
if(volume < 30) //smol injection will self-replicate up to 30u using 240u of blood.
- L.reagents.add_reagent(/datum/reagent/medicine/research/medicalnanites, 0.15)
- L.blood_volume -= 2
+ L.reagents.add_reagent(/datum/reagent/medicalnanites, 0.15)
+ L.adjust_blood_volume(-2)
if(volume < 35) //allows 10 ticks of healing for 20 points of free heal to lower scratch damage bloodloss amounts.
- L.reagents.add_reagent(/datum/reagent/medicine/research/medicalnanites, 0.1)
+ L.reagents.add_reagent(/datum/reagent/medicalnanites, 0.1)
+
+ if(volume > 5)
+ L.reagent_pain_modifier += PAIN_REDUCTION_VERY_HEAVY
+ L.adjustToxLoss(-0.15 * effect_str)
- if (volume > 5 && L.getBruteLoss(organic_only = TRUE))
- L.heal_overall_damage(2*effect_str, 0)
- L.adjustToxLoss(0.1*effect_str)
- holder.remove_reagent(/datum/reagent/medicine/research/medicalnanites, 0.5)
- if(prob(40))
+ if(volume > 5 && L.getBruteLoss(organic_only = TRUE))
+ L.heal_overall_damage(3 * effect_str, 0)
+ holder.remove_reagent(/datum/reagent/medicalnanites, 0.5)
+ if(prob(10))
to_chat(L, span_notice("Your cuts and bruises begin to scab over rapidly!"))
- if (volume > 5 && L.getFireLoss(organic_only = TRUE))
- L.heal_overall_damage(0, 2*effect_str)
- L.adjustToxLoss(0.1*effect_str)
- holder.remove_reagent(/datum/reagent/medicine/research/medicalnanites, 0.5)
- if(prob(40))
+ if(volume > 5 && L.getFireLoss(organic_only = TRUE))
+ L.heal_overall_damage(0, 3 * effect_str)
+ holder.remove_reagent(/datum/reagent/medicalnanites, 0.5)
+ if(prob(10))
to_chat(L, span_notice("Your burns begin to slough off, revealing healthy tissue!"))
return ..()
-/datum/reagent/medicine/research/medicalnanites/overdose_process(mob/living/L, metabolism)
+/datum/reagent/medicalnanites/overdose_process(mob/living/L, metabolism)
L.adjustToxLoss(effect_str) //softcap VS injecting massive amounts of medical nanites for the healing factor with no downsides. Still doable if you're clever about it.
- holder.remove_reagent(/datum/reagent/medicine/research/medicalnanites, 0.25)
+ holder.remove_reagent(/datum/reagent/medicalnanites, 0.25)
-/datum/reagent/medicine/research/medicalnanites/on_mob_delete(mob/living/L, metabolism)
+/datum/reagent/medicalnanites/on_mob_delete(mob/living/L, metabolism)
to_chat(L, span_userdanger("Your nanites have been fully purged! They no longer affect you."))
/datum/reagent/medicine/research/stimulon
@@ -1339,7 +1317,6 @@
description = "A chemical designed to boost running by driving your body beyond it's normal limits. Can have unpredictable side effects, caution recommended."
color = COLOR_REAGENT_STIMULON
custom_metabolism = 0
- scannable = TRUE
/datum/reagent/medicine/research/stimulon/on_mob_add(mob/living/L, metabolism)
to_chat(L, span_userdanger("You feel jittery and fast! Time to MOVE!"))
diff --git a/code/modules/reagents/reagents/other.dm b/code/modules/reagents/reagents/other.dm
index cb2c42d457a3d..2b2c9dca6d366 100644
--- a/code/modules/reagents/reagents/other.dm
+++ b/code/modules/reagents/reagents/other.dm
@@ -345,7 +345,6 @@
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
taste_description = "iron"
- scannable = TRUE
/datum/reagent/iron/overdose_process(mob/living/L, metabolism)
L.apply_damages(1, 0, 1)
@@ -654,4 +653,3 @@
custom_metabolism = REAGENTS_METABOLISM * 0.1
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
diff --git a/code/modules/reagents/reagents/toxin.dm b/code/modules/reagents/reagents/toxin.dm
index 3c109bf56c122..0434fd4bdeb0e 100644
--- a/code/modules/reagents/reagents/toxin.dm
+++ b/code/modules/reagents/reagents/toxin.dm
@@ -17,6 +17,9 @@
L.adjustToxLoss(toxpwr*0.5*effect_str)
return ..()
+///For medicines that generate toxin reagent when metabolized
+/datum/reagent/toxin/scannable
+
/datum/reagent/toxin/hptoxin
name = "Toxin"
description = "A toxic chemical."
@@ -217,7 +220,6 @@
toxpwr = 0
overdose_threshold = REAGENTS_OVERDOSE
overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL
- scannable = TRUE
taste_description = "cough syrup"
trait_flags = BRADYCARDICS
@@ -425,14 +427,14 @@
/datum/reagent/toxin/nanites/on_mob_add(mob/living/L, metabolism)
to_chat(L, span_userdanger("Your body begins to twist and deform! Get out of the razorburn!"))
- . = ..()
+ return ..()
/datum/reagent/toxin/nanites/on_mob_life(mob/living/L, metabolism)
L.apply_damages(2.5*effect_str, 1.5*effect_str, 1.5*effect_str) //DO NOT DRINK THIS. Seriously!
- L.blood_volume -= 5
+ L.adjust_blood_volume(-5)
if(current_cycle > 5)
L.apply_damages(2.5*effect_str, 1.5*effect_str, 1.5*effect_str)
- L.blood_volume -= 5
+ L.adjust_blood_volume(-5)
holder.remove_reagent(/datum/reagent/toxin/nanites, (current_cycle * 0.2) - 1)
if(volume > 100)
var/turf/location = get_turf(holder.my_atom)
@@ -448,7 +450,6 @@
color = COLOR_TOXIN_XENO_NEUROTOXIN
custom_metabolism = REAGENTS_METABOLISM * 2
overdose_threshold = 10000 //Overdosing for neuro is what happens when you run out of stamina to avoid its oxy and toxin damage
- scannable = TRUE
toxpwr = 0
/datum/reagent/toxin/xeno_neurotoxin/on_mob_life(mob/living/L, metabolism)
@@ -495,7 +496,6 @@
color = COLOR_TOXIN_XENO_HEMODILE
custom_metabolism = 0.4
overdose_threshold = 10000
- scannable = TRUE
toxpwr = 0
/datum/reagent/toxin/xeno_hemodile/on_mob_life(mob/living/L, metabolism)
@@ -538,7 +538,6 @@
color = COLOR_TOXIN_XENO_TRANSVITOX
custom_metabolism = 0.4
overdose_threshold = 10000
- scannable = TRUE
toxpwr = 0
/datum/reagent/toxin/xeno_transvitox/on_mob_add(mob/living/L, metabolism, affecting)
@@ -606,7 +605,6 @@
color = COLOR_TOXIN_XENO_SANGUINAL
custom_metabolism = 0.4
overdose_threshold = 10000
- scannable = TRUE
toxpwr = 0
/datum/reagent/toxin/xeno_sanguinal/on_mob_life(mob/living/L, metabolism)
@@ -640,7 +638,6 @@
color = COLOR_TOXIN_XENO_OZELOMELYN
custom_metabolism = 1.5 // metabolizes decently quickly. A sting does 15 at the same rate as neurotoxin.
overdose_threshold = 10000
- scannable = TRUE
toxpwr = 0 // This is going to do slightly snowflake tox damage.
purge_list = list(/datum/reagent/medicine)
purge_rate = 5
@@ -661,7 +658,6 @@
reagent_state = LIQUID
color = COLOR_TOXIN_ZOMBIUM
custom_metabolism = REAGENTS_METABOLISM * 0.25
- scannable = TRUE
overdose_threshold = 20
overdose_crit_threshold = 50
@@ -701,7 +697,6 @@
color = COLOR_TOXIN_SATRAPINE
overdose_threshold = 10000
custom_metabolism = REAGENTS_METABOLISM
- scannable = TRUE
toxpwr = 0
purge_list = list(
/datum/reagent/medicine/tramadol,
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index aa3561200a860..268d6f217c206 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -1,52 +1,42 @@
//conveyor2 is pretty much like the original, except it supports corners, but not diverters.
//note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards.
+
+///Max amount of items it will try move in one go
#define MAX_CONVEYOR_ITEMS_MOVE 30
+
+///It don't go
+#define CONVEYOR_OFF 0
+///It go forwards
+#define CONVEYOR_ON_FORWARDS 1
+///It go back
+#define CONVEYOR_ON_REVERSE -1
+
+///true if can operate (no broken segments in this belt run)
+#define CONVEYOR_OPERABLE (1<<0)
+///Inverts the direction the conveyor belt moves, only particularly relevant for diagonals
+#define CONVEYOR_INVERTED (1<<1)
+///Currently has things scheduled for movement. Required to reduce lag
+#define CONVEYOR_IS_CONVEYING (1<<2)
+
GLOBAL_LIST_EMPTY(conveyors_by_id)
/obj/machinery/conveyor
icon = 'icons/obj/recycling.dmi'
icon_state = "conveyor_map"
name = "conveyor belt"
- desc = "A conveyor belt. It can be rotated with a wrench. It can be reversed with a screwdriver. The belt can be flipped with a wirecutter."
+ desc = "A conveyor belt. It can be rotated with a wrench. It can be reversed with a screwdriver."
layer = FIREDOOR_OPEN_LAYER
max_integrity = 50
resistance_flags = XENO_DAMAGEABLE
- var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off
- var/operable = 1 // true if can operate (no broken segments in this belt run)
- var/forwards // this is the default (forward) direction, set by the map dir
- var/backwards // hopefully self-explanatory
- var/movedir // the actual direction to move stuff in
-
- var/list/affecting // the list of all items that will be moved this ptick
- var/id = "" // the control ID - must match controller ID
- /// Inverts the direction the conveyor belt moves when false.
- var/verted = FALSE
- /// Is the conveyor's belt flipped? Useful mostly for conveyor belt corners. It makes the belt point in the other direction, rather than just going in reverse.
- var/flipped = FALSE
- /// Are we currently conveying items?
- var/conveying = FALSE
-
-/obj/machinery/conveyor/centcom_auto
- id = "round_end_belt"
-
-/obj/machinery/conveyor/inverted //Directions inverted so you can use different corner pieces.
- icon_state = "conveyor_map_inverted"
- verted = -1
- flipped = TRUE
-
-/obj/machinery/conveyor/inverted/Initialize(mapload)
- . = ..()
- if(mapload && !(ISDIAGONALDIR(dir)))
- stack_trace("[src] at [AREACOORD(src)] spawned without using a diagonal dir. Please replace with a normal version.")
-
-
-/obj/machinery/conveyor/auto/update()
- . = ..()
- if(.)
- operating = TRUE
- update_icon()
+ ///Conveyor specific flags
+ var/conveyor_flags = CONVEYOR_OPERABLE
+ ///Operating direction
+ var/operating = CONVEYOR_OFF
+ ///Current direction of movement
+ var/movedir
+ /// the control ID - must match controller ID
+ var/id = ""
-// create a conveyor
/obj/machinery/conveyor/Initialize(mapload, newdir, newid)
. = ..()
if(newdir)
@@ -57,10 +47,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
update_move_direction()
update_icon()
-/obj/machinery/conveyor/auto/Initialize(mapload, newdir)
- operating = TRUE
- return ..()
-
/obj/machinery/conveyor/Destroy()
LAZYREMOVE(GLOB.conveyors_by_id[id], src)
return ..()
@@ -74,101 +60,17 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
else
return ..()
-/obj/machinery/conveyor/setDir(newdir)
- . = ..()
- update_move_direction()
-
-/obj/machinery/conveyor/proc/update_move_direction()
- switch(dir)
- if(NORTH)
- forwards = NORTH
- backwards = SOUTH
- if(SOUTH)
- forwards = SOUTH
- backwards = NORTH
- if(EAST)
- forwards = EAST
- backwards = WEST
- if(WEST)
- forwards = WEST
- backwards = EAST
- if(NORTHEAST)
- forwards = EAST
- backwards = SOUTH
- if(NORTHWEST)
- forwards = NORTH
- backwards = EAST
- if(SOUTHEAST)
- forwards = SOUTH
- backwards = WEST
- if(SOUTHWEST)
- forwards = WEST
- backwards = NORTH
- if(verted)
- var/temp = forwards
- forwards = backwards
- backwards = temp
- if(flipped)
- var/temp = forwards
- forwards = backwards
- backwards = temp
- if(operating == 1)
- movedir = forwards
- else
- movedir = backwards
- update()
-
/obj/machinery/conveyor/update_icon_state()
+ . = ..()
if(machine_stat & BROKEN)
icon_state = "conveyor-broken"
- else
- icon_state = "conveyor[verted ? -operating : operating ][flipped ? "-flipped" : ""]"
-/obj/machinery/conveyor/proc/update()
- if(machine_stat & BROKEN || !operable || machine_stat & NOPOWER)
- operating = FALSE
- update_icon()
- return FALSE
- return TRUE
-
-// machine process
-// move items to the target location
-/obj/machinery/conveyor/process()
- if(machine_stat & (BROKEN | NOPOWER))
- return
-
- //If the conveyor is broken or already moving items
- if(!operating || conveying)
- return
-
- //get the first 30 items in contents
- var/turf/locturf = loc
- var/list/items = locturf.contents - src
- if(!LAZYLEN(items))//Dont do anything at all if theres nothing there but the conveyor
- return
- var/list/affecting
- if(length(items) > MAX_CONVEYOR_ITEMS_MOVE)
- affecting = items.Copy(1, MAX_CONVEYOR_ITEMS_MOVE + 1)//Lists start at 1 lol
else
- affecting = items
- conveying = TRUE
+ icon_state = "conveyor[!operating ? "_off" : operating == CONVEYOR_ON_FORWARDS ? "_forwards": "_reverse"][conveyor_flags & CONVEYOR_INVERTED ? "_inverted" : ""]"
- INVOKE_NEXT_TICK(src, PROC_REF(convey), affecting)//Movement effect
-
-/obj/machinery/conveyor/proc/convey(list/affecting)
- for(var/am in affecting)
- if(!ismovable(am)) //This is like a third faster than for(var/atom/movable in affecting)
- continue
- var/atom/movable/movable_thing = am
- //Give this a chance to yield if the server is busy
- stoplag()
- if(QDELETED(movable_thing) || (movable_thing.loc != loc))
- continue
- if(iseffect(movable_thing) || isdead(movable_thing))
- continue
- if(!movable_thing.anchored)
- step(movable_thing, movedir)
- conveying = FALSE
+/obj/machinery/conveyor/setDir(newdir)
+ . = ..()
+ update_move_direction()
/obj/machinery/conveyor/crowbar_act(mob/living/user, obj/item/I)
user.visible_message(span_notice("[user] struggles to pry up \the [src] with \the [I]."), \
@@ -192,16 +94,10 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/obj/machinery/conveyor/screwdriver_act(mob/living/user, obj/item/I)
if(machine_stat & BROKEN)
return TRUE
- verted = !verted
+ conveyor_flags ^= CONVEYOR_INVERTED
update_move_direction()
- to_chat(user, span_notice("You set [src]'s direction [verted ? "backwards" : "back to default"]."))
-
-/obj/machinery/conveyor/wirecutter_act(mob/living/user, obj/item/I)
- if(machine_stat & BROKEN)
- return TRUE
- flipped = !flipped
- update_move_direction()
- to_chat(user, span_notice("You flip [src]'s belt [flipped ? "around" : "back to normal"]."))
+ update_icon()
+ balloon_alert(user, "[conveyor_flags & CONVEYOR_INVERTED ? "backwards" : "back to default"]")
/obj/machinery/conveyor/attackby(obj/item/I, mob/living/user, def_zone)
. = ..()
@@ -215,52 +111,148 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
return
user.Move_Pulled(src)
-// make the conveyor broken
-// also propagate inoperability to any connected conveyor with the same ID
-/obj/machinery/conveyor/proc/broken()
- obj_break()
+/obj/machinery/conveyor/power_change()
+ . = ..()
update()
- var/obj/machinery/conveyor/C = locate() in get_step(src, dir)
- if(C)
- C.set_operable(dir, id, 0)
+/obj/machinery/conveyor/process()
+ if(conveyor_flags & CONVEYOR_IS_CONVEYING)
+ return //you've made a lag monster
+ if(!is_operational())
+ return PROCESS_KILL
+ if(!operating)
+ return PROCESS_KILL
+ if(!isturf(loc))
+ return PROCESS_KILL //how
- C = locate() in get_step(src, REVERSE_DIR(dir))
- if(C)
- C.set_operable(REVERSE_DIR(dir), id, 0)
+ //get the first 30 items in contents
+ var/list/items_to_move = loc.contents - src
+ if(length(items_to_move) > MAX_CONVEYOR_ITEMS_MOVE)
+ items_to_move = items_to_move.Copy(1, MAX_CONVEYOR_ITEMS_MOVE + 1)
+ conveyor_flags |= CONVEYOR_IS_CONVEYING
+ INVOKE_NEXT_TICK(src, PROC_REF(convey), items_to_move)
-//set the operable var if ID matches, propagating in the given direction
+///Attempts to move a batch of AMs
+/obj/machinery/conveyor/proc/convey(list/affecting)
+ conveyor_flags &= ~CONVEYOR_IS_CONVEYING
+ if(!is_operational())
+ return
+ if(!operating)
+ return
+ for(var/am in affecting)
+ if(!ismovable(am)) //This is like a third faster than for(var/atom/movable in affecting)
+ continue
+ var/atom/movable/movable_thing = am
+ stoplag() //Give this a chance to yield if the server is busy
+ if(QDELETED(movable_thing))
+ continue
+ if((movable_thing.loc != loc))
+ continue
+ if(iseffect(movable_thing))
+ continue
+ if(isdead(movable_thing))
+ continue
+ if(movable_thing.anchored)
+ continue
+ step(movable_thing, movedir)
-/obj/machinery/conveyor/proc/set_operable(stepdir, match_id, op)
+///Sets the correct movement directions based on dir
+/obj/machinery/conveyor/proc/update_move_direction()
+ var/forwards
+ var/backwards
+ switch(dir)
+ if(NORTH)
+ forwards = NORTH
+ backwards = SOUTH
+ if(SOUTH)
+ forwards = SOUTH
+ backwards = NORTH
+ if(EAST)
+ forwards = EAST
+ backwards = WEST
+ if(WEST)
+ forwards = WEST
+ backwards = EAST
+ if(NORTHEAST)
+ forwards = EAST
+ backwards = SOUTH
+ if(NORTHWEST)
+ forwards = NORTH
+ backwards = EAST
+ if(SOUTHEAST)
+ forwards = SOUTH
+ backwards = WEST
+ if(SOUTHWEST)
+ forwards = WEST
+ backwards = NORTH
+ if(conveyor_flags & CONVEYOR_INVERTED)
+ var/temp = forwards
+ forwards = backwards
+ backwards = temp
+ if(operating == CONVEYOR_ON_FORWARDS)
+ movedir = forwards
+ else
+ movedir = backwards
+ update()
- if(id != match_id)
+///Handles setting its operating status
+/obj/machinery/conveyor/proc/set_operating(new_position)
+ if(operating == new_position)
return
- operable = op
+ operating = new_position
+ update_move_direction()
+ update_icon()
- update()
- var/obj/machinery/conveyor/C = locate() in get_step(src, stepdir)
- if(C)
- C.set_operable(stepdir, id, op)
+ if(operating)
+ start_processing()
+ else
+ stop_processing()
-/obj/machinery/conveyor/power_change()
+///Checks to see if the conveyor needs to be switched off
+/obj/machinery/conveyor/proc/update()
+ if(!is_operational() || !(conveyor_flags & CONVEYOR_OPERABLE))
+ set_operating(CONVEYOR_OFF)
+ return FALSE
+ return TRUE
+
+/obj/machinery/conveyor/centcom_auto
+ id = "round_end_belt"
+
+/obj/machinery/conveyor/inverted //Directions inverted so you can use different corner pieces.
+ icon_state = "conveyor_map_inverted"
+ conveyor_flags = CONVEYOR_OPERABLE|CONVEYOR_INVERTED
+
+/obj/machinery/conveyor/inverted/Initialize(mapload)
. = ..()
- update()
+ if(mapload && !(ISDIAGONALDIR(dir)))
+ stack_trace("[src] at [AREACOORD(src)] spawned without using a diagonal dir. Please replace with a normal version.")
-///////// the conveyor control switch
+/obj/machinery/conveyor/auto/Initialize(mapload, newdir)
+ set_operating(CONVEYOR_ON_FORWARDS)
+ return ..()
+
+/obj/machinery/conveyor/auto/update()
+ . = ..()
+ if(.)
+ set_operating(CONVEYOR_ON_FORWARDS)
+///////// the conveyor control switch
/obj/machinery/conveyor_switch
name = "conveyor switch"
desc = "A conveyor control switch."
icon = 'icons/obj/recycling.dmi'
icon_state = "switch-off"
-
- var/position = 0 // 0 off, -1 reverse, 1 forward
- var/last_pos = -1 // last direction setting
- var/oneway = FALSE // if the switch only operates the conveyor belts in a single direction.
- var/invert_icon = FALSE // If the level points the opposite direction when it's turned on.
-
- var/id = "" // must match conveyor IDs to control them
+ ///switch position
+ var/position = CONVEYOR_OFF
+ ///Previous switch position
+ var/last_pos = -1
+ ///If this only works one way
+ var/oneway = FALSE
+ ///If the level points the opposite direction when it's turned on.
+ var/invert_icon = FALSE
+ ///ID. Must match conveyor ID's to control them
+ var/id = ""
/obj/machinery/conveyor_switch/Initialize(mapload, newid)
. = ..()
@@ -285,12 +277,13 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
// update the icon depending on the position
/obj/machinery/conveyor_switch/update_icon_state()
- if(position<0)
+ . = ..()
+ if(position == CONVEYOR_ON_REVERSE)
if(invert_icon)
icon_state = "switch-fwd"
else
icon_state = "switch-rev"
- else if(position>0)
+ else if(position == CONVEYOR_ON_FORWARDS)
if(invert_icon)
icon_state = "switch-rev"
else
@@ -301,13 +294,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/// Updates all conveyor belts that are linked to this switch, and tells them to start processing.
/obj/machinery/conveyor_switch/proc/update_linked_conveyors()
for(var/obj/machinery/conveyor/C in GLOB.conveyors_by_id[id])
- C.operating = position
- C.update_move_direction()
- C.update_icon()
- if(C.operating)
- C.start_processing()
- else
- C.stop_processing()
+ C.set_operating(position)
CHECK_TICK
/// Finds any switches with same `id` as this one, and set their position and icon to match us.
@@ -325,14 +312,14 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
position = oneway
else
if(last_pos < 0)
- position = 1
- last_pos = 0
+ position = CONVEYOR_ON_FORWARDS
+ last_pos = CONVEYOR_OFF
else
- position = -1
- last_pos = 0
+ position = CONVEYOR_ON_REVERSE
+ last_pos = CONVEYOR_OFF
else
last_pos = position
- position = 0
+ position = CONVEYOR_OFF
/// Called when a user clicks on this switch with an open hand.
/obj/machinery/conveyor_switch/interact(mob/user)
@@ -421,7 +408,9 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
use(1)
/obj/item/stack/conveyor/attackby(obj/item/I, mob/user, params)
- ..()
+ . = ..()
+ if(.)
+ return
if(istype(I, /obj/item/conveyor_switch_construct))
to_chat(user, span_notice("You link the switch to the conveyor belt assembly."))
var/obj/item/conveyor_switch_construct/C = I
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index 4bc6008a21354..14def464574bd 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -247,7 +247,7 @@
if(W.remove_fuel(0,user))
playsound(src.loc, 'sound/items/welder2.ogg', 25, 1)
to_chat(user, "Welding the [nicetype] in place.")
- if(do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, /obj/item/tool/weldingtool/proc/isOn)))
+ if(do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
to_chat(user, "The [nicetype] has been welded in place!")
update() // TODO: Make this neat
if(ispipe) // Pipe
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index c09dc4c1bf170..d7f631f50a29b 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -67,6 +67,8 @@
//Attack by item places it in to disposal
/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(machine_stat & BROKEN)
return
@@ -100,7 +102,7 @@
playsound(loc, 'sound/items/welder2.ogg', 25, 1)
to_chat(user, span_notice("You start slicing the floorweld off the disposal unit."))
- if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return
to_chat(user, span_notice("You sliced the floorweld off the disposal unit."))
@@ -702,6 +704,8 @@
//Attack by item. Weldingtool: unfasten and convert to obj/disposalconstruct
/obj/structure/disposalpipe/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
var/turf/T = loc
if(T.intact_tile)
@@ -1011,6 +1015,8 @@
/obj/structure/disposalpipe/tagger/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/destTagger))
var/obj/item/destTagger/O = I
@@ -1082,6 +1088,8 @@
/obj/structure/disposalpipe/sortjunction/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/destTagger))
var/obj/item/destTagger/O = I
@@ -1304,6 +1312,8 @@
/obj/structure/disposaloutlet/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
mode = !mode
@@ -1323,7 +1333,7 @@
playsound(loc, 'sound/items/welder2.ogg', 25, 1)
to_chat(user, span_notice("You start slicing the floorweld off the disposal outlet."))
- if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return
to_chat(user, span_notice("You sliced the floorweld off the disposal outlet."))
diff --git a/code/modules/recycling/recycler.dm b/code/modules/recycling/recycler.dm
index d0430626397ca..551b82d21eeef 100644
--- a/code/modules/recycling/recycler.dm
+++ b/code/modules/recycling/recycler.dm
@@ -9,7 +9,8 @@
//Pointing west because that's the only sprite we got
dir = NORTH
-/obj/machinery/recycler/update_icon()
+/obj/machinery/recycler/update_icon_state()
+ . = ..()
icon_state = "grinder-o[(machine_stat & (BROKEN|NOPOWER)) ? "0":"1"]"
/obj/machinery/recycler/Bumped(atom/movable/AM)
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 88e1c34f49bc4..09c839a636791 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -24,8 +24,8 @@ GLOBAL_LIST_EMPTY(tagger_locations)
qdel(src)
return
-/obj/structure/bigDelivery/update_icon()
- overlays = new()
+/obj/structure/bigDelivery/update_overlays()
+ . = ..()
if(nameset || examtext)
var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_label")
if(icon_state == "deliverycloset")
@@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(tagger_locations)
label_x = rand(-8, 6)
I.pixel_x = label_x
I.pixel_y = -3
- overlays += I
+ . += I
if(src.sortTag)
var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_tag")
if(icon_state == "deliverycloset")
@@ -51,7 +51,7 @@ GLOBAL_LIST_EMPTY(tagger_locations)
tag_x = rand(-8, 6)
I.pixel_x = tag_x
I.pixel_y = -3
- overlays += I
+ . += I
/obj/structure/bigDelivery/examine(mob/user)
..()
@@ -62,11 +62,13 @@ GLOBAL_LIST_EMPTY(tagger_locations)
to_chat(user, span_notice("It has a note attached which reads, \"[examtext]\""))
return
-/obj/structure/bigDelivery/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
- attack_hand(X)
+/obj/structure/bigDelivery/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ attack_hand(xeno_attacker)
/obj/structure/bigDelivery/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/destTagger))
var/obj/item/destTagger/O = I
@@ -139,13 +141,13 @@ GLOBAL_LIST_EMPTY(tagger_locations)
qdel(src)
return
-/obj/item/smallDelivery/update_icon()
- overlays = new()
+/obj/item/smallDelivery/update_overlays()
+ . = ..()
if((nameset || examtext) && icon_state != "deliverycrate1")
var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_label")
if(icon_state == "deliverycrate5")
I.pixel_y = -1
- overlays += I
+ . += I
if(src.sortTag)
var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_tag")
switch(icon_state)
@@ -162,7 +164,7 @@ GLOBAL_LIST_EMPTY(tagger_locations)
I.pixel_y = 3
if("deliverycrate5")
I.pixel_y = -3
- overlays += I
+ . += I
/obj/item/smallDelivery/examine(mob/user)
..()
@@ -174,6 +176,8 @@ GLOBAL_LIST_EMPTY(tagger_locations)
/obj/item/smallDelivery/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/destTagger))
var/obj/item/destTagger/O = I
@@ -329,8 +333,8 @@ GLOBAL_LIST_EMPTY(tagger_locations)
slot_r_hand_str = 'icons/mob/inhands/equipment/engineering_right.dmi',
)
item_state = "electronic"
- flags_atom = CONDUCT
- flags_equip_slot = ITEM_SLOT_BELT
+ atom_flags = CONDUCT
+ equip_slot_flags = ITEM_SLOT_BELT
/obj/item/destTagger/proc/openwindow(mob/user as mob)
var/dat
@@ -422,6 +426,8 @@ GLOBAL_LIST_EMPTY(tagger_locations)
/obj/machinery/disposal/deliveryChute/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(isscrewdriver(I))
c_mode = !c_mode
@@ -442,7 +448,7 @@ GLOBAL_LIST_EMPTY(tagger_locations)
playsound(loc, 'sound/items/welder2.ogg', 25, 1)
to_chat(user, "You start slicing the floorweld off the delivery chute.")
- if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, /obj/item/tool/weldingtool/proc/isOn)))
+ if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD, extra_checks = CALLBACK(W, TYPE_PROC_REF(/obj/item/tool/weldingtool, isOn))))
return
to_chat(user, "You sliced the floorweld off the delivery chute.")
diff --git a/code/modules/reqs/supply.dm b/code/modules/reqs/supply.dm
index 943813c5b5493..dff2cae509da4 100644
--- a/code/modules/reqs/supply.dm
+++ b/code/modules/reqs/supply.dm
@@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
icon = 'icons/Marine/marine-navigation.dmi'
icon_state = "req_tablet_off"
req_access = list(ACCESS_MARINE_CARGO)
- flags_equip_slot = ITEM_SLOT_POCKET
+ equip_slot_flags = ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
var/datum/supply_ui/SU
///Id of the shuttle controlled
@@ -608,19 +608,14 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
item_state = "radiopack"
///Var for the window pop-up
var/datum/supply_ui/requests/supply_interface
- /// Reference to the datum used by the supply drop console
- var/datum/supply_beacon/beacon_datum
-/obj/item/storage/backpack/marine/radiopack/Destroy()
- if(beacon_datum)
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
- return ..()
+/obj/item/storage/backpack/marine/radiopack/Initialize(mapload, ...)
+ . = ..()
+ AddComponent(/datum/component/beacon)
/obj/item/storage/backpack/marine/radiopack/examine(mob/user)
. = ..()
. += span_notice("Right-Click with empty hand to open requisitions interface.")
- . += span_notice("Activate in hand to create a supply beacon signal.")
/obj/item/storage/backpack/marine/radiopack/attack_hand_alternate(mob/living/user)
if(!allowed(user))
@@ -628,22 +623,3 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
if(!supply_interface)
supply_interface = new(src)
return supply_interface.interact(user)
-
-/obj/item/storage/backpack/marine/radiopack/attack_self(mob/living/user)
- if(beacon_datum)
- UnregisterSignal(beacon_datum, COMSIG_QDELETING)
- QDEL_NULL(beacon_datum)
- user.show_message(span_warning("The [src] beeps and states, \"Your last position is no longer accessible by the supply console"), EMOTE_AUDIBLE, span_notice("The [src] vibrates but you can not hear it!"))
- return
- if(!is_ground_level(user.z))
- to_chat(user, span_warning("You have to be on the planet to use this or it won't transmit."))
- return FALSE
- var/turf/location = get_turf(src)
- beacon_datum = new /datum/supply_beacon(user.name, user.loc, user.faction, 4 MINUTES)
- RegisterSignal(beacon_datum, COMSIG_QDELETING, PROC_REF(clean_beacon_datum))
- user.show_message(span_notice("The [src] beeps and states, \"Your current coordinates were registered by the supply console. LONGITUDE [location.x]. LATITUDE [location.y]. Area ID: [get_area(src)]\""), EMOTE_AUDIBLE, span_notice("The [src] vibrates but you can not hear it!"))
-
-/// Signal handler to nullify beacon datum
-/obj/item/storage/backpack/marine/radiopack/proc/clean_beacon_datum()
- SIGNAL_HANDLER
- beacon_datum = null
diff --git a/code/modules/reqs/supplypacks.dm b/code/modules/reqs/supplypacks.dm
index c52b9d132f74b..2b86d02196bd0 100644
--- a/code/modules/reqs/supplypacks.dm
+++ b/code/modules/reqs/supplypacks.dm
@@ -39,7 +39,7 @@ OPERATIONS
/datum/supply_packs/operations/beacons_supply
name = "Supply beacon"
- contains = list(/obj/item/beacon/supply_beacon)
+ contains = list(/obj/item/supply_beacon)
cost = 100
/datum/supply_packs/operations/fulton_extraction_pack
@@ -156,6 +156,11 @@ OPERATIONS
containertype = null
cost = 200
+/datum/supply_packs/operations/supply_tablet
+ name = "Supply Tablet"
+ contains = list(/obj/item/supplytablet)
+ cost = 50
+
/*******************************************************************************
WEAPONS
*******************************************************************************/
@@ -184,6 +189,26 @@ WEAPONS
contains = list(/obj/item/ammo_magazine/minisentry)
cost = 100
+/datum/supply_packs/weapons/sentry_shotgun
+ name = "SHT-573 Shotgun Sentry"
+ contains = list(/obj/item/storage/box/crate/sentry_shotgun)
+ cost = 400
+
+/datum/supply_packs/weapons/sentry_shotgun_ammo
+ name = "SHT-573 shotgun sentry ammunition"
+ contains = list(/obj/item/ammo_magazine/sentry/shotgun)
+ cost = 100
+
+/datum/supply_packs/weapons/sentry_sniper
+ name = "SST-574 Sniper Sentry"
+ contains = list(/obj/item/storage/box/crate/sentry_sniper)
+ cost = 600
+
+/datum/supply_packs/weapons/sentry_sniper_ammo
+ name = "SST-571 sniper sentry ammunition"
+ contains = list(/obj/item/ammo_magazine/sentry/sniper)
+ cost = 100
+
/datum/supply_packs/weapons/buildasentry
name = "Build-A-Sentry Attachment System"
contains = list(
@@ -192,14 +217,14 @@ WEAPONS
cost = 250
-/datum/supply_packs/weapons/m56d_emplacement
+/datum/supply_packs/weapons/hsg_102_emplacement
name = "HSG-102 Mounted Heavy Smartgun"
- contains = list(/obj/item/storage/box/tl102)
+ contains = list(/obj/item/storage/box/hsg_102)
cost = 600
-/datum/supply_packs/weapons/m56d
+/datum/supply_packs/weapons/hsg_102
name = "HSG-102 mounted heavy smartgun ammo"
- contains = list(/obj/item/ammo_magazine/tl102)
+ contains = list(/obj/item/ammo_magazine/hsg_102)
cost = 30
/datum/supply_packs/weapons/minigun_emplacement
@@ -315,17 +340,17 @@ WEAPONS
/datum/supply_packs/weapons/flak_gun
name = "FK-88 Flak Gun"
contains = list(/obj/item/weapon/gun/heavy_isg)
- cost = 1200
+ cost = 1000
/datum/supply_packs/weapons/flak_he
- name = "FK-88 HE Shell"
+ name = "FK-88 Flak HE Shell"
contains = list(/obj/item/ammo_magazine/heavy_isg/he)
- cost = 100
+ cost = 50
/datum/supply_packs/weapons/flak_sabot
- name = "FK-88 APFDS Shell"
+ name = "FK-88 Flak APFDS Shell"
contains = list(/obj/item/ammo_magazine/heavy_isg/sabot)
- cost = 120
+ cost = 50
/datum/supply_packs/weapons/heayvlaser_emplacement
name = "Mounted Heavy Laser"
@@ -343,6 +368,30 @@ WEAPONS
contains = list(/obj/item/weapon/gun/energy/lasgun/lasrifle/tesla)
cost = 600
+/datum/supply_packs/weapons/plasma_cells
+ name = "WML plasma energy cell (x3)"
+ contains = list(
+ /obj/item/cell/lasgun/plasma,
+ /obj/item/cell/lasgun/plasma,
+ /obj/item/cell/lasgun/plasma,
+ )
+ cost = 100
+
+/datum/supply_packs/weapons/plasma_smg
+ name = "PL-51 Plasma SMG"
+ contains = list(/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/smg)
+ cost = 400
+
+/datum/supply_packs/weapons/plasma_rifle
+ name = "PL-38 Plasma Rifle"
+ contains = list(/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/rifle)
+ cost = 350
+
+/datum/supply_packs/weapons/plasma_cannon
+ name = "PL-96 Plasma Cannon"
+ contains = list(/obj/item/weapon/gun/energy/lasgun/lasrifle/plasma/cannon)
+ cost = 400
+
/datum/supply_packs/weapons/tx54
name = "GL-54 airburst grenade launcher"
contains = list(/obj/item/weapon/gun/rifle/tx54)
@@ -373,12 +422,6 @@ WEAPONS
contains = list(/obj/item/ammo_magazine/rifle/tx54/smoke/tangle)
cost = 48
-/datum/supply_packs/weapons/tx54_he
- name = "GL-54 HE grenade magazine"
- contains = list(/obj/item/ammo_magazine/rifle/tx54/he)
- cost = 50
- available_against_xeno_only = TRUE
-
/datum/supply_packs/weapons/tx55
name = "AR-55 OICW Rifle"
contains = list(/obj/item/weapon/gun/rifle/tx55)
@@ -584,13 +627,13 @@ WEAPONS
/datum/supply_packs/weapons/antimaterial_incend_ammo
name = "SR-26 AMR incendiary magazine"
contains = list(/obj/item/ammo_magazine/sniper/incendiary)
- cost = 50
+ cost = 30
available_against_xeno_only = TRUE
/datum/supply_packs/weapons/antimaterial_flak_ammo
name = "SR-26 AMR flak magazine"
contains = list(/obj/item/ammo_magazine/sniper/flak)
- cost = 40
+ cost = 30
available_against_xeno_only = TRUE
/datum/supply_packs/weapons/specminigun
@@ -643,6 +686,11 @@ WEAPONS
contains = list(/obj/item/ammo_magazine/packet/smart_minigun)
cost = 50
+/datum/supply_packs/weapons/smart_minigun_powerpack
+ name = "SG-85 powerpack"
+ contains = list(/obj/item/ammo_magazine/minigun_powerpack/smartgun)
+ cost = 150
+
/datum/supply_packs/weapons/smarttarget_rifle
name = "SG-62 Smart Target Rifle"
contains = list(/obj/item/weapon/gun/rifle/standard_smarttargetrifle)
@@ -653,6 +701,11 @@ WEAPONS
contains = list(/obj/item/ammo_magazine/rifle/standard_smarttargetrifle)
cost = 35
+/datum/supply_packs/weapons/smarttarget_rifle_ammo_bin
+ name = "SG-62 smart target rifle ammo bin"
+ contains = list(/obj/item/ammo_magazine/packet/smart_targetrifle)
+ cost = 50
+
/datum/supply_packs/weapons/spotting_rifle_ammo
name = "SG-153 spotting rifle ammo"
contains = list(/obj/item/ammo_magazine/rifle/standard_spottingrifle)
@@ -782,6 +835,21 @@ WEAPONS
contains = list(/obj/item/ammo_magazine/pistol/standard_pistol/smart_pistol)
cost = 10
+/datum/supply_packs/weapons/ltb_shells
+ name = "LTB tank shell"
+ contains = list(/obj/item/ammo_magazine/tank/ltb_cannon)
+ cost = 10
+
+/datum/supply_packs/weapons/ltaap_rounds
+ name = "LTAAP tank magazine"
+ contains = list(/obj/item/ammo_magazine/tank/ltaap_chaingun)
+ cost = 10
+
+/datum/supply_packs/weapons/cupola_rounds
+ name = "Cupola tank magazine"
+ contains = list(/obj/item/ammo_magazine/tank/secondary_cupola)
+ cost = 10
+
/*******************************************************************************
EXPLOSIVES
*******************************************************************************/
@@ -802,7 +870,7 @@ EXPLOSIVES
/datum/supply_packs/explosives/explosives_razor
name = "Razorburn grenade box crate"
- notes = "Contains 15 razor burns"
+ notes = "Contains 25 razor burns"
contains = list(/obj/item/storage/box/visual/grenade/razorburn)
cost = 500
@@ -810,31 +878,43 @@ EXPLOSIVES
name = "M40 adhesive charge grenade box crate"
notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/sticky)
- cost = 310
+ cost = 300
/datum/supply_packs/explosives/explosives_smokebomb
name = "M40 HSDP smokebomb grenade box crate"
notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/smokebomb)
- cost = 310
+ cost = 300
/datum/supply_packs/explosives/explosives_hedp
name = "M40 HEDP high explosive grenade box crate"
notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/frag)
- cost = 310
+ cost = 300
/datum/supply_packs/explosives/explosives_cloaker
name = "M45 Cloaker grenade box crate"
notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/cloaker)
- cost = 310
+ cost = 300
+
+/datum/supply_packs/explosives/explosives_antigas
+ name = "M40-AG Anti-Gas grenade box crate"
+ notes = "Cotains 25 grenades"
+ contains = list(/obj/item/storage/box/visual/grenade/antigas)
+ cost = 600
/datum/supply_packs/explosives/explosives_cloak
name = "M40-2 SCDP grenade box crate"
- notes = "contains 25 grenades"
+ notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/cloak)
- cost = 310
+ cost = 300
+
+/datum/supply_packs/explosives/explosives_lasburster
+ name = "M80 lasburster grenade box crate"
+ notes = "Contains 25 grenades"
+ contains = list(/obj/item/storage/box/visual/grenade/lasburster)
+ cost = 300
/datum/supply_packs/explosives/explosives_hidp
name = "M40 HIDP incendiary explosive grenade box crate"
@@ -844,7 +924,7 @@ EXPLOSIVES
/datum/supply_packs/explosives/explosives_m15
name = "M15 fragmentation grenade box crate"
- notes = "Contains 15 grenades"
+ notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/M15)
cost = 350
@@ -852,20 +932,19 @@ EXPLOSIVES
name = "M45 Trailblazer grenade box crate"
notes = "Contains 25 grenades"
contains = list(/obj/item/storage/box/visual/grenade/trailblazer)
- cost = 350
+ cost = 500
/datum/supply_packs/explosives/explosives_hsdp
name = "M40 HSDP white phosphorous grenade box crate"
notes = "Contains 15 grenades"
contains = list(/obj/item/storage/box/visual/grenade/phosphorus)
- cost = 700
+ cost = 1000
-/datum/supply_packs/explosives/explosives_plasmadrain
- name = "M40-T gas grenade box crate"
+/datum/supply_packs/explosives/explosives_hefa
+ name = "M25 HEFA grenade box crate"
notes = "Contains 25 grenades"
- contains = list(/obj/item/storage/box/visual/grenade/drain)
- cost = 700
- available_against_xeno_only = TRUE
+ contains = list(/obj/item/storage/box/visual/grenade/hefa)
+ cost = 500
/datum/supply_packs/explosives/plastique
name = "C4 plastic explosive"
@@ -927,7 +1006,17 @@ EXPLOSIVES
/datum/supply_packs/explosives/mlrs_rockets_gas
name = "TA-40L X-50 MLRS Rocket Pack (x16)"
- contains = list(/obj/item/storage/box/mlrs_rockets_gas)
+ contains = list(/obj/item/storage/box/mlrs_rockets/gas)
+ cost = 60
+
+/datum/supply_packs/explosives/mlrs_rockets_cloak
+ name = "TA-40L S-2 MLRS Cloak Rocket Pack (x16)"
+ contains = list(/obj/item/storage/box/mlrs_rockets/cloak)
+ cost = 50
+
+/datum/supply_packs/explosives/mlrs_rockets_incendiary
+ name = "TA-40L MLRS Incendiary Rocket Pack (x16)"
+ contains = list(/obj/item/storage/box/mlrs_rockets/incendiary)
cost = 60
/* RU TGMC EDIT BEGIN
@@ -985,11 +1074,6 @@ ARMOR
cost = 120
available_against_xeno_only = TRUE
-/datum/supply_packs/armor/marine_shield
- name = "TL-172 Defensive Shield"
- contains = list(/obj/item/weapon/shield/riot/marine)
- cost = 100
-
/datum/supply_packs/armor/marine_shield/deployable
name = "TL-182 Deployable Shield"
contains = list(/obj/item/weapon/shield/riot/marine/deployable)
@@ -1014,7 +1098,7 @@ ARMOR
/datum/supply_packs/armor/scout_cloak
name = "Scout Cloak"
- contains = list(/obj/item/storage/backpack/marine/satchel/scout_cloak/scout)
+ contains = list(/obj/item/storage/backpack/marine/satchel/scout_cloak)
cost = 500
/datum/supply_packs/armor/sniper_cloak
@@ -1350,7 +1434,7 @@ ENGINEERING
/datum/supply_packs/engineering/glass50
name = "50 glass sheets"
- contains = list(/obj/item/stack/sheet/glass/large_stack)
+ contains = list(/obj/item/stack/sheet/glass/glass/large_stack)
cost = 100
/datum/supply_packs/engineering/wood50
@@ -1979,7 +2063,7 @@ VEHICLES
/datum/supply_packs/vehicles/hsg_ammo
name = "Mounted HSG ammo"
- contains = list(/obj/item/ammo_magazine/tl102/hsg_nest)
+ contains = list(/obj/item/ammo_magazine/hsg_102/hsg_nest)
cost = 100
containertype = /obj/structure/closet/crate/ammo
@@ -2048,15 +2132,55 @@ FACTORY
contains = list(/obj/machinery/unboxer)
cost = 50
+/datum/supply_packs/factory/bignaderefill
+ name = "Rounded M15 plates refill"
+ contains = list(/obj/item/factory_refill/bignade_refill)
+ cost = 550
+
+/datum/supply_packs/factory/incennaderefill
+ name = "Incendiary grenade refill"
+ contains = list(/obj/item/factory_refill/incennade_refill)
+ cost = 550
+
+/datum/supply_packs/factory/stickynaderefill
+ name = "Adhesive grenade refill"
+ contains = list(/obj/item/factory_refill/stickynade_refill)
+ cost = 450
+
/datum/supply_packs/factory/phosphosrefill
name = "Phosphorus-resistant plates refill"
contains = list(/obj/item/factory_refill/phosnade_refill)
+ cost = 1050
+
+/datum/supply_packs/factory/cloaknade_refill
+ name = "Cloak grenade refill"
+ contains = list(/obj/item/factory_refill/cloaknade_refill)
+ cost = 450
+
+/datum/supply_packs/factory/trailblazerrefill
+ name = "Trailblazer grenade refill"
+ contains = list(/obj/item/factory_refill/trailblazer_refill)
+ cost = 750
+
+/datum/supply_packs/factory/lasenaderefill
+ name = "Laserburster grenade refill"
+ contains = list(/obj/item/factory_refill/lasenade_refill)
+ cost = 450
+
+/datum/supply_packs/factory/hefanaderefill
+ name = "HEFA fragmentation grenade refill"
+ contains = list(/obj/item/factory_refill/hefanade_refill)
+ cost = 750
+
+/datum/supply_packs/factory/antigasrefill
+ name = "Anti-Gas grenade refill"
+ contains = list(/obj/item/factory_refill/antigas_refill)
cost = 900
-/datum/supply_packs/factory/bignaderefill
- name = "Rounded M15 plates refill"
- contains = list(/obj/item/factory_refill/bignade_refill)
- cost = 500
+/datum/supply_packs/factory/razornade_refill
+ name = "Razornade assembly refill"
+ contains = list(/obj/item/factory_refill/razornade_refill)
+ cost = 750
/datum/supply_packs/factory/sadar_refill_he
name = "SADAR HE missile assembly refill"
@@ -2123,10 +2247,9 @@ FACTORY
contains = list(/obj/item/factory_refill/smartgunner_machinegun_magazine_refill)
cost = 250
-
/datum/supply_packs/factory/smartgun_targetrifle_refill
- name = "SG-62 ammo drum parts refill"
- contains = list(/datum/supply_packs/factory/smartgun_magazine_refill)
+ name = "SG-62 ammo magazine parts refill"
+ contains = list(/obj/item/factory_refill/smartgunner_targetrifle_magazine_refill)
cost = 250
/datum/supply_packs/factory/autosniper_magazine_refill
@@ -2154,28 +2277,38 @@ FACTORY
contains = list(/obj/item/factory_refill/railgun_magazine_refill)
cost = 200
+/datum/supply_packs/factory/railgun_hvap_magazine_refill
+ name = "Railgun HVAP magazine assembly refill"
+ contains = list(/obj/item/factory_refill/railgun_hvap_magazine_refill)
+ cost = 200
+
+/datum/supply_packs/factory/railgun_smart_magazine_refill
+ name = "Railgun magazine assembly refill"
+ contains = list(/obj/item/factory_refill/railgun_smart_magazine_refill)
+ cost = 200
+
/datum/supply_packs/factory/minigun_powerpack_refill
name = "Minigun powerpack assembly refill"
contains = list(/obj/item/factory_refill/minigun_powerpack_refill)
cost = 250
-/datum/supply_packs/factory/razornade_refill
- name = "Razornade assembly refill"
- contains = list(/obj/item/factory_refill/razornade_refill)
- cost = 500
+/datum/supply_packs/factory/flak_sniper_refill
+ name = "SR-127 flak magazine assembly refill"
+ contains = list(/obj/item/factory_refill/sniper_flak_magazine_refill)
+ cost = 600
/datum/supply_packs/factory/amr_magazine_refill
- name = "T-26 AMR magazine assembly refill"
+ name = "T-26 AMR standard magazine assembly refill"
contains = list(/obj/item/factory_refill/amr_magazine_refill)
cost = 400
/datum/supply_packs/factory/amr_magazine_incend_refill
- name = "T-26 AMR magazine assembly refill"
+ name = "T-26 AMR incendiary magazine assembly refill"
contains = list(/obj/item/factory_refill/amr_magazine_incend_refill)
cost = 400
/datum/supply_packs/factory/amr_magazine_flak_refill
- name = "T-26 AMR magazine assembly refill"
+ name = "T-26 AMR flak magazine assembly refill"
contains = list(/obj/item/factory_refill/amr_magazine_flak_refill)
cost = 400
@@ -2204,10 +2337,6 @@ FACTORY
contains = list(/obj/item/factory_refill/swat_mask_refill)
cost = 500
-/datum/supply_packs/factory/med_advpack
- name = "Advanced medical pack assembly refill"
- contains = list(/obj/item/factory_refill/med_advpack_refill)
- cost = 500
/* RU TGMC EDIT
/datum/supply_packs/factory/module_valk_refill
name = "Valkyrie Automedical Armor System assembly refill"
@@ -2234,6 +2363,21 @@ FACTORY
contains = list(/obj/item/factory_refill/module_surt_refill)
cost = 600
RU TGMC EDIT*/
+/datum/supply_packs/factory/plastique_refill
+ name = "C4 assembly refill"
+ contains = list(/obj/item/factory_refill/plastique_refill)
+ cost = 150
+
+/datum/supply_packs/factory/plastique_incendiary_refill
+ name = "EX-62 Genghis incendiary assembly refill"
+ contains = list(/obj/item/factory_refill/plastique_incendiary_refill)
+ cost = 500
+
+/datum/supply_packs/factory/detpack_refill
+ name = "Detpack assembly refill"
+ contains = list(/obj/item/factory_refill/detpack_refill)
+ cost = 250
+
/datum/supply_packs/factory/mortar_shell_he_refill
name = "Mortar High Explosive shell assembly refill"
contains = list(/obj/item/factory_refill/mortar_shell_he_refill)
@@ -2264,6 +2408,96 @@ RU TGMC EDIT*/
contains = list(/obj/item/factory_refill/mlrs_rocket_refill)
cost = 240
+/datum/supply_packs/factory/mlrs_rocket_refill_cloak
+ name = "MLRS 'S-2' Cloak rocket assembly refill"
+ contains = list(/obj/item/factory_refill/mlrs_rocket_refill_cloak)
+ cost = 240
+
+/datum/supply_packs/factory/mlrs_rocket_refill_gas
+ name = "MLRS 'X-50' gas rocket assembly refill"
+ contains = list(/obj/item/factory_refill/mlrs_rocket_refill_gas)
+ cost = 240
+
+/datum/supply_packs/factory/mlrs_rocket_refill_incendiary
+ name = "MLRS Incendiary rocket assembly refill"
+ contains = list(/obj/item/factory_refill/mlrs_rocket_refill_incendiary)
+ cost = 240
+
+/datum/supply_packs/factory/agls_he_refill
+ name = "AGLS HE magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_he_refill)
+ cost = 300
+
+/datum/supply_packs/factory/agls_frag_refill
+ name = "AGLS FRAG magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_frag_refill)
+ cost = 300
+
+/datum/supply_packs/factory/agls_incendiary_refill
+ name = "AGLS Incendiary magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_incendiary_refill)
+ cost = 300
+
+/datum/supply_packs/factory/agls_flare_refill
+ name = "AGLS Flare magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_flare_refill)
+ cost = 200
+
+/datum/supply_packs/factory/agls_cloak_refill
+ name = "AGLS Cloak magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_cloak_refill)
+ cost = 200
+
+/datum/supply_packs/factory/agls_tanglefoot_refill
+ name = "AGLS Tanglefoot magazine assembly refill"
+ contains = list(/obj/item/factory_refill/agls_tanglefoot_refill)
+ cost = 400
+
+/datum/supply_packs/factory/atgun_aphe_refill
+ name = "AT-36 AP-HE shell assembly refill"
+ contains = list(/obj/item/factory_refill/atgun_aphe_refill)
+ cost = 100
+
+/datum/supply_packs/factory/atgun_apcr_refill
+ name = "AT-36 APCR shell assembly refill"
+ contains = list(/obj/item/factory_refill/atgun_apcr_refill)
+ cost = 100
+
+/datum/supply_packs/factory/atgun_he_refill
+ name = "AT-36 HE shell assembly refill"
+ contains = list(/obj/item/factory_refill/atgun_he_refill)
+ cost = 100
+
+/datum/supply_packs/factory/atgun_beehive_refill
+ name = "AT-36 Beehive shell assembly refill"
+ contains = list(/obj/item/factory_refill/atgun_beehive_refill)
+ cost = 100
+
+/datum/supply_packs/factory/atgun_incend_refill
+ name = "AT-36 Napalm shell assembly refill"
+ contains = list(/obj/item/factory_refill/atgun_incend_refill)
+ cost = 100
+
+/datum/supply_packs/factory/heavy_isg_he_refill
+ name = "FK-88 Flak HE shell assembly refill"
+ contains = list(/obj/item/factory_refill/heavy_isg_he_refill)
+ cost = 300
+
+/datum/supply_packs/factory/heavy_isg_sabot_refill
+ name = "FK-88 Flak APFDS shell assembly refill"
+ contains = list(/obj/item/factory_refill/heavy_isg_sabot_refill)
+ cost = 400
+
+/datum/supply_packs/factory/ac_hv_refill
+ name = "ATR-22 High Velocity magazine assembly refill"
+ contains = list(/obj/item/factory_refill/ac_hv_refill)
+ cost = 300
+
+/datum/supply_packs/factory/ac_flak_refill
+ name = "ATR-22 Flak magazine assembly refill"
+ contains = list(/obj/item/factory_refill/ac_flak_refill)
+ cost = 300
+
/datum/supply_packs/factory/thermobaric_wp_refill
name = "RL-57 Thermobaric WP rocket array assembly refill"
contains = list(/obj/item/factory_refill/thermobaric_wp_refill)
@@ -2273,3 +2507,13 @@ RU TGMC EDIT*/
name = "Zeus orbital drop pod assembly refill"
contains = list(/obj/item/factory_refill/drop_pod_refill)
cost = 250
+
+/datum/supply_packs/factory/deployable_floodlight_refill
+ name = "Deployable floodlight assembly refill"
+ contains = list(/obj/item/factory_refill/deployable_floodlight_refill)
+ cost = 150
+
+/datum/supply_packs/factory/deployable_camera_refill
+ name = "Deplyable security camera refill"
+ contains = list(/obj/item/factory_refill/deployable_camera_refill)
+ cost = 100
diff --git a/code/modules/requisitions/supply_export.dm b/code/modules/requisitions/supply_export.dm
index 420ac4a73869e..2734dd995779c 100644
--- a/code/modules/requisitions/supply_export.dm
+++ b/code/modules/requisitions/supply_export.dm
@@ -1,56 +1,61 @@
///Function that sells whatever object this is to the faction_selling; returns a /datum/export_report if successful
/atom/movable/proc/supply_export(faction_selling)
- var/points = get_export_value()
+ var/list/points = get_export_value()
if(!points)
return FALSE
- SSpoints.supply_points[faction_selling] += points
- SSpoints.dropship_points += points * 0.1
- return new /datum/export_report(points, name, faction_selling)
+ SSpoints.supply_points[faction_selling] += points[1]
+ SSpoints.dropship_points += points[2]
+ return new /datum/export_report(points[1], name, faction_selling)
/mob/living/carbon/human/supply_export(faction_selling)
if(!can_sell_human_body(src, faction_selling))
return new /datum/export_report(0, name, faction_selling)
return ..()
-///Getter to obtain the req point value of whatever this is
+/**
+ * Getter proc for the point value of this object
+ *
+ * Returns:
+ * * A list where the first value is the number of req points and the second number is the number of cas points.
+ */
/atom/movable/proc/get_export_value()
- return 0
+ . = list(0,0)
/mob/living/carbon/human/get_export_value()
switch(job.job_category)
if(JOB_CAT_ENGINEERING, JOB_CAT_MEDICAL, JOB_CAT_REQUISITIONS)
- . = 200
+ . = list(200, 20)
if(JOB_CAT_MARINE)
- . = 300
+ . = list(300, 30)
if(JOB_CAT_SILICON)
- . = 800
+ . = list(800, 80)
if(JOB_CAT_COMMAND)
- . = 1000
+ . = list(1000, 100)
return
/mob/living/carbon/xenomorph/get_export_value()
switch(tier)
if(XENO_TIER_MINION)
- . = 50
+ . = list(50, 5)
if(XENO_TIER_ZERO)
- . = 70
+ . = list(70, 7)
if(XENO_TIER_ONE)
- . = 150
+ . = list(150, 15)
if(XENO_TIER_TWO)
- . = 300
+ . = list(350, 30)
if(XENO_TIER_THREE)
- . = 500
+ . = list(600, 50)
if(XENO_TIER_FOUR)
- . = 1000
+ . = list(1100, 100)
return
//I hate it but it's how it was so I'm not touching it further than this
/mob/living/carbon/xenomorph/shrike/get_export_value()
- return 500
+ return list(600, 50)
/obj/item/reagent_containers/food/snacks/req_pizza/get_export_value()
- return 10
+ return list(10, 0)
//RUTGMC EDIT REMOVAL BEGIN - ALLY_SALE - (Moved to modular_RUtgmc\code\modules\requisitions\supply_export.dm)
/*
diff --git a/code/modules/screen_alert/command_alert.dm b/code/modules/screen_alert/command_alert.dm
index 0324201415142..089ccec2f1823 100644
--- a/code/modules/screen_alert/command_alert.dm
+++ b/code/modules/screen_alert/command_alert.dm
@@ -21,7 +21,7 @@
///What skill is needed to have this action
var/skill_name = SKILL_LEADERSHIP
///What minimum level in that skill is needed to have that action
- var/skill_min = SKILL_LEAD_EXPERT
+ var/skill_min = SKILL_LEAD_TRAINED
/datum/action/innate/message_squad/should_show()
return owner.skills.getRating(skill_name) >= skill_min
@@ -49,16 +49,38 @@
return
if(!can_use_action())
return
- human_owner.playsound_local(owner, "sound/effects/CIC_order.ogg", 10, 1)
+ var/sound/S = sound('sound/misc/notice2.ogg')
+ S.channel = CHANNEL_ANNOUNCEMENTS
TIMER_COOLDOWN_START(owner, COOLDOWN_HUD_ORDER, ORDER_COOLDOWN)
log_game("[key_name(human_owner)] has broadcasted the hud message [text] at [AREACOORD(human_owner)]")
- deadchat_broadcast(" has sent the command order \"[text]\"", human_owner, human_owner)
+ var/override_color // for squad colors
+ var/list/alert_receivers = (GLOB.alive_human_list + GLOB.ai_list + GLOB.observer_list) // for full faction alerts, do this so that faction's AI and ghosts can hear aswell
if(human_owner.assigned_squad)
- for(var/mob/living/carbon/human/marine AS in human_owner.assigned_squad.marines_list)
- marine.play_screen_text("SQUAD ORDERS UPDATED: " + text, /atom/movable/screen/text/screen_text/command_order)
- to_chat(marine, "
")
+ for(var/mob/faction_receiver in alert_receivers)
+ if(faction_receiver.faction == human_owner.faction || isdead(faction_receiver))
+ faction_receiver.play_screen_text("COMMAND ANNOUNCEMENT: " + text, /atom/movable/screen/text/screen_text/command_order)
+ to_chat(faction_receiver, assemble_alert(
+ title = "Command Announcement",
+ subtitle = "Sent by [human_owner.real_name]",
+ message = text
+ ))
+ SEND_SOUND(faction_receiver, S)
diff --git a/code/modules/screen_alert/misc_alert.dm b/code/modules/screen_alert/misc_alert.dm
index 9f206bfbecd3d..cbaebfd87f8c5 100644
--- a/code/modules/screen_alert/misc_alert.dm
+++ b/code/modules/screen_alert/misc_alert.dm
@@ -17,7 +17,7 @@
///x offset of image
var/image_to_play_offset_x = 0
-/atom/movable/screen/text/screen_text/picture/Initialize(mapload)
+/atom/movable/screen/text/screen_text/picture/Initialize(mapload, datum/hud/hud_owner)
. = ..()
overlays += image('icons/UI_Icons/screen_alert_images.dmi', icon_state = image_to_play, pixel_y = image_to_play_offset_y, pixel_x = image_to_play_offset_x)
@@ -43,11 +43,63 @@
maptext_y = 0
letters_per_update = 2
+/atom/movable/screen/text/screen_text/picture/potrait/tgmc_req
+ image_to_play = "req_tgmc"
+
+/atom/movable/screen/text/screen_text/picture/potrait/pod_officer
+ image_to_play = "pod_officer"
+
+/atom/movable/screen/text/screen_text/picture/potrait/tgmc_mortar
+ image_to_play = "mortar_team"
+
+/atom/movable/screen/text/screen_text/picture/potrait/som_mortar
+ image_to_play = "mortar_team_som"
+
/atom/movable/screen/text/screen_text/picture/potrait/som_over
image_to_play = "overwatch_som"
+/atom/movable/screen/text/screen_text/picture/potrait/som_req
+ image_to_play = "req_som"
+
+/atom/movable/screen/text/screen_text/picture/potrait/som_scientist
+ image_to_play = "scientist_som"
+
/atom/movable/screen/text/screen_text/picture/potrait/unknown
image_to_play = "overwatch_unknown"
/atom/movable/screen/text/screen_text/picture/potrait/pilot
- image_to_play = "po"
+ image_to_play = "cas"
+
+/atom/movable/screen/text/screen_text/picture/potrait/som_pilot
+ image_to_play = "cas_som"
+
+//
+/atom/movable/screen/text/screen_text/picture/potrait/icc_over
+ image_to_play = "overwatch_icc"
+
+/atom/movable/screen/text/screen_text/picture/potrait/militia_reinforcement
+ image_to_play = "reinforcement_clf"
+
+/atom/movable/screen/text/screen_text/picture/potrait/freelancer_reinforcement
+ image_to_play = "reinforcement_fre"
+
+/atom/movable/screen/text/screen_text/picture/potrait/robot_reinforcement
+ image_to_play = "reinforcement_robot"
+
+/atom/movable/screen/text/screen_text/picture/potrait/spec_reinforcement
+ image_to_play = "reinforcement_spec"
+
+/atom/movable/screen/text/screen_text/picture/potrait/pmc_reinforcement
+ image_to_play = "reinforcement_pmc"
+
+/atom/movable/screen/text/screen_text/picture/potrait/icc_reinforcement
+ image_to_play = "reinforcement_icc"
+
+/atom/movable/screen/text/screen_text/picture/potrait/som_reinforcement
+ image_to_play = "reinforcement_som"
+
+/atom/movable/screen/text/screen_text/picture/potrait/tgmc_distress
+ image_to_play = "distress_tgmc"
+
+/atom/movable/screen/text/screen_text/picture/potrait/som_distress
+ image_to_play = "distress_som"
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index 438ef05dab523..b99e6d9bb3590 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -25,6 +25,8 @@
/obj/machinery/keycard_auth/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(machine_stat & (NOPOWER|BROKEN))
to_chat(user, "This device is not powered.")
@@ -42,7 +44,8 @@
event_triggered_by = user
broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices
-/obj/machinery/keycard_auth/update_icon()
+/obj/machinery/keycard_auth/update_icon_state()
+ . = ..()
if(machine_stat &NOPOWER)
icon_state = "auth_off"
diff --git a/code/modules/shuttle/escape_pod.dm b/code/modules/shuttle/escape_pod.dm
index e671e9c2f0d5c..4f4117b37fbdb 100644
--- a/code/modules/shuttle/escape_pod.dm
+++ b/code/modules/shuttle/escape_pod.dm
@@ -210,5 +210,5 @@
/obj/machinery/door/airlock/evacuation/attack_hand(mob/living/user)
return TRUE
-/obj/machinery/door/airlock/evacuation/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
+/obj/machinery/door/airlock/evacuation/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
return FALSE //Probably a better idea that these cannot be forced open.
diff --git a/code/modules/shuttle/marine_dropship.dm b/code/modules/shuttle/marine_dropship.dm
index d143112f64232..a940778d89e1c 100644
--- a/code/modules/shuttle/marine_dropship.dm
+++ b/code/modules/shuttle/marine_dropship.dm
@@ -93,7 +93,7 @@
/obj/docking_port/stationary/marine_dropship/lz1/Initialize(mapload)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/obj/docking_port/stationary/marine_dropship/lz1/prison
name = "LZ1: Main Hangar"
@@ -105,7 +105,7 @@
/obj/docking_port/stationary/marine_dropship/lz2/Initialize(mapload)
. = ..()
var/area/area = get_area(src)
- area.flags_area |= MARINE_BASE
+ area.area_flags |= MARINE_BASE
/obj/docking_port/stationary/marine_dropship/lz2/prison
name = "LZ2: Civ Residence Hangar"
@@ -255,7 +255,7 @@
if(hijack_state != HIJACK_STATE_NORMAL)
return
cycle_timer = addtimer(CALLBACK(src, PROC_REF(go_to_previous_destination)), 20 SECONDS, TIMER_STOPPABLE)
- priority_announce("Dropship taking off in 20 seconds towards [previous.name]", "Dropship Automatic Departure")
+ priority_announce("The Alamo will depart towards [previous.name] in 20 seconds.", "Dropship Automatic Departure", color_override = "grey")
///Send the dropship to its previous dock
/obj/docking_port/mobile/marine_dropship/proc/go_to_previous_destination()
@@ -320,7 +320,7 @@
/obj/docking_port/mobile/marine_dropship/on_prearrival()
. = ..()
if(hijack_state == HIJACK_STATE_CRASHING)
- priority_announce("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT.", "EMERGENCY", sound = 'sound/AI/dropship_emergency.ogg')
+ priority_announce("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT.", "EMERGENCY", sound = 'sound/AI/dropship_emergency.ogg', color_override = "red")
for(var/obj/machinery/landinglight/light AS in GLOB.landing_lights)
if(light.linked_port == destination)
light.turn_on()
@@ -375,7 +375,7 @@
message_admins("[ADMIN_TPMONTY(src)] has summoned the dropship")
log_admin("[key_name(src)] has summoned the dropship")
hive?.xeno_message("[src] has summoned down the metal bird to [port], gather to her now!")
- priority_announce("Unknown interference with dropship control. Shutting down autopilot", "Dropship malfunction")
+ priority_announce("Unknown external interference with dropship control. Shutting down autopilot.", "Critical Dropship Alert", type = ANNOUNCEMENT_PRIORITY, color_override = "red")
#define ALIVE_HUMANS_FOR_CALLDOWN 0.1
@@ -437,7 +437,7 @@
D.silicon_lock_airlocks(TRUE)
to_chat(user, span_warning("We have overriden the shuttle lockdown!"))
playsound(user, "alien_roar", 50)
- priority_announce("Alamo lockdown protocol compromised. Interference preventing remote control", "Dropship Lock Alert")
+ priority_announce("Alamo lockdown protocol compromised. Interference preventing remote control.", "Dropship Lock Alert", type = ANNOUNCEMENT_PRIORITY, color_override = "red")
return FALSE
if(D.mode != SHUTTLE_IDLE && D.mode != SHUTTLE_RECHARGING)
to_chat(user, span_warning("The bird's mind is currently active. We need to wait until it's more vulnerable..."))
@@ -495,46 +495,28 @@
resistance_flags = RESIST_ALL
req_one_access = list(ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LEADER) // TLs can only operate the remote console
possible_destinations = "lz1;lz2;alamo"
+ opacity = FALSE
-/obj/machinery/computer/shuttle/marine_dropship/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- if(!(X.xeno_caste.caste_flags & CASTE_IS_INTELLIGENT))
+/obj/machinery/computer/shuttle/marine_dropship/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
+ var/datum/game_mode/infestation/infestation_mode = SSticker.mode //Minor QOL, any xeno can check the console after a leader hijacks
+ if(!(xeno_attacker.xeno_caste.caste_flags & CASTE_IS_INTELLIGENT) && (infestation_mode.round_stage != INFESTATION_MARINE_CRASHING))
return
#ifndef TESTING
if(SSticker.round_start_time + SHUTTLE_HIJACK_LOCK > world.time)
- to_chat(X, span_xenowarning("It's too early to do this!"))
+ to_chat(xeno_attacker, span_xenowarning("It's too early to do this!"))
return
#endif
- var/obj/docking_port/mobile/marine_dropship/M = SSshuttle.getShuttle(shuttleId)
- var/dat = "Status: [M ? M.getStatusText() : "*Missing*"]
"
- if(M)
- dat += "Launch to [SSmapping.configs[SHIP_MAP].map_name] "
- dat += "Capture the [M] "
- M.unlock_all()
- M.silicon_lock_airlocks(TRUE)
- if(M.hijack_state != HIJACK_STATE_CALLED_DOWN)
- to_chat(X, span_xenowarning("We corrupt the bird's controls, unlocking the doors[(M.mode != SHUTTLE_IGNITING) ? "and preventing it from flying." : ", but we are unable to prevent it from flying as it is already taking off!"]"))
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_DROPSHIP_CONTROLS_CORRUPTED, src)
- if(M.mode != SHUTTLE_IGNITING)
- M.set_hijack_state(HIJACK_STATE_CALLED_DOWN)
- M.do_start_hijack_timer()
-
- var/datum/browser/popup = new(X, "computer", M ? M.name : "shuttle", 300, 200)
- popup.set_content("
[dat]
")
- popup.open()
-
-
-/obj/machinery/computer/shuttle/marine_dropship/can_interact(mob/user)
- . = ..()
-
- if(isxeno(user))
- var/mob/living/carbon/xenomorph/X = user
- if(!(X.xeno_caste.caste_flags & CASTE_IS_INTELLIGENT))
- return FALSE
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttleId)
+ if(shuttle.hijack_state != HIJACK_STATE_CALLED_DOWN && shuttle.hijack_state != HIJACK_STATE_CRASHING) //Process of corrupting the controls
+ to_chat(xeno_attacker, span_xenowarning("We corrupt the bird's controls, unlocking the doors and preventing it from flying."))
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_DROPSHIP_CONTROLS_CORRUPTED, src)
+ shuttle.set_idle()
+ shuttle.set_hijack_state(HIJACK_STATE_CALLED_DOWN)
+ shuttle.do_start_hijack_timer()
+ interact(xeno_attacker) //Open the UI
- else if(!allowed(user))
- return FALSE
-
- return TRUE
+/obj/machinery/computer/shuttle/marine_dropship/ui_state(mob/user)
+ return GLOB.alamo_state
/obj/machinery/computer/shuttle/marine_dropship/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -543,19 +525,31 @@
ui = new(user, src, "MarineDropship", name)
ui.open()
+/obj/machinery/computer/shuttle/marine_dropship/ui_static_data(mob/user)
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttleId)
+ var/list/static_data = list()
+ static_data["current_map"] = SSmapping.configs[SHIP_MAP].map_name
+ static_data["ship_name"] = shuttle
+
+ return static_data
+
/obj/machinery/computer/shuttle/marine_dropship/ui_data(mob/user)
var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttleId)
if(!shuttle)
WARNING("[src] could not find shuttle [shuttleId] from SSshuttle")
return
- . = list()
- .["on_flyby"] = shuttle.mode == SHUTTLE_CALL
- .["dest_select"] = !(shuttle.mode == SHUTTLE_CALL || shuttle.mode == SHUTTLE_IDLE)
- .["hijack_state"] = shuttle.hijack_state != HIJACK_STATE_CALLED_DOWN
- .["ship_status"] = shuttle.getStatusText()
- .["automatic_cycle_on"] = shuttle.automatic_cycle_on
- .["time_between_cycle"] = shuttle.time_between_cycle
+ var/list/data = list()
+ data["is_xeno"] = isxeno(user)
+ data["on_flyby"] = shuttle.mode == SHUTTLE_CALL
+ data["dest_select"] = !(shuttle.mode == SHUTTLE_CALL || shuttle.mode == SHUTTLE_IDLE)
+ data["hijack_state"] = shuttle.hijack_state != HIJACK_STATE_CALLED_DOWN
+ data["ship_status"] = shuttle.getStatusText()
+ data["automatic_cycle_on"] = shuttle.automatic_cycle_on
+ data["time_between_cycle"] = shuttle.time_between_cycle
+
+ var/datum/game_mode/infestation/infestation_mode = SSticker.mode
+ data["shuttle_hijacked"] = (infestation_mode.round_stage == INFESTATION_MARINE_CRASHING) //If we hijacked, our capture button greys out
var/locked = 0
var/reardoor = 0
@@ -564,12 +558,12 @@
if(A.locked && A.density)
reardoor++
if(!reardoor)
- .["rear"] = 0
+ data["rear"] = 0
else if(reardoor==length(shuttle.rear_airlocks))
- .["rear"] = 2
+ data["rear"] = 2
locked++
else
- .["rear"] = 1
+ data["rear"] = 1
var/leftdoor = 0
for(var/i in shuttle.left_airlocks)
@@ -577,12 +571,12 @@
if(A.locked && A.density)
leftdoor++
if(!leftdoor)
- .["left"] = 0
+ data["left"] = 0
else if(leftdoor==length(shuttle.left_airlocks))
- .["left"] = 2
+ data["left"] = 2
locked++
else
- .["left"] = 1
+ data["left"] = 1
var/rightdoor = 0
for(var/i in shuttle.right_airlocks)
@@ -590,19 +584,19 @@
if(A.locked && A.density)
rightdoor++
if(!rightdoor)
- .["right"] = 0
+ data["right"] = 0
else if(rightdoor==length(shuttle.right_airlocks))
- .["right"] = 2
+ data["right"] = 2
locked++
else
- .["right"] = 1
+ data["right"] = 1
if(locked == 3)
- .["lockdown"] = 2
+ data["lockdown"] = 2
else if(!locked)
- .["lockdown"] = 0
+ data["lockdown"] = 0
else
- .["lockdown"] = 1
+ data["lockdown"] = 1
var/list/options = valid_destinations()
var/list/valid_destinations = list()
@@ -612,17 +606,19 @@
if(!shuttle.check_dock(S, silent=TRUE))
continue
valid_destinations += list(list("name" = S.name, "id" = S.id))
- .["destinations"] = valid_destinations
+ data["destinations"] = valid_destinations
-/obj/machinery/computer/shuttle/marine_dropship/ui_act(action, list/params)
+ return data
+
+/obj/machinery/computer/shuttle/marine_dropship/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- var/obj/docking_port/mobile/marine_dropship/M = SSshuttle.getShuttle(shuttleId)
- if(!M)
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttleId)
+ if(!shuttle)
return
- if(M.hijack_state == HIJACK_STATE_CALLED_DOWN)
+ if(shuttle.hijack_state == HIJACK_STATE_CALLED_DOWN && ishuman(usr))
return
switch(action)
@@ -630,115 +626,79 @@
Topic(null, list("move" = params["move"]))
return
if("lockdown")
- M.lockdown_all()
+ shuttle.lockdown_all()
. = TRUE
if("release")
- M.unlock_all()
+ shuttle.unlock_all()
. = TRUE
if("lock")
- M.lockdown_airlocks(params["lock"])
+ shuttle.lockdown_airlocks(params["lock"])
. = TRUE
if("unlock")
- M.unlock_airlocks(params["unlock"])
+ shuttle.unlock_airlocks(params["unlock"])
. = TRUE
if("automation_on")
- M.automatic_cycle_on = params["automation_on"]
- if(!M.automatic_cycle_on)
- deltimer(M.cycle_timer)
+ shuttle.automatic_cycle_on = params["automation_on"]
+ if(!shuttle.automatic_cycle_on)
+ deltimer(shuttle.cycle_timer)
if("cycle_time_change")
- M.time_between_cycle = params["cycle_time_change"]
-
-/* RUTGMC DELETION
-/obj/machinery/computer/shuttle/marine_dropship/Topic(href, href_list)
- var/obj/docking_port/mobile/marine_dropship/M = SSshuttle.getShuttle(shuttleId)
- if(!M)
- return
- if(!isxeno(usr) && M.hijack_state == HIJACK_STATE_CALLED_DOWN)
- to_chat(usr, span_warning("The shuttle isn't responding to commands."))
- return
- . = ..()
- if(.)
- return
- if(M.hijack_state == HIJACK_STATE_CRASHING)
- return
-
- if(ishuman(usr) || isAI(usr))
- if(!allowed(usr))
- return
- if(href_list["lockdown"])
-
- else if(href_list["release"])
-
- else if(href_list["lock"])
- M.lockdown_airlocks(href_list["lock"])
- else if(href_list["unlock"])
- M.unlock_airlocks(href_list["unlock"])
- return
-
- if(!is_ground_level(M.z))
- return
-
- if(!isxeno(usr))
- return
-
- var/mob/living/carbon/xenomorph/X = usr
-
- if(href_list["hijack"])
- if(!(X.hive.hive_flags & HIVE_CAN_HIJACK))
- to_chat(X, span_warning("Our hive lacks the psychic prowess to hijack the bird."))
- return
- switch(M.mode)
- if(SHUTTLE_RECHARGING)
- to_chat(X, span_xenowarning("The bird is still cooling down."))
+ shuttle.time_between_cycle = params["cycle_time_change"]
+ //These are actions for the Xeno dropship UI
+ if("hijack")
+ var/mob/living/carbon/xenomorph/xeno = usr
+ if(!(xeno.hive.hive_flags & HIVE_CAN_HIJACK))
+ to_chat(xeno, span_warning("Our hive lacks the psychic prowess to hijack the bird."))
return
- if(SHUTTLE_IDLE) //Continue.
- else
- to_chat(X, span_xenowarning("We can't do that right now."))
+ if(shuttle.mode == SHUTTLE_RECHARGING)
+ to_chat(xeno, span_xenowarning("The bird is still cooling down."))
+ return
+ if(shuttle.mode != SHUTTLE_IDLE)
+ to_chat(xeno, span_xenowarning("We can't do that right now."))
+ return
+ var/confirm = tgui_alert(usr, "Would you like to hijack the metal bird?", "Hijack the bird?", list("Yes", "No"))
+ if(confirm != "Yes")
+ return
+ var/obj/docking_port/stationary/marine_dropship/crash_target/CT = pick(SSshuttle.crash_targets)
+ if(!CT)
+ return
+ do_hijack(shuttle, CT, xeno)
+ if("abduct")
+ var/datum/game_mode/infestation/infestation_mode = SSticker.mode
+ if(infestation_mode.round_stage == INFESTATION_MARINE_CRASHING)
+ message_admins("[usr] tried to capture the shuttle after it was already hijacked, possible use of exploits.")
+ return
+ var/groundside_humans = length(GLOB.humans_by_zlevel["[z]"])
+ if(groundside_humans > 5)
+ to_chat(usr, span_xenowarning("There is still prey left to hunt!"))
+ return
+ var/confirm = tgui_alert(usr, "Would you like to capture the metal bird?\n THIS WILL END THE ROUND", "Capture the ship?", list( "Yes", "No"))
+ if(confirm != "Yes")
+ return
+ groundside_humans = length(GLOB.humans_by_zlevel["[z]"])
+ if(groundside_humans > 5)
+ to_chat(usr, span_xenowarning("There is still prey left to hunt!"))
return
- var/confirm = tgui_alert(usr, "Would you like to hijack the metal bird?", "Hijack the bird?", list("Yes", "No"))
- if(confirm != "Yes")
- return
- var/obj/docking_port/stationary/marine_dropship/crash_target/CT = pick(SSshuttle.crash_targets)
- if(!CT)
- return
- do_hijack(M, CT, X)
-
- if(href_list["abduct"])
- var/groundside_humans
- for(var/N in GLOB.alive_human_list)
- var/mob/H = N
- if(H.z != X.z)
- continue
- groundside_humans++
-
- if(groundside_humans > 5)
- to_chat(X, span_xenowarning("There is still prey left to hunt!"))
- return
- var/confirm = tgui_alert(usr, "Would you like to capture the metal bird?\n THIS WILL END THE ROUND", "Capture the ship?", list( "Yes", "No"))
- if(confirm != "Yes")
+ priority_announce("The Normandy has been captured! Losing their main mean of accessing the ground, the marines have no choice but to retreat.", title = "Alamo Captured", color_override = "orange")
+ infestation_mode.round_stage = INFESTATION_DROPSHIP_CAPTURED_XENOS
return
- priority_announce("The Alamo has been captured! Losing their main mean of accessing the ground, the marines have no choice but to retreat.", title = "ALAMO CAPTURED")
- var/datum/game_mode/infestation/infestation_mode = SSticker.mode
- infestation_mode.round_stage = INFESTATION_DROPSHIP_CAPTURED_XENOS
- return
-*/
/obj/machinery/computer/shuttle/marine_dropship/proc/do_hijack(obj/docking_port/mobile/marine_dropship/crashing_dropship, obj/docking_port/stationary/marine_dropship/crash_target/crash_target, mob/living/carbon/xenomorph/user)
crashing_dropship.set_hijack_state(HIJACK_STATE_CRASHING)
- if(SSticker.mode?.flags_round_type & MODE_HIJACK_POSSIBLE)
+ if(SSticker.mode?.round_type_flags & MODE_HIJACK_POSSIBLE)
var/datum/game_mode/infestation/infestation_mode = SSticker.mode
infestation_mode.round_stage = INFESTATION_MARINE_CRASHING
crashing_dropship.callTime = 120 * (GLOB.current_orbit/3) SECONDS
crashing_dropship.crashing = TRUE
crashing_dropship.unlock_all()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_DROPSHIP_HIJACKED)
- priority_announce("Unscheduled dropship departure detected from operational area. Hijack likely.", "Dropship Alert", sound = 'sound/AI/hijack.ogg')
+ priority_announce("Unscheduled dropship departure detected from operational area. Hijack likely.", title = "Critical Dropship Alert", type = ANNOUNCEMENT_PRIORITY, sound = 'sound/AI/hijack.ogg', color_override = "red")
to_chat(user, span_danger("A loud alarm erupts from [src]! The fleshy hosts must know that you can access it!"))
+ GLOB.hive_datums[XENO_HIVE_NORMAL].special_build_points = 25 //resets special build points
user.hive.on_shuttle_hijack(crashing_dropship)
playsound(src, 'sound/misc/queen_alarm.ogg')
crashing_dropship.silicon_lock_airlocks(TRUE)
- SSevacuation.flags_scuttle &= ~FLAGS_SDEVAC_TIMELOCK
+ SSevacuation.scuttle_flags &= ~FLAGS_SDEVAC_TIMELOCK
switch(SSshuttle.moveShuttleToDock(shuttleId, crash_target, TRUE))
if(0)
visible_message("Shuttle departing. Please stand away from the doors.")
@@ -754,7 +714,6 @@
name = "\improper 'Alamo' flight controls"
desc = "The flight controls for the 'Alamo' Dropship. Named after the Alamo Mission, stage of the Battle of the Alamo in the United States' state of Texas in the Spring of 1836. The defenders held to the last, encouraging other Texians to rally to the flag."
possible_destinations = "lz1;lz2;alamo"
- opacity = FALSE
/* RUTGMC DELETION
/obj/machinery/computer/shuttle/marine_dropship/one/Initialize(mapload)
@@ -786,6 +745,12 @@
/turf/open/shuttle/dropship/floor/alt
icon_state = "rasputin14"
+/turf/open/shuttle/dropship/floor/corners
+ icon_state = "rasputin16"
+
+/turf/open/shuttle/dropship/floor/out
+ icon_state = "rasputin17"
+
/obj/machinery/door/airlock/multi_tile/mainship/dropshiprear/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
. = ..()
if(!istype(port, /obj/docking_port/mobile/marine_dropship))
@@ -1311,13 +1276,13 @@
if(action != "selectDestination")
return FALSE
- var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
+ var/obj/docking_port/mobile/shuttle = SSshuttle.getShuttle(shuttleId)
#ifndef TESTING
- if(!(M.shuttle_flags & GAMEMODE_IMMUNE) && world.time < SSticker.round_start_time + SSticker.mode.deploy_time_lock)
+ if(!(shuttle.shuttle_flags & GAMEMODE_IMMUNE) && world.time < SSticker.round_start_time + SSticker.mode.deploy_time_lock)
to_chat(usr, span_warning("The engines are still refueling."))
return TRUE
#endif
- if(!M.can_move_topic(usr))
+ if(!shuttle.can_move_topic(usr))
return TRUE
if(!params["destination"])
@@ -1328,8 +1293,8 @@
message_admins("[ADMIN_TPMONTY(usr)] may be attempting a href dock exploit on [src] with target location \"[html_encode(params["destination"])]\"")
return TRUE
- var/previous_status = M.mode
- log_game("[key_name(usr)] has sent the shuttle [M] to [params["destination"]]")
+ var/previous_status = shuttle.mode
+ log_game("[key_name(usr)] has sent the shuttle [shuttle] to [params["destination"]]")
switch(SSshuttle.moveShuttle(shuttleId, params["destination"], 1))
if(0)
@@ -1352,12 +1317,12 @@
/obj/machinery/computer/shuttle/shuttle_control/ui_data(mob/user)
var/list/data = list()
var/list/options = valid_destinations()
- var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
- if(!M)
+ var/obj/docking_port/mobile/shuttle = SSshuttle.getShuttle(shuttleId)
+ if(!shuttle)
return data //empty but oh well
- data["linked_shuttle_name"] = M.name
- data["shuttle_status"] = M.getStatusText()
+ data["linked_shuttle_name"] = shuttle.name
+ data["shuttle_status"] = shuttle.getStatusText()
for(var/option in options)
for(var/obj/docking_port/stationary/S AS in SSshuttle.stationary)
if(option != S.id)
@@ -1365,7 +1330,7 @@
var/list/dataset = list()
dataset["id"] = S.id
dataset["name"] = S.name
- dataset["locked"] = !M.check_dock(S, silent=TRUE)
+ dataset["locked"] = !shuttle.check_dock(S, silent=TRUE)
data["destinations"] += list(dataset)
return data
diff --git a/code/modules/shuttle/mini_dropship.dm b/code/modules/shuttle/mini_dropship.dm
index 73ee62729ee0a..dc017a3f28ee7 100644
--- a/code/modules/shuttle/mini_dropship.dm
+++ b/code/modules/shuttle/mini_dropship.dm
@@ -17,7 +17,7 @@
desc = "Used to designate a precise transit location for the Tadpole."
icon_state = "shuttlecomputer"
screen_overlay = "shuttlecomputer_screen"
- req_one_access = list(ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LEADER)
+ req_access = list(ACCESS_MARINE_TADPOLE)
density = FALSE
interaction_flags = INTERACT_OBJ_UI
resistance_flags = RESIST_ALL
@@ -160,23 +160,23 @@
return
nvg_vision_mode = !nvg_vision_mode
-/obj/machinery/computer/camera_advanced/shuttle_docker/minidropship/attack_alien(mob/living/carbon/xenomorph/X, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
+/obj/machinery/computer/camera_advanced/shuttle_docker/minidropship/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
. = ..()
if(machine_stat & BROKEN)
return
- if(X.status_flags & INCORPOREAL)
+ if(xeno_attacker.status_flags & INCORPOREAL)
return
- X.visible_message("[X] begins to slash delicately at the computer",
+ xeno_attacker.visible_message("[xeno_attacker] begins to slash delicately at the computer",
"We start slashing delicately at the computer. This will take a while.")
- if(!do_after(X, 10 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
+ if(!do_after(xeno_attacker, 10 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
return
visible_message("The inner wiring is visible, it can be slashed!")
- X.visible_message("[X] continue to slash at the computer",
+ xeno_attacker.visible_message("[xeno_attacker] continue to slash at the computer",
"We continue slashing at the computer. If we stop now we will have to start all over again.")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
s.start()
- if(!do_after(X, 10 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
+ if(!do_after(xeno_attacker, 10 SECONDS, NONE, src, BUSY_ICON_DANGER, BUSY_ICON_HOSTILE))
return
visible_message("The wiring is destroyed, nobody will be able to repair this computer!")
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MINI_DROPSHIP_DESTROYED, src)
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 1b659ea65cdcd..2f287d18e597d 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -161,7 +161,7 @@
if(designate_time && (landing_clear != SHUTTLE_DOCKER_BLOCKED))
to_chat(current_user, span_warning("Targeting transit location, please wait [DisplayTimeText(designate_time)]..."))
designating_target_loc = the_eye.loc
- var/wait_completed = do_after(current_user, designate_time, NONE, designating_target_loc, extra_checks = CALLBACK(src, /obj/machinery/computer/camera_advanced/shuttle_docker/proc/canDesignateTarget))
+ var/wait_completed = do_after(current_user, designate_time, NONE, designating_target_loc, extra_checks = CALLBACK(src, PROC_REF(canDesignateTarget)))
designating_target_loc = null
if(!current_user)
return
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index b0f256cfd42e4..f3ea3f6d61e46 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -38,7 +38,7 @@ All ShuttleMove procs go here
continue
if(ismovable(thing))
var/atom/movable/movable_thing = thing
- if(movable_thing.flags_atom & SHUTTLE_IMMUNE)
+ if(movable_thing.atom_flags & SHUTTLE_IMMUNE)
var/old_dir = movable_thing.dir
movable_thing.abstract_move(src)
movable_thing.setDir(old_dir)
@@ -98,7 +98,7 @@ All ShuttleMove procs go here
if(loc != oldT) // This is for multi tile objects
return
- if(flags_atom & SHUTTLE_IMMUNE)
+ if(atom_flags & SHUTTLE_IMMUNE)
return
abstract_move(newT)
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index b443bb58d6676..d02847188cd0e 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -315,7 +315,7 @@
/obj/docking_port/stationary/proc/on_crash()
return
-//returns first-found touching shuttleport
+///returns first-found touching shuttleport
/obj/docking_port/stationary/get_docked()
. = locate(/obj/docking_port/mobile) in loc
@@ -355,14 +355,20 @@
var/list/shuttle_areas
- var/timer //used as a timer (if you want time left to complete move, use timeLeft proc)
+ ///used as a timer (if you want time left to complete move, use timeLeft proc)
+ var/timer
var/last_timer_length
- var/mode = SHUTTLE_IDLE //current shuttle mode
- var/callTime = 100 //time spent in transit (deciseconds). Should not be lower then 10 seconds without editing the animation of the hyperspace ripples.
- var/ignitionTime = 55 // time spent "starting the engines". Also rate limits how often we try to reserve transit space if its ever full of transiting shuttles.
- var/rechargeTime = 0 //time spent after arrival before being able to launch again
- var/prearrivalTime = 0 //delay after call time finishes for sound effects, explosions, etc.
+ ///current shuttle mode
+ var/mode = SHUTTLE_IDLE
+ ///time spent in transit (deciseconds). Should not be lower then 10 seconds without editing the animation of the hyperspace ripples.
+ var/callTime = 100
+ /// time spent "starting the engines". Also rate limits how often we try to reserve transit space if its ever full of transiting shuttles.
+ var/ignitionTime = 55
+ ///time spent after arrival before being able to launch again
+ var/rechargeTime = 0
+ ///delay after call time finishes for sound effects, explosions, etc.
+ var/prearrivalTime = 0
var/landing_sound = 'sound/effects/engine_landing.ogg'
var/ignition_sound = 'sound/effects/engine_startup.ogg'
diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm
index 1bad750d5e0ef..fb5c5625cca84 100644
--- a/code/modules/surgery/eye.dm
+++ b/code/modules/surgery/eye.dm
@@ -40,7 +40,7 @@
/datum/surgery_step/eye/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected)
user.visible_message(span_notice("[user] has separated the cornea on [target]'s eyes with \the [tool].") , \
- span_notice("You have separated the cornea on [target]'s eyes with \the [tool]."),)
+ span_notice("You have separated the cornea on [target]'s eyes with \the [tool]."))
target.balloon_alert_to_viewers("Success")
var/datum/internal_organ/eyes/E = target.internal_organs_by_name["eyes"]
E.eye_surgery_stage = 1
diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm
index 8539fc54e9fc3..e4003d8f5e95e 100644
--- a/code/modules/surgery/generic.dm
+++ b/code/modules/surgery/generic.dm
@@ -44,7 +44,7 @@
/datum/surgery_step/generic/incision_manager/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected)
user.visible_message(span_notice("[user] has constructed a prepared incision on and within [target]'s [affected.display_name] with \the [tool]."), \
- span_notice("You have constructed a prepared incision on and within [target]'s [affected.display_name] with \the [tool]."),)
+ span_notice("You have constructed a prepared incision on and within [target]'s [affected.display_name] with \the [tool]."))
target.balloon_alert_to_viewers("Success")
affected.surgery_open_stage = 1
@@ -143,7 +143,7 @@
/datum/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected)
user.visible_message(span_notice("[user] has made an incision on [target]'s [affected.display_name] with \the [tool]."), \
- span_notice("You have made an incision on [target]'s [affected.display_name] with \the [tool]."),)
+ span_notice("You have made an incision on [target]'s [affected.display_name] with \the [tool]."))
target.balloon_alert_to_viewers("Success")
affected.surgery_open_stage = 1
@@ -200,7 +200,7 @@
/datum/surgery_step/generic/clamp_bleeders/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected)
user.visible_message(span_warning("[user]'s hand slips, tearing blood vessals and causing massive bleeding in [target]'s [affected.display_name] with \the [tool]!"), \
- span_warning("Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.display_name] with \the [tool]!"),)
+ span_warning("Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.display_name] with \the [tool]!"))
target.balloon_alert_to_viewers("Slipped!")
affected.createwound(CUT, 10)
affected.update_wounds()
diff --git a/code/modules/tgchat/README.md b/code/modules/tgchat/README.md
new file mode 100644
index 0000000000000..95f28ae0e8cf9
--- /dev/null
+++ b/code/modules/tgchat/README.md
@@ -0,0 +1,30 @@
+## /TG/ Chat
+
+/TG/ Chat, which will be referred to as TgChat from this point onwards, is a system in which we can send messages to clients in a controlled and semi-reliable manner. The standard way of sending messages to BYOND clients simply dumps whatever you output to them directly into their chat window, however BYOND allows us to load our own code on the client to change this behaviour in a way that allows us to do some pretty neat things.
+
+### Message Format
+
+TgChat handles sending messages from the server to the client through the use of JSON payloads, of which the format will change depending on the type of message and the intended client endpoint. An example of the payload for chat messages is as follows:
+```json
+{
+ "sequence": 0,
+ "content": {
+ "type": ". . .", // ?optional
+ "text": ". . .", // ?optional !atleast-one
+ "html": ". . .", // ?optional !atleast-one
+ "avoidHighlighting": 0 // ?optional
+ },
+}
+```
+
+### Reliability
+
+In the past there have been issues where BYOND will silently and without reason lose a message we sent to the client, to detect this and recover from it seamlessly TgChat also has a baked in reliability layer. This reliability layer is very primitive, and simply keeps track of recieved sequence numbers. Should the client recieve an unexpected sequence number TgChat asks the server to resend any missing packets.
+
+### Ping System
+
+TgChat supports a round trip time ping measurement, which is displayed to the client so they can know how long it takes for their commands and inputs to reach the server. This is done by sending the client a ping request, `ping/soft`, which tells the client to send a ping to the server. When the server recieves said ping it sends a reply, `ping/reply`, to the client with a payload containing the current DateTime which the client can reference against the initial ping request.
+
+### Chat Tabs, Local Storage, and Highlighting
+
+To make organizing and managing chat easier and more functional for both players and admins, TgChat has the ability to filter out messages based on their primary tag, such as individual departmental radios, to a dedicated chat tab for easier reading and comprehension. These tabs can also be configured to highlist messages based on a simple keyword search. You can set a multitude of different keywords to search for and they will be highlighting for instant alerting of the client. Said tabs, highlighting rules, and your chat history will persist thanks to use of local storage on the client. Using local storage TgChat can ensure that your preferences are saved and maintained between client restarts and switching between other /TG/ servers. Local Storage is also used to keep your chat history aswell, should you need to scroll through your chat logs.
diff --git a/code/modules/tgchat/to_chat.dm b/code/modules/tgchat/to_chat.dm
index 6ee122c719414..fda50b66dc69d 100644
--- a/code/modules/tgchat/to_chat.dm
+++ b/code/modules/tgchat/to_chat.dm
@@ -25,23 +25,9 @@
if(text) message["text"] = text
if(html) message["html"] = html
if(avoid_highlighting) message["avoidHighlighting"] = avoid_highlighting
- var/message_blob = TGUI_CREATE_MESSAGE("chat/message", message)
- var/message_html = message_to_html(message)
- if(islist(target))
- for(var/_target in target)
- var/client/client = CLIENT_FROM_VAR(_target)
- if(client)
- // Send to tgchat
- client.tgui_panel?.window.send_raw_message(message_blob)
- // Send to old chat
- SEND_TEXT(client, message_html)
- return
- var/client/client = CLIENT_FROM_VAR(target)
- if(client)
- // Send to tgchat
- client.tgui_panel?.window.send_raw_message(message_blob)
- // Send to old chat
- SEND_TEXT(client, message_html)
+
+ // send it immediately
+ SSchat.send_immediate(target, message)
/**
* Sends the message to the recipient (target).
diff --git a/code/modules/tgs/LICENSE b/code/modules/tgs/LICENSE
index 2bedf9a63aa0e..324c48e993e13 100644
--- a/code/modules/tgs/LICENSE
+++ b/code/modules/tgs/LICENSE
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2017-2023 Jordan Brown
+Copyright (c) 2017-2024 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index b9a9f27a28ae8..15622228e91fe 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -42,11 +42,11 @@
var/datum/tgs_version/max_api_version = TgsMaximumApiVersion();
if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
- TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.")
+ TGS_ERROR_LOG("Detected unknown Interop API version! Defaulting to latest. Update the DMAPI to fix this problem.")
api_datum = /datum/tgs_api/latest
if(!api_datum)
- TGS_ERROR_LOG("Found unsupported API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.")
+ TGS_ERROR_LOG("Found unsupported Interop API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.")
return
TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]")
@@ -107,6 +107,13 @@
if(api)
return api.ApiVersion()
+/world/TgsEngine()
+#ifdef OPENDREAM
+ return TGS_ENGINE_TYPE_OPENDREAM
+#else
+ return TGS_ENGINE_TYPE_BYOND
+#endif
+
/world/TgsInstanceName()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
@@ -159,3 +166,11 @@
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
return api.Visibility()
+
+/world/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ if(!istype(parameters, /list))
+ parameters = list()
+
+ return api.TriggerEvent(event_name, parameters, wait_for_completion)
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index 07ce3b684584e..f734fd0527f0e 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -7,7 +7,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
var/list/warned_deprecated_command_runs
/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
- . = ..()
+ ..()
src.event_handler = event_handler
src.version = version
@@ -17,7 +17,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
world.sleep_offline = FALSE // https://www.byond.com/forum/post/2894866
del(world)
world.sleep_offline = FALSE // just in case, this is BYOND after all...
- sleep(1)
+ sleep(world.tick_lag)
TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]")
/datum/tgs_api/latest
@@ -69,3 +69,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api)
/datum/tgs_api/proc/Visibility()
return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/TriggerEvent(event_name, list/parameters, wait_for_completion)
+ return FALSE
diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm
index a5dae1241a306..bc561e67487a2 100644
--- a/code/modules/tgs/core/tgs_version.dm
+++ b/code/modules/tgs/core/tgs_version.dm
@@ -1,4 +1,5 @@
/datum/tgs_version/New(raw_parameter)
+ ..()
src.raw_parameter = raw_parameter
deprefixed_parameter = replacetext(raw_parameter, "/tg/station 13 Server v", "")
var/list/version_bits = splittext(deprefixed_parameter, ".")
diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm
index 945e2e4117671..7c87922750b9b 100644
--- a/code/modules/tgs/v4/api.dm
+++ b/code/modules/tgs/v4/api.dm
@@ -181,7 +181,7 @@
var/json = json_encode(data)
while(requesting_new_port && !override_requesting_new_port)
- sleep(1)
+ sleep(world.tick_lag)
//we need some port open at this point to facilitate return communication
if(!world.port)
@@ -209,7 +209,7 @@
requesting_new_port = FALSE
while(export_lock)
- sleep(1)
+ sleep(world.tick_lag)
export_lock = TRUE
last_interop_response = null
@@ -217,7 +217,7 @@
text2file(json, server_commands_json_path)
for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I)
- sleep(1)
+ sleep(world.tick_lag)
if(!last_interop_response)
TGS_ERROR_LOG("Failed to get export result for: [json]")
diff --git a/code/modules/tgs/v5/__interop_version.dm b/code/modules/tgs/v5/__interop_version.dm
index 83420d130a747..f4806f7adb97c 100644
--- a/code/modules/tgs/v5/__interop_version.dm
+++ b/code/modules/tgs/v5/__interop_version.dm
@@ -1 +1 @@
-"5.7.0"
+"5.9.0"
diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
index 48969c0c7d561..92c7a8388a711 100644
--- a/code/modules/tgs/v5/_defines.dm
+++ b/code/modules/tgs/v5/_defines.dm
@@ -8,16 +8,17 @@
#define DMAPI5_TOPIC_REQUEST_LIMIT 65528
#define DMAPI5_TOPIC_RESPONSE_LIMIT 65529
-#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0
#define DMAPI5_BRIDGE_COMMAND_STARTUP 1
#define DMAPI5_BRIDGE_COMMAND_PRIME 2
#define DMAPI5_BRIDGE_COMMAND_REBOOT 3
#define DMAPI5_BRIDGE_COMMAND_KILL 4
#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
#define DMAPI5_BRIDGE_COMMAND_CHUNK 6
+#define DMAPI5_BRIDGE_COMMAND_EVENT 7
#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
#define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands"
+#define DMAPI5_PARAMETER_TOPIC_PORT "topicPort"
#define DMAPI5_CHUNK "chunk"
#define DMAPI5_CHUNK_PAYLOAD "payload"
@@ -34,6 +35,7 @@
#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
+#define DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION "eventInvocation"
#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
@@ -81,6 +83,7 @@
#define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9
#define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10
#define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11
+#define DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT 12
#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
@@ -116,3 +119,9 @@
#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"
+
+#define DMAPI5_EVENT_ID "eventId"
+
+#define DMAPI5_EVENT_INVOCATION_NAME "eventName"
+#define DMAPI5_EVENT_INVOCATION_PARAMETERS "parameters"
+#define DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION "notifyCompletion"
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
index 7226f29bba603..95b8edd3ee5c2 100644
--- a/code/modules/tgs/v5/api.dm
+++ b/code/modules/tgs/v5/api.dm
@@ -8,8 +8,12 @@
var/reboot_mode = TGS_REBOOT_MODE_NORMAL
+ /// List of chat messages list()s that attempted to be sent during a topic call. To be bundled in the result of the call
var/list/intercepted_message_queue
+ /// List of chat messages list()s that attempted to be sent during a topic call. To be bundled in the result of the call
+ var/list/offline_message_queue
+
var/list/custom_commands
var/list/test_merges
@@ -17,15 +21,20 @@
var/list/chat_channels
var/initialized = FALSE
+ var/initial_bridge_request_received = FALSE
+ var/datum/tgs_version/interop_version
var/chunked_requests = 0
var/list/chunked_topics = list()
+ var/list/pending_events = list()
+
var/detached = FALSE
/datum/tgs_api/v5/New()
. = ..()
- TGS_DEBUG_LOG("V5 API created")
+ interop_version = version
+ TGS_DEBUG_LOG("V5 API created: [json_encode(args)]")
/datum/tgs_api/v5/ApiVersion()
return new /datum/tgs_version(
@@ -38,8 +47,12 @@
access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER]
var/datum/tgs_version/api_version = ApiVersion()
- version = null
- var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
+ version = null // we want this to be the TGS version, not the interop version
+
+ // sleep once to prevent an issue where world.Export on the first tick can hang indefinitely
+ sleep(world.tick_lag)
+
+ var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort()))
if(!istype(bridge_response))
TGS_ERROR_LOG("Failed initial bridge request!")
return FALSE
@@ -53,7 +66,8 @@
TGS_INFO_LOG("DMAPI validation, exiting...")
TerminateWorld()
- version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
+ initial_bridge_request_received = TRUE
+ version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION]) // reassigning this because it can change if TGS updates
security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL]
visibility = runtime_information[DMAPI5_RUNTIME_INFORMATION_VISIBILITY]
instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME]
@@ -102,15 +116,22 @@
initialized = TRUE
return TRUE
+/datum/tgs_api/v5/proc/GetTopicPort()
+#if defined(OPENDREAM) && defined(OPENDREAM_TOPIC_PORT_EXISTS)
+ return "[world.opendream_topic_port]"
+#else
+ return null
+#endif
+
/datum/tgs_api/v5/proc/RequireInitialBridgeResponse()
TGS_DEBUG_LOG("RequireInitialBridgeResponse()")
var/logged = FALSE
- while(!version)
+ while(!initial_bridge_request_received)
if(!logged)
TGS_DEBUG_LOG("RequireInitialBridgeResponse: Starting sleep")
logged = TRUE
- sleep(1)
+ sleep(world.tick_lag)
TGS_DEBUG_LOG("RequireInitialBridgeResponse: Passed")
@@ -183,17 +204,7 @@
var/datum/tgs_chat_channel/channel = I
ids += channel.id
- message2 = UpgradeDeprecatedChatMessage(message2)
-
- if (!length(channels))
- return
-
- var/list/data = message2._interop_serialize()
- data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = ids
- if(intercepted_message_queue)
- intercepted_message_queue += list(data)
- else
- Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
+ SendChatMessageRaw(message2, ids)
/datum/tgs_api/v5/ChatTargetedBroadcast(datum/tgs_message_content/message2, admin_only)
var/list/channels = list()
@@ -202,32 +213,82 @@
if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
channels += channel.id
+ SendChatMessageRaw(message2, channels)
+
+/datum/tgs_api/v5/ChatPrivateMessage(datum/tgs_message_content/message2, datum/tgs_chat_user/user)
+ SendChatMessageRaw(message2, list(user.channel.id))
+
+/datum/tgs_api/v5/proc/SendChatMessageRaw(datum/tgs_message_content/message2, list/channel_ids)
message2 = UpgradeDeprecatedChatMessage(message2)
- if (!length(channels))
+ if (!length(channel_ids))
return
var/list/data = message2._interop_serialize()
- data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = channels
+ data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = channel_ids
if(intercepted_message_queue)
intercepted_message_queue += list(data)
- else
- Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
+ return
-/datum/tgs_api/v5/ChatPrivateMessage(datum/tgs_message_content/message2, datum/tgs_chat_user/user)
- message2 = UpgradeDeprecatedChatMessage(message2)
- var/list/data = message2._interop_serialize()
- data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = list(user.channel.id)
- if(intercepted_message_queue)
- intercepted_message_queue += list(data)
+ if(offline_message_queue)
+ offline_message_queue += list(data)
+ return
+
+ if(detached)
+ offline_message_queue = list(data)
+
+ WaitForReattach(FALSE)
+
+ data = offline_message_queue
+ offline_message_queue = null
+
+ for(var/queued_message in data)
+ SendChatDataRaw(queued_message)
else
- Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
+ SendChatDataRaw(data)
+
+/datum/tgs_api/v5/proc/SendChatDataRaw(list/data)
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
/datum/tgs_api/v5/ChatChannelInfo()
RequireInitialBridgeResponse()
WaitForReattach(TRUE)
return chat_channels.Copy()
+/datum/tgs_api/v5/TriggerEvent(event_name, list/parameters, wait_for_completion)
+ RequireInitialBridgeResponse()
+ WaitForReattach(TRUE)
+
+ if(interop_version.minor < 9)
+ TGS_WARNING_LOG("Interop version too low for custom events!")
+ return FALSE
+
+ var/str_parameters = list()
+ for(var/i in parameters)
+ str_parameters += "[i]"
+
+ var/list/response = Bridge(DMAPI5_BRIDGE_COMMAND_EVENT, list(DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION = list(DMAPI5_EVENT_INVOCATION_NAME = event_name, DMAPI5_EVENT_INVOCATION_PARAMETERS = str_parameters, DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION = wait_for_completion)))
+ if(!response)
+ return FALSE
+
+ var/event_id = response[DMAPI5_EVENT_ID]
+ if(!event_id)
+ return FALSE
+
+ TGS_DEBUG_LOG("Created event ID: [event_id]")
+ if(!wait_for_completion)
+ return TRUE
+
+ TGS_DEBUG_LOG("Waiting for completion of event ID: [event_id]")
+
+ while(!pending_events[event_id])
+ sleep(world.tick_lag)
+
+ TGS_DEBUG_LOG("Completed wait on event ID: [event_id]")
+ pending_events -= event_id
+
+ return TRUE
+
/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
TGS_DEBUG_LOG("DecodeChannels()")
var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
diff --git a/code/modules/tgs/v5/bridge.dm b/code/modules/tgs/v5/bridge.dm
index 37f58bcdf632e..0c5e701a32b60 100644
--- a/code/modules/tgs/v5/bridge.dm
+++ b/code/modules/tgs/v5/bridge.dm
@@ -48,7 +48,9 @@
var/json = CreateBridgeData(command, data, TRUE)
var/encoded_json = url_encode(json)
- var/url = "http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]"
+ var/api_prefix = interop_version.minor >= 8 ? "api/" : ""
+
+ var/url = "http://127.0.0.1:[server_port]/[api_prefix]Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]"
return url
/datum/tgs_api/v5/proc/CreateBridgeData(command, list/data, needs_auth)
@@ -63,7 +65,7 @@
if(detached)
// Wait up to one minute
for(var/i in 1 to 600)
- sleep(1)
+ sleep(world.tick_lag)
if(!detached && (!require_channels || length(chat_channels)))
break
@@ -75,17 +77,25 @@
/datum/tgs_api/v5/proc/PerformBridgeRequest(bridge_request)
WaitForReattach(FALSE)
+ TGS_DEBUG_LOG("Bridge request start")
// This is an infinite sleep until we get a response
var/export_response = world.Export(bridge_request)
+ TGS_DEBUG_LOG("Bridge request complete")
+
if(!export_response)
TGS_ERROR_LOG("Failed bridge request: [bridge_request]")
return
- var/response_json = file2text(export_response["CONTENT"])
- if(!response_json)
+ var/content = export_response["CONTENT"]
+ if(!content)
TGS_ERROR_LOG("Failed bridge request, missing content!")
return
+ var/response_json = TGS_FILE2TEXT_NATIVE(content)
+ if(!response_json)
+ TGS_ERROR_LOG("Failed bridge request, failed to load content!")
+ return
+
var/list/bridge_response = json_decode(response_json)
if(!bridge_response)
TGS_ERROR_LOG("Failed bridge request, bad json: [response_json]")
diff --git a/code/modules/tgs/v5/topic.dm b/code/modules/tgs/v5/topic.dm
index 2ef0c70a97fa0..e1f2cb6385789 100644
--- a/code/modules/tgs/v5/topic.dm
+++ b/code/modules/tgs/v5/topic.dm
@@ -175,6 +175,11 @@
var/list/reattach_response = TopicResponse(error_message)
reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands()
+ reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort()
+
+ for(var/eventId in pending_events)
+ pending_events[eventId] = TRUE
+
return reattach_response
if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK)
@@ -275,6 +280,15 @@
TGS_WORLD_ANNOUNCE(message)
return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT)
+ var/event_id = topic_parameters[DMAPI5_EVENT_ID]
+ if (!istext(event_id))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_ID]")
+
+ TGS_DEBUG_LOG("Completing event ID [event_id]...")
+ pending_events[event_id] = TRUE
+ return TopicResponse()
+
return TopicResponse("Unknown command: [command]")
/datum/tgs_api/v5/proc/WorldBroadcast(message)
diff --git a/code/modules/tgs/v5/undefs.dm b/code/modules/tgs/v5/undefs.dm
index fd1ed7e4cf54f..237207fdfd056 100644
--- a/code/modules/tgs/v5/undefs.dm
+++ b/code/modules/tgs/v5/undefs.dm
@@ -8,16 +8,17 @@
#undef DMAPI5_TOPIC_REQUEST_LIMIT
#undef DMAPI5_TOPIC_RESPONSE_LIMIT
-#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE
#undef DMAPI5_BRIDGE_COMMAND_STARTUP
#undef DMAPI5_BRIDGE_COMMAND_PRIME
#undef DMAPI5_BRIDGE_COMMAND_REBOOT
#undef DMAPI5_BRIDGE_COMMAND_KILL
#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
#undef DMAPI5_BRIDGE_COMMAND_CHUNK
+#undef DMAPI5_BRIDGE_COMMAND_EVENT
#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
#undef DMAPI5_PARAMETER_CUSTOM_COMMANDS
+#undef DMAPI5_PARAMETER_TOPIC_PORT
#undef DMAPI5_CHUNK
#undef DMAPI5_CHUNK_PAYLOAD
@@ -34,6 +35,7 @@
#undef DMAPI5_BRIDGE_PARAMETER_VERSION
#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
+#undef DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION
#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
@@ -81,6 +83,7 @@
#undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST
+#undef DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT
#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
@@ -116,3 +119,9 @@
#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY
+
+#undef DMAPI5_EVENT_ID
+
+#undef DMAPI5_EVENT_INVOCATION_NAME
+#undef DMAPI5_EVENT_INVOCATION_PARAMETERS
+#undef DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION
diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm
index 1f80f5e869757..bcd97a9124516 100644
--- a/code/modules/tgui/external.dm
+++ b/code/modules/tgui/external.dm
@@ -70,7 +70,7 @@
* change static data.
*/
/datum/proc/update_static_data_for_all_viewers()
- for (var/datum/tgui/window AS in SStgui.open_uis_by_src[REF(src)])
+ for (var/datum/tgui/window as anything in open_uis)
window.send_full_update()
/**
diff --git a/code/modules/tgui/states/alamo.dm b/code/modules/tgui/states/alamo.dm
new file mode 100644
index 0000000000000..3e4dd98ad6b40
--- /dev/null
+++ b/code/modules/tgui/states/alamo.dm
@@ -0,0 +1,35 @@
+/**
+ * tgui state: access_state
+ *
+ * Humans need to have access and be adjacent to use it.
+ * Silicons and other lifeforms get their default ui_state pass.
+ * Xenomorphs need to be intelligent
+ */
+
+GLOBAL_DATUM_INIT(alamo_state, /datum/ui_state/alamo_state, new)
+
+/datum/ui_state/alamo_state/can_use_topic(src_object, mob/user)
+ return user.alamo_can_use_topic(src_object)
+
+/mob/proc/alamo_can_use_topic(src_object)
+ return default_can_use_topic(src_object)
+
+/mob/living/alamo_can_use_topic(src_object)
+ . = human_adjacent_can_use_topic(src_object)
+
+ var/obj/O = src_object
+ if(!O?.allowed(src)) //No access? No ui!
+ to_chat(src, span_warning("Access Denied!"))
+ return UI_CLOSE
+ . = min(., UI_INTERACTIVE)
+
+/mob/living/silicon/alamo_can_use_topic(src_object)
+ return default_can_use_topic(src_object)
+
+/mob/living/carbon/xenomorph/alamo_can_use_topic(src_object)
+ var/datum/game_mode/infestation/infestation_mode = SSticker.mode
+ if(infestation_mode.round_stage == INFESTATION_MARINE_CRASHING) //Minor QOL, any xeno can check the console after a leader hijacks
+ return GLOB.xeno_state.can_use_topic(src_object, src)
+ if(!(xeno_caste.caste_flags & CASTE_IS_INTELLIGENT))
+ return default_can_use_topic(src_object)
+ return GLOB.xeno_state.can_use_topic(src_object, src)
diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm
index 674016bcafac3..aec20f0f3a354 100644
--- a/code/modules/tgui/tgui_window.dm
+++ b/code/modules/tgui/tgui_window.dm
@@ -372,6 +372,8 @@
client << link(href_list["url"])
if("cacheReloaded")
reinitialize()
+ if("chat/resend")
+ SSchat.handle_resend(client, payload)
/datum/tgui_window/vv_edit_var(var_name, var_value)
return var_name != NAMEOF(src, id) && ..()
diff --git a/code/modules/tgui_input/say_modal/modal.dm b/code/modules/tgui_input/say_modal/modal.dm
index 88814a434c2ac..239888d91c40f 100644
--- a/code/modules/tgui_input/say_modal/modal.dm
+++ b/code/modules/tgui_input/say_modal/modal.dm
@@ -36,6 +36,7 @@
/datum/tgui_say/New(client/client, id)
src.client = client
window = new(client, id)
+ winset(client, "tgui_say", "size=1,1;is-visible=0;")
window.subscribe(src, PROC_REF(on_message))
window.is_browser = TRUE
@@ -62,11 +63,14 @@
*/
/datum/tgui_say/proc/load()
window_open = FALSE
- winshow(client, "tgui_say", FALSE)
+
+ winset(client, "tgui_say", "pos=848,500;size=231,30;is-visible=0;")
+
window.send_message("props", list(
lightMode = FALSE, //client.prefs?.read_preference(/datum/preference/toggle/tgui_say_light_mode),
maxLength = max_length,
))
+
stop_thinking()
return TRUE
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 73da6d9826422..29b0991748b84 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -68,6 +68,7 @@
#include "weed_spread.dm"
#include "xeno_logical_scaling.dm"
#include "item_variant_test.dm"
+#include "xenoaccuracy.dm"
#ifdef REFERENCE_TRACKING //Don't try and parse this file if ref tracking isn't turned on. IE: don't parse ref tracking please mr linter
#include "find_reference_sanity.dm"
diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm
index be40f64df1192..b8b9bc011f2ad 100644
--- a/code/modules/unit_tests/create_and_destroy.dm
+++ b/code/modules/unit_tests/create_and_destroy.dm
@@ -47,6 +47,8 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE)
ignore += typesof(/obj/effect/temp_visual)
ignore += typesof(/obj/effect/landmark)
ignore += typesof(/obj/effect/baseturf_helper)
+ ///forcespawned abstract type for vehicles, will never spawn outside of it
+ ignore += typesof(/obj/hitbox)
//Screen objects don't play nicely when spawned manually.
ignore += typesof(/atom/movable/screen)
diff --git a/code/modules/unit_tests/map_templates.dm b/code/modules/unit_tests/map_templates.dm
index f79919bad70d9..907ef824dc00f 100644
--- a/code/modules/unit_tests/map_templates.dm
+++ b/code/modules/unit_tests/map_templates.dm
@@ -7,6 +7,7 @@
/datum/map_template/modular/prison,
/datum/map_template/modular/bigred,
/datum/map_template/modular/end_of_round,
+ /datum/map_template/interior,
)
/datum/unit_test/map_templates/Run()
diff --git a/code/modules/unit_tests/xenoaccuracy.dm b/code/modules/unit_tests/xenoaccuracy.dm
new file mode 100644
index 0000000000000..033aa88b5a43c
--- /dev/null
+++ b/code/modules/unit_tests/xenoaccuracy.dm
@@ -0,0 +1,6 @@
+/datum/unit_test/xenoaccuracy
+
+/datum/unit_test/xenoaccuracy/Run()
+ for(var/datum/xeno_caste/caste AS in subtypesof(/datum/xeno_caste))
+ if(initial(caste.accuracy_malus) >= XENO_DEFAULT_ACCURACY)
+ Fail("A xeno accuracy malus of 70 or over was detected, negatives cannot be used in accuracy calculations.")
diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/__vehicle.dm
similarity index 94%
rename from code/modules/vehicles/_vehicle.dm
rename to code/modules/vehicles/__vehicle.dm
index 64236ebe0e9c4..58950fb0a47c4 100644
--- a/code/modules/vehicles/_vehicle.dm
+++ b/code/modules/vehicles/__vehicle.dm
@@ -20,6 +20,8 @@
var/max_drivers = 1
var/move_delay = 2
var/lastmove = 0
+ ///multitile hitbox, set to a hitbox type to make this vehicle multitile.
+ var/obj/hitbox/hitbox
/**
* If the driver needs a certain item in hand (or inserted, for vehicles) to drive this. For vehicles, this must be duplicated on their riding component subtype
* [/datum/component/riding/var/keytype] variable because only a few specific checks are handled here with this var, and the majority of it is on the riding component
@@ -42,6 +44,8 @@
/obj/vehicle/Initialize(mapload)
. = ..()
+ if(hitbox)
+ hitbox = new hitbox(loc, src)
occupants = list()
autogrant_actions_passenger = list()
autogrant_actions_controller = list()
@@ -92,6 +96,10 @@
/obj/vehicle/proc/is_driver(mob/M)
return is_occupant(M) && occupants[M] & VEHICLE_CONTROL_DRIVE
+///Is the passed mob an equipment controller?
+/obj/vehicle/proc/is_equipment_controller(mob/M)
+ return is_occupant(M) && occupants[M] & VEHICLE_CONTROL_EQUIPMENT
+
/obj/vehicle/proc/is_occupant(mob/M)
return !isnull(LAZYACCESS(occupants, M))
diff --git a/code/modules/vehicles/_hitbox.dm b/code/modules/vehicles/_hitbox.dm
new file mode 100644
index 0000000000000..7f0362d68c10e
--- /dev/null
+++ b/code/modules/vehicles/_hitbox.dm
@@ -0,0 +1,223 @@
+/**
+ * HITBOX
+ * The core of multitile. Acts as a relay for damage and stops people from walking onto the multitle sprite
+ * has changed bounds and as thus must always be forcemoved so it doesnt break everything
+ * I would use pixel movement but the maptick caused by it is way too high and a fake tile based movement might work? but I want this to at least pretend to be generic
+ * Thus we just use this relay. it's an obj so we can make sure all the damage procs that work on root also work on the hitbox
+ */
+/obj/hitbox
+ density = TRUE
+ anchored = TRUE
+ invisibility = INVISIBILITY_MAXIMUM
+ bound_width = 96
+ bound_height = 96
+ bound_x = -32
+ bound_y = -32
+ max_integrity = INFINITY
+ move_resist = INFINITY // non forcemoving this could break gliding so lets just say no
+ ///people riding on this hitbox that we want to move with us
+ var/list/atom/movable/tank_desants
+ ///The "parent" that this hitbox is attached to and to whom it will relay damage
+ var/obj/vehicle/root = null
+
+/obj/hitbox/Initialize(mapload, obj/vehicle/new_root)
+ . = ..()
+ root = new_root
+ allow_pass_flags = root.allow_pass_flags
+ atom_flags = root.atom_flags
+ resistance_flags = root.resistance_flags
+ RegisterSignal(new_root, COMSIG_MOVABLE_MOVED, PROC_REF(root_move))
+ RegisterSignal(new_root, COMSIG_QDELETING, PROC_REF(root_delete))
+ RegisterSignals(new_root, list(COMSIG_RIDDEN_DRIVER_MOVE, COMSIG_VEHICLE_MOVE), PROC_REF(on_attempt_drive))
+ RegisterSignal(new_root, COMSIG_ATOM_DIR_CHANGE, PROC_REF(owner_turned))
+
+ var/static/list/connections = list(
+ COMSIG_OBJ_TRY_ALLOW_THROUGH = PROC_REF(can_cross_hitbox),
+ COMSIG_TURF_JUMP_ENDED_HERE = PROC_REF(on_jump_landed),
+ COMSIG_ATOM_EXITED = PROC_REF(on_exited),
+ )
+ AddElement(/datum/element/connect_loc, connections)
+
+/obj/hitbox/Destroy(force)
+ if(!force) // only when the parent is deleted
+ return QDEL_HINT_LETMELIVE
+ root?.hitbox = null
+ root = null
+ return ..()
+
+///signal handler for handling PASS_WALKOVER
+/obj/hitbox/proc/can_cross_hitbox(datum/source, atom/mover)
+ SIGNAL_HANDLER
+ if(locate(src) in mover.loc)
+ return TRUE
+
+///Signal handler to spin the desants as well when the tank turns
+/obj/hitbox/proc/owner_turned(datum/source, old_dir, new_dir)
+ SIGNAL_HANDLER
+ if(!new_dir || new_dir == old_dir)
+ return
+ for(var/mob/living/desant AS in tank_desants)
+ if(desant.loc == root.loc)
+ continue
+ var/turf/new_pos
+ //doesnt work with diags, but that shouldnt happen, right?
+ if(REVERSE_DIR(old_dir) == new_dir)
+ new_pos = get_step(root, REVERSE_DIR(get_dir(desant, root)))
+ else if(turn(old_dir, 90) == new_dir)
+ new_pos = get_step(root, turn(get_dir(desant, root), -90))
+ else
+ new_pos = get_step(root, turn(get_dir(desant, root), 90))
+ desant.forceMove(new_pos)
+
+///signal handler when someone jumping lands on us
+/obj/hitbox/proc/on_jump_landed(datum/source, atom/lander)
+ SIGNAL_HANDLER
+ if(HAS_TRAIT(lander, TRAIT_TANK_DESANT))
+ return
+ ADD_TRAIT(lander, TRAIT_TANK_DESANT, VEHICLE_TRAIT)
+ LAZYSET(tank_desants, lander, lander.layer)
+ RegisterSignal(lander, COMSIG_QDELETING, PROC_REF(on_desant_del))
+ lander.layer = ABOVE_MOB_PLATFORM_LAYER
+
+///signal handler when we leave a turf under the hitbox
+/obj/hitbox/proc/on_exited(atom/source, atom/movable/AM, direction)
+ SIGNAL_HANDLER
+ if(!HAS_TRAIT(AM, TRAIT_TANK_DESANT))
+ return
+ if(locate(src) in AM.loc) //Î'd cut the locate but for some reason it wdoesnt work lol
+ return
+ REMOVE_TRAIT(AM, TRAIT_TANK_DESANT, VEHICLE_TRAIT)
+ AM.layer = LAZYACCESS(tank_desants, AM)
+ LAZYREMOVE(tank_desants, AM)
+ UnregisterSignal(AM, COMSIG_QDELETING)
+
+///cleanup riders on deletion
+/obj/hitbox/proc/on_desant_del(datum/source)
+ SIGNAL_HANDLER
+ LAZYREMOVE(tank_desants, source)
+
+///when root deletes is the only time we want to be deleting
+/obj/hitbox/proc/root_delete()
+ SIGNAL_HANDLER
+ qdel(src, TRUE)
+
+///when the owner moves, let's move with them!
+/obj/hitbox/proc/root_move(atom/movable/mover, atom/oldloc, direction)
+ SIGNAL_HANDLER
+ //direction is null here, so we improvise
+ direction = get_dir(oldloc, mover)
+ var/move_dist = get_dist(oldloc, mover)
+ forceMove(mover.loc)
+ for(var/mob/living/tank_desant AS in tank_desants)
+ step(tank_desant, direction, root.step_size)
+ if(isxeno(tank_desant) || move_dist > 1) //skips xenos, and
+ return
+ var/away_dir = get_dir(tank_desant, root)
+ if(!away_dir)
+ away_dir = pick(GLOB.alldirs)
+ away_dir = REVERSE_DIR(away_dir)
+ var/turf/target = get_step(get_step(root, away_dir), away_dir)
+ tank_desant.throw_at(target, 3, 3, root)
+
+///called when the tank is off movement cooldown and someone tries to move it
+/obj/hitbox/proc/on_attempt_drive(atom/movable/movable_parent, mob/living/user, direction)
+ SIGNAL_HANDLER
+ if(ISDIAGONALDIR(direction))
+ return COMPONENT_DRIVER_BLOCK_MOVE
+ if((root.dir != direction) && (root.dir != REVERSE_DIR(direction)))
+ root.setDir(direction)
+ if(isarmoredvehicle(root))
+ var/obj/vehicle/sealed/armored/armor = root
+ playsound(armor, armor.engine_sound, 100, TRUE, 20)
+ return COMPONENT_DRIVER_BLOCK_MOVE
+ //Due to this being a hot proc this part here is inlined and set on a by-hitbox-size basis
+ /////////////////////////////
+ var/turf/centerturf = get_step(get_step(root, direction), direction)
+ var/list/enteringturfs = list(centerturf)
+ enteringturfs += get_step(centerturf, turn(direction, 90))
+ enteringturfs += get_step(centerturf, turn(direction, -90))
+ /////////////////////////////
+ var/canstep = TRUE
+ for(var/turf/T AS in enteringturfs) //No break because we want to crush all the turfs before we start trying to move
+ if(!T.Enter(root, direction)) //Check if we can cross the turf first/bump the turf
+ canstep = FALSE
+
+ for(var/atom/movable/O AS in T.contents) // this is checked in turf/enter but it doesnt return false so lmao
+ if(O.CanPass(root)) // Then check for obstacles to crush
+ continue
+ root.Bump(O) //manually call bump on everything
+ canstep = FALSE
+
+ if(canstep)
+ return NONE
+ return COMPONENT_DRIVER_BLOCK_MOVE
+
+/obj/hitbox/CanAllowThrough(atom/movable/mover, turf/target)
+ . = ..()
+ if(.)
+ return
+ if((allow_pass_flags & PASS_TANK) && (mover.pass_flags & PASS_TANK))
+ return TRUE
+
+/obj/hitbox/projectile_hit(obj/projectile/proj)
+ if(proj.shot_from == root)
+ return FALSE
+ return root.projectile_hit(arglist(args))
+
+/obj/hitbox/bullet_act(obj/projectile/proj)
+ SHOULD_CALL_PARENT(FALSE) // this is an abstract object: we have to avoid everything on parent
+ SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, proj)
+ return root.bullet_act(proj)
+
+/obj/hitbox/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
+ return root.take_damage(arglist(args))
+
+/obj/hitbox/ex_act(severity)
+ return
+
+///2x2 hitbox version
+/obj/hitbox/medium
+ bound_width = 64
+ bound_height = 64
+ bound_x = 0
+ bound_y = -32
+
+/obj/hitbox/medium/on_attempt_drive(atom/movable/movable_parent, mob/living/user, direction)
+ if(ISDIAGONALDIR(direction))
+ return COMPONENT_DRIVER_BLOCK_MOVE
+ if((root.dir != direction) && (root.dir != REVERSE_DIR(direction)))
+ root.setDir(direction)
+ if(isarmoredvehicle(root))
+ var/obj/vehicle/sealed/armored/armor = root
+ playsound(armor, armor.engine_sound, 100, TRUE, 20)
+ return COMPONENT_DRIVER_BLOCK_MOVE
+ ///////////////////////////
+ var/turf/centerturf = get_step(root, direction)
+ var/list/enteringturfs = list()
+ switch(direction)
+ if(NORTH)
+ enteringturfs += get_step(centerturf, turn(direction, -90))
+ if(SOUTH)
+ centerturf = get_step(centerturf, direction)
+ enteringturfs += get_step(centerturf, turn(direction, 90))
+ if(EAST)
+ centerturf = get_step(centerturf, direction)
+ enteringturfs += get_step(centerturf, turn(direction, -90))
+ if(WEST)
+ enteringturfs += get_step(centerturf, turn(direction, 90))
+ enteringturfs += centerturf
+ ////////////////////////////////////
+ var/canstep = TRUE
+ for(var/turf/T AS in enteringturfs) //No break because we want to crush all the turfs before we start trying to move
+ if(!T.Enter(root, direction)) //Check if we can cross the turf first/bump the turf
+ canstep = FALSE
+
+ for(var/atom/movable/O AS in T.contents) // this is checked in turf/enter but it doesnt return false so lmao
+ if(O.CanPass(root)) // Then check for obstacles to crush
+ continue
+ root.Bump(O) //manually call bump on everything
+ canstep = FALSE
+
+ if(canstep)
+ return NONE
+ return COMPONENT_DRIVER_BLOCK_MOVE
diff --git a/code/modules/vehicles/armored/__armored.dm b/code/modules/vehicles/armored/__armored.dm
new file mode 100644
index 0000000000000..37dd51543c87f
--- /dev/null
+++ b/code/modules/vehicles/armored/__armored.dm
@@ -0,0 +1,619 @@
+
+/obj/vehicle/sealed/armored
+ name = "\improper MT - Shortstreet MK4"
+ desc = "An adorable chunk of metal with an alarming amount of firepower designed to crush, immolate, destroy and maim anything that Nanotrasen wants it to. This model contains advanced Bluespace technology which allows a TARDIS-like amount of room on the inside."
+ icon = 'icons/obj/armored/1x1/tinytank.dmi'
+ icon_state = "tank"
+ pixel_x = -16
+ pixel_y = -8
+ layer = ABOVE_MOB_LAYER
+ max_drivers = 1
+ move_resist = INFINITY
+ atom_flags = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION
+ allow_pass_flags = PASS_TANK|PASS_AIR|PASS_WALKOVER
+ resistance_flags = XENO_DAMAGEABLE|UNACIDABLE|PLASMACUTTER_IMMUNE|PORTAL_IMMUNE
+
+ // placeholder, make skill check or similar later
+ req_access = list(ACCESS_MARINE_MECH)
+ move_delay = 0.7 SECONDS
+ max_integrity = 600
+ light_range = 10
+ ///Tank bitflags
+ var/armored_flags = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_HEADLIGHTS
+ ///Sound file(s) to play when we drive around
+ var/engine_sound = 'sound/ambience/tank_driving.ogg'
+ ///frequency to play the sound with
+ var/engine_sound_length = 2 SECONDS
+ /// How long it takes to rev (vrrm vrrm!) TODO: merge this up to /vehicle here and on tg because of cars
+ COOLDOWN_DECLARE(enginesound_cooldown)
+
+ ///Cool and good turret overlay that allows independently swiveling guns
+ var/atom/movable/vis_obj/turret_overlay/turret_overlay
+ ///Icon for the rotating turret icon. also should hold the icons for the weapon icons
+ var/turret_icon = 'icons/obj/armored/1x1/tinytank_gun.dmi'
+ ///Iconstate for the rotating main turret
+ var/turret_icon_state = "turret"
+ ///secondary independently rotating overlay, if we only have a secondary weapon
+ var/image/secondary_weapon_overlay
+ ///Icon for the secondary rotating turret, should contain all possible icons. iconstate is fetched from the attached weapon
+ var/secondary_turret_icon
+ ///Damage overlay for when the vehicle gets damaged
+ var/atom/movable/vis_obj/tank_damage/damage_overlay
+ ///Icon file path for the damage overlay
+ var/damage_icon_path
+ ///Overlay for larger vehicles that need under parts
+ var/image/underlay
+
+ ///reference to our interior datum if set, uses the typepath its set to
+ var/datum/interior/armored/interior
+ ///Skill required to enter this vehicle
+ var/required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT
+ ///What weapon we have in our primary slot
+ var/obj/item/armored_weapon/primary_weapon
+ ///What weapon we have in our secondary slot
+ var/obj/item/armored_weapon/secondary_weapon
+ ///Our driver utility module
+ var/obj/item/tank_module/driver_utility_module
+ ///Our driver utility module
+ var/obj/item/tank_module/gunner_utility_module
+ //What kind of primary tank weaponry we start with. Defaults to a tank gun.
+ var/primary_weapon_type = /obj/item/armored_weapon
+ //What kind of secondary tank weaponry we start with. Default minigun as standard.
+ var/secondary_weapon_type = /obj/item/armored_weapon/secondary_weapon
+ ///Minimap flags to use for this vehcile
+ var/minimap_flags = MINIMAP_FLAG_MARINE
+ ///minimap iconstate to use for this vehicle
+ var/minimap_icon_state
+ ///if true disables stops users from being able to shoot weapons
+ var/weapons_safety = FALSE
+ //Bool for zoom on/off
+ var/zoom_mode = FALSE
+ /// damage done by rams
+ var/ram_damage = 20
+
+/obj/vehicle/sealed/armored/Initialize(mapload)
+ if(interior)
+ interior = new interior(src, CALLBACK(src, PROC_REF(interior_exit)))
+ . = ..()
+ if(armored_flags & ARMORED_HAS_UNDERLAY)
+ underlay = new(icon, icon_state + "_underlay", layer = layer-0.1)
+ add_overlay(underlay)
+ if(damage_icon_path)
+ damage_overlay = new()
+ damage_overlay.icon = damage_icon_path
+ damage_overlay.layer = layer+0.001
+ vis_contents += damage_overlay
+ if(armored_flags & ARMORED_HAS_PRIMARY_WEAPON)
+ turret_overlay = new()
+ turret_overlay.icon = turret_icon
+ turret_overlay.icon_state = turret_icon_state
+ turret_overlay.setDir(dir)
+ turret_overlay.layer = layer+0.002
+ if(armored_flags & ARMORED_HAS_MAP_VARIANTS)
+ switch(SSmapping.configs[GROUND_MAP].armor_style)
+ if(MAP_ARMOR_STYLE_JUNGLE)
+ turret_overlay.icon_state += "_jungle"
+ if(MAP_ARMOR_STYLE_ICE)
+ turret_overlay.icon_state += "_snow"
+ if(MAP_ARMOR_STYLE_PRISON)
+ turret_overlay.icon_state += "_urban"
+ if(MAP_ARMOR_STYLE_DESERT)
+ turret_overlay.icon_state += "_desert"
+ vis_contents += turret_overlay
+ if(primary_weapon_type)
+ var/obj/item/armored_weapon/primary = new primary_weapon_type(src)
+ primary.attach(src, TRUE)
+ if(armored_flags & ARMORED_HAS_SECONDARY_WEAPON)
+ if(secondary_weapon_type)
+ var/obj/item/armored_weapon/secondary = new secondary_weapon_type(src)
+ secondary.attach(src, FALSE)
+ if(armored_flags & ARMORED_HAS_MAP_VARIANTS)
+ switch(SSmapping.configs[GROUND_MAP].armor_style)
+ if(MAP_ARMOR_STYLE_JUNGLE)
+ icon_state += "_jungle"
+ if(MAP_ARMOR_STYLE_ICE)
+ icon_state += "_snow"
+ if(MAP_ARMOR_STYLE_PRISON)
+ icon_state += "_urban"
+ if(MAP_ARMOR_STYLE_DESERT)
+ icon_state += "_desert"
+ if(minimap_icon_state)
+ SSminimaps.add_marker(src, minimap_flags, image('icons/UI_icons/map_blips_large.dmi', null, minimap_icon_state, HIGH_FLOAT_LAYER))
+ GLOB.tank_list += src
+
+/obj/vehicle/sealed/armored/Destroy()
+ QDEL_NULL(primary_weapon)
+ QDEL_NULL(secondary_weapon)
+ QDEL_NULL(driver_utility_module)
+ QDEL_NULL(gunner_utility_module)
+ QDEL_NULL(damage_overlay)
+ QDEL_NULL(turret_overlay)
+ QDEL_NULL(interior)
+ underlay = null
+ GLOB.tank_list -= src
+ return ..()
+
+/obj/vehicle/sealed/armored/generate_actions()
+ if(armored_flags & ARMORED_HAS_HEADLIGHTS)
+ initialize_controller_action_type(/datum/action/vehicle/sealed/armored/toggle_lights, VEHICLE_CONTROL_SETTINGS)
+ if(interior)
+ return
+ initialize_passenger_action_type(/datum/action/vehicle/sealed/armored/eject)
+ if(max_occupants > 1)
+ initialize_passenger_action_type(/datum/action/vehicle/sealed/armored/swap_seat)
+
+/obj/vehicle/sealed/armored/obj_destruction(damage_amount, damage_type, damage_flag)
+ . = ..()
+ playsound(get_turf(src), 'sound/weapons/guns/fire/tank_cannon1.ogg', 100, TRUE)
+
+/obj/vehicle/sealed/armored/update_icon()
+ . = ..()
+ if(!damage_overlay)
+ return
+ switch(PERCENT(obj_integrity / max_integrity))
+ if(0 to 29)
+ damage_overlay.icon_state = "damage_veryhigh"
+ if(29 to 59)
+ damage_overlay.icon_state = "damage_high"
+ if(59 to 70)
+ damage_overlay.icon_state = "damage_medium"
+ if(70 to 90)
+ damage_overlay.icon_state = "damage_small"
+ else
+ damage_overlay.icon_state = "null"
+
+/obj/vehicle/sealed/armored/update_overlays()
+ . = ..()
+ if(secondary_weapon_overlay)
+ . += secondary_weapon_overlay
+
+/obj/vehicle/sealed/armored/setDir(newdir)
+ . = ..()
+ if(secondary_weapon_overlay)
+ cut_overlay(secondary_weapon_overlay)
+ secondary_weapon_overlay.icon_state = secondary_weapon.icon_state + "_" + "[newdir]"
+ add_overlay(secondary_weapon_overlay)
+
+/obj/vehicle/sealed/armored/examine(mob/user)
+ . = ..()
+ if(!isxeno(user))
+ . += "To fire its main cannon, left click a tile."
+ . += "To fire its secondary weapon, right click a tile."
+ . += "Middle click to toggle weapon safety."
+ . += "It's currently holding [LAZYLEN(occupants)]/[max_occupants] crew."
+ . += span_notice("There is [isnull(primary_weapon) ? "nothing" : "[primary_weapon]"] in the primary attachment point, [isnull(secondary_weapon) ? "nothing" : "[secondary_weapon]"] installed in the secondary slot, [isnull(driver_utility_module) ? "nothing" : "[driver_utility_module]"] in the driver utility slot and [isnull(gunner_utility_module) ? "nothing" : "[gunner_utility_module]"] in the gunner utility slot.")
+ if(!isxeno(user))
+ . += "It is currently at [PERCENT(obj_integrity / max_integrity)]% integrity."
+
+/obj/vehicle/sealed/armored/vehicle_move(mob/living/user, direction)
+ . = ..()
+ if(!.)
+ return
+ if(COOLDOWN_CHECK(src, enginesound_cooldown))
+ COOLDOWN_START(src, enginesound_cooldown, engine_sound_length)
+ playsound(get_turf(src), engine_sound, 100, TRUE, 20)
+ after_move(direction)
+ forceMove(get_step(src, direction)) // still animates and calls moved() and all that stuff BUT we skip checks
+
+/obj/vehicle/sealed/armored/resisted_against(mob/living/user)
+ balloon_alert(user, "exiting...")
+ if(do_after(user, enter_delay, NONE, src))
+ balloon_alert(user, "exited")
+ mob_exit(user, TRUE)
+
+/obj/vehicle/sealed/armored/CanAllowThrough(atom/movable/mover, turf/target)
+ . = ..()
+ if(.)
+ return
+ if((allow_pass_flags & PASS_TANK) && (mover.pass_flags & PASS_TANK))
+ return TRUE
+
+/obj/vehicle/sealed/armored/Bump(atom/A)
+ . = ..()
+ if(HAS_TRAIT(A, TRAIT_STOPS_TANK_COLLISION))
+ if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_VEHICLE_CRUSHSOUND))
+ visible_message(span_danger("[src] is stopped by [A]!"))
+ playsound(src, 'sound/effects/metal_crash.ogg', 45)
+ TIMER_COOLDOWN_START(src, COOLDOWN_VEHICLE_CRUSHSOUND, 1 SECONDS)
+ return
+ var/pilot
+ var/list/drivers = return_drivers()
+ if(length(drivers))
+ pilot = drivers[1]
+ A.vehicle_collision(src, get_dir(src, A), get_turf(loc), get_turf(loc), pilot)
+
+/obj/vehicle/sealed/armored/auto_assign_occupant_flags(mob/new_occupant)
+ if(interior) //handled by interior seats
+ return
+ if(max_occupants == 1)
+ add_control_flags(new_occupant, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS|VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+ return
+
+ if(driver_amount() < max_drivers) //movement controllers
+ add_control_flags(new_occupant, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ else if(length(return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)) < 1)
+ add_control_flags(new_occupant, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+
+/obj/vehicle/sealed/armored/exit_location(mob/M)
+ return get_step(src, REVERSE_DIR(dir))
+
+///called when a mob tried to leave our interior
+/obj/vehicle/sealed/armored/proc/interior_exit(mob/leaver, datum/interior/inside, teleport)
+ if(!teleport)
+ remove_occupant(leaver)
+ return
+ mob_exit(leaver, TRUE)
+
+/obj/vehicle/sealed/armored/mob_try_enter(mob/M)
+ if(isobserver(M))
+ interior?.mob_enter(M)
+ return FALSE
+ if(!ishuman(M))
+ return FALSE
+ if(M.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ return FALSE
+ return ..()
+
+/obj/vehicle/sealed/armored/enter_checks(mob/M)
+ . = ..()
+ if(!.)
+ return
+ if(LAZYLEN(M.buckled_mobs))
+ balloon_alert(M, "remove riders first")
+ return FALSE
+
+/obj/vehicle/sealed/armored/add_occupant(mob/M, control_flags)
+ if(!interior)
+ RegisterSignal(M, COMSIG_MOB_DEATH, PROC_REF(mob_exit), TRUE)
+ RegisterSignal(M, COMSIG_LIVING_DO_RESIST, TYPE_PROC_REF(/atom/movable, resisted_against), TRUE)
+ . = ..()
+ if(primary_weapon)
+ var/list/primary_icons
+ if(primary_weapon.ammo)
+ primary_icons = list(primary_weapon.ammo.default_ammo.hud_state, primary_weapon.ammo.default_ammo.hud_state_empty)
+ else
+ primary_icons = list(primary_weapon.hud_state_empty, primary_weapon.hud_state_empty)
+ M.hud_used.add_ammo_hud(primary_weapon, primary_icons, primary_weapon.ammo.current_rounds)
+ if(secondary_weapon)
+ var/list/secondary_icons
+ if(secondary_weapon.ammo)
+ secondary_icons = list(secondary_weapon.ammo.default_ammo.hud_state, secondary_weapon.ammo.default_ammo.hud_state_empty)
+ else
+ secondary_icons = list(secondary_weapon.hud_state_empty, secondary_weapon.hud_state_empty)
+ M.hud_used.add_ammo_hud(secondary_weapon, secondary_icons, secondary_weapon.ammo.current_rounds)
+
+/obj/vehicle/sealed/armored/after_add_occupant(mob/M)
+ . = ..()
+ if(interior)
+ REMOVE_TRAIT(M, TRAIT_HANDS_BLOCKED, VEHICLE_TRAIT)
+
+/obj/vehicle/sealed/armored/grant_controller_actions_by_flag(mob/M, flag)
+ . = ..()
+ if(. && (flag & VEHICLE_CONTROL_EQUIPMENT))
+ RegisterSignal(M, COMSIG_MOB_MOUSEDOWN, PROC_REF(on_mouseclick), TRUE)
+
+/obj/vehicle/sealed/armored/remove_controller_actions_by_flag(mob/M, flag)
+ . = ..()
+ if(. && (flag & VEHICLE_CONTROL_EQUIPMENT))
+ UnregisterSignal(M, COMSIG_MOB_MOUSEDOWN)
+
+/obj/vehicle/sealed/armored/remove_occupant(mob/M)
+ M.hud_used.remove_ammo_hud(primary_weapon)
+ M.hud_used.remove_ammo_hud(secondary_weapon)
+ UnregisterSignal(M, COMSIG_MOB_DEATH)
+ UnregisterSignal(M, COMSIG_LIVING_DO_RESIST)
+ return ..()
+
+/obj/vehicle/sealed/armored/relaymove(mob/living/user, direction)
+ . = ..()
+ if(!is_driver(user) && is_equipment_controller(user))
+ swivel_turret(null, direction)
+
+/obj/vehicle/sealed/armored/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing)
+ for(var/mob/living/carbon/human/crew AS in occupants)
+ if(crew.wear_id?.iff_signal & proj.iff_signal)
+ return FALSE
+ return ..()
+
+/obj/vehicle/sealed/armored/attack_hand(mob/living/user)
+ . = ..()
+ if(interior) // handled by gun breech
+ return
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(!primary_weapon)
+ balloon_alert(user, "no primary")
+ return
+ if(!length(primary_weapon.ammo_magazine))
+ balloon_alert(user, "magazine empty")
+ return
+ var/choice
+ if(length(primary_weapon.ammo_magazine) == 1)
+ choice = primary_weapon.ammo_magazine[1]
+ else
+ choice = tgui_input_list(user, "Select a magazine to take out", primary_weapon.name, primary_weapon.ammo_magazine)
+ if(!choice)
+ return
+ if(!do_after(user, 1 SECONDS, NONE, src))
+ return
+ balloon_alert(user, "magazine removed")
+ primary_weapon.ammo_magazine -= choice
+ user.put_in_hands(choice)
+
+/obj/vehicle/sealed/armored/attack_hand_alternate(mob/living/user)
+ . = ..()
+ if(interior) // handled by gun breech
+ return
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(!secondary_weapon)
+ balloon_alert(user, "no secondary")
+ return
+ if(!length(secondary_weapon.ammo_magazine))
+ balloon_alert(user, "magazine empty")
+ return
+ var/choice
+ if(length(secondary_weapon.ammo_magazine) == 1)
+ choice = secondary_weapon.ammo_magazine[1]
+ else
+ choice = tgui_input_list(user, "Select a magazine to take out", secondary_weapon.name, secondary_weapon.ammo_magazine)
+ if(!choice)
+ return
+ if(!do_after(user, 1 SECONDS, NONE, src))
+ return
+ balloon_alert(user, "magazine removed")
+ secondary_weapon.ammo_magazine -= choice
+ user.put_in_hands(choice)
+
+/obj/vehicle/sealed/armored/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if(istype(I, /obj/item/armored_weapon))
+ var/obj/item/armored_weapon/gun = I
+ if(!(gun.weapon_slot & MODULE_PRIMARY))
+ balloon_alert(user, "not a primary weapon")
+ return
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ user.temporarilyRemoveItemFromInventory(I)
+ gun.attach(src, TRUE)
+ return
+ if(istype(I, /obj/item/tank_module))
+ var/obj/item/tank_module/mod = I
+ mod.on_equip(src, user)
+ return
+ if(interior) // if interior handle by gun breech
+ return
+ if(istype(I, /obj/item/ammo_magazine))
+ if(!primary_weapon)
+ balloon_alert(user, "no primary weapon")
+ return
+ if(!(I.type in primary_weapon.accepted_ammo))
+ balloon_alert(user, "not accepted ammo")
+ return
+ if(length(primary_weapon.ammo_magazine) >= primary_weapon.maximum_magazines)
+ balloon_alert(user, "magazine already full")
+ return
+ user.temporarilyRemoveItemFromInventory(I)
+ I.forceMove(primary_weapon)
+ if(!primary_weapon.ammo)
+ primary_weapon.ammo = I
+ balloon_alert(user, "primary gun loaded")
+ for(var/mob/occupant AS in occupants)
+ occupant.hud_used.update_ammo_hud(primary_weapon, list(primary_weapon.ammo.default_ammo.hud_state, primary_weapon.ammo.default_ammo.hud_state_empty), primary_weapon.ammo.current_rounds)
+ else
+ primary_weapon.ammo_magazine += I
+ balloon_alert(user, "magazines [length(primary_weapon.ammo_magazine)]/[primary_weapon.maximum_magazines]")
+
+/obj/vehicle/sealed/armored/attackby_alternate(obj/item/I, mob/user, params)
+ . = ..()
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(istype(I, /obj/item/armored_weapon))
+ var/obj/item/armored_weapon/gun = I
+ if(!(gun.weapon_slot & MODULE_SECONDARY))
+ balloon_alert(user, "not a secondary weapon")
+ return
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ user.temporarilyRemoveItemFromInventory(I)
+ gun.attach(src, FALSE)
+ return
+ if(isscrewdriver(I))
+ if(!gunner_utility_module)
+ balloon_alert(user, "no gunner utility module")
+ return
+ balloon_alert(user, "detaching gunner utility")
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ gunner_utility_module.on_unequip(user)
+ balloon_alert(user, "detached")
+ return
+ if(interior) // if interior handle by gun breech
+ return
+ if(istype(I, /obj/item/ammo_magazine))
+ if(!secondary_weapon)
+ balloon_alert(user, "no primary weapon")
+ return
+ if(!(I.type in secondary_weapon.accepted_ammo))
+ balloon_alert(user, "not accepted ammo")
+ return
+ if(length(secondary_weapon.ammo_magazine) >= secondary_weapon.maximum_magazines)
+ balloon_alert(user, "magazine already full")
+ return
+ user.temporarilyRemoveItemFromInventory(I)
+ I.forceMove(secondary_weapon)
+ if(!secondary_weapon.ammo)
+ secondary_weapon.ammo = I
+ balloon_alert(user, "secondary gun loaded")
+ for(var/mob/occupant AS in occupants)
+ occupant.hud_used.update_ammo_hud(secondary_weapon, list(secondary_weapon.ammo.default_ammo.hud_state, secondary_weapon.ammo.default_ammo.hud_state_empty), secondary_weapon.ammo.current_rounds)
+ else
+ secondary_weapon.ammo_magazine += I
+ balloon_alert(user, "magazines [length(secondary_weapon.ammo_magazine)]/[secondary_weapon.maximum_magazines]")
+
+
+/obj/vehicle/sealed/armored/welder_act(mob/living/user, obj/item/I)
+ return welder_repair_act(user, I, 50, 5 SECONDS, 0, SKILL_ENGINEER_METAL, 5, 2 SECONDS)
+
+/obj/vehicle/sealed/armored/crowbar_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(!primary_weapon)
+ balloon_alert(user, "no primary weapon")
+ return
+ balloon_alert(user, "detaching primary")
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ var/obj/item/armored_weapon/gun = primary_weapon
+ primary_weapon.detach(loc)
+ user.put_in_hands(gun)
+ balloon_alert(user, "detached")
+
+/obj/vehicle/sealed/armored/wrench_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(!secondary_weapon)
+ balloon_alert(user, "no secondary weapon")
+ return
+ balloon_alert(user, "detaching secondary")
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ var/obj/item/armored_weapon/gun = secondary_weapon
+ secondary_weapon.detach(loc)
+ user.put_in_hands(gun)
+ balloon_alert(user, "detached")
+
+/obj/vehicle/sealed/armored/screwdriver_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill)
+ balloon_alert(user, "not enough skill")
+ return
+ if(!driver_utility_module)
+ balloon_alert(user, "no driver utility module")
+ return
+ balloon_alert(user, "detaching driver utility")
+ if(!do_after(user, 2 SECONDS, NONE, src))
+ return
+ driver_utility_module.on_unequip(user)
+ balloon_alert(user, "detached")
+
+/obj/vehicle/sealed/armored/plastique_act(mob/living/plastique_user)
+ ex_act(EXPLODE_LIGHT)
+
+/**
+ * Toggles Weapons Safety
+ *
+ * Handles enabling or disabling the safety function.
+ */
+/obj/vehicle/sealed/armored/proc/set_safety(mob/user)
+ weapons_safety = !weapons_safety
+ SEND_SOUND(user, sound('sound/machines/beep.ogg', volume = 25))
+ balloon_alert(user, "equipment [weapons_safety ? "safe" : "ready"]")
+ // todo maybe make tanks also update the mouse icon?
+
+///Rotates the cannon overlay
+/obj/vehicle/sealed/armored/proc/swivel_turret(atom/A, new_weapon_dir)
+ if(!new_weapon_dir)
+ new_weapon_dir = angle_to_cardinal_dir(Get_Angle(get_turf(src), get_turf(A)))
+ if(turret_overlay.dir == new_weapon_dir)
+ return FALSE
+ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_TANK_SWIVEL)) //Slight cooldown to avoid spam
+ return FALSE
+ playsound(src, 'sound/effects/tankswivel.ogg', 80,1)
+ TIMER_COOLDOWN_START(src, COOLDOWN_TANK_SWIVEL, 3 SECONDS)
+ turret_overlay.setDir(new_weapon_dir)
+ return TRUE
+
+///handles mouseclicks by a user in the vehicle
+/obj/vehicle/sealed/armored/proc/on_mouseclick(mob/user, atom/target, turf/location, control, list/modifiers)
+ SIGNAL_HANDLER
+ modifiers = params2list(modifiers)
+ if(isnull(location) && target.plane == CLICKCATCHER_PLANE) //Checks if the intended target is in deep darkness and adjusts target based on params.
+ target = params2turf(modifiers["screen-loc"], get_turf(user), user.client)
+ modifiers["icon-x"] = num2text(ABS_PIXEL_TO_REL(text2num(modifiers["icon-x"])))
+ modifiers["icon-y"] = num2text(ABS_PIXEL_TO_REL(text2num(modifiers["icon-y"])))
+ if(modifiers[SHIFT_CLICK]) //Allows things to be examined.
+ return
+ if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled
+ return
+ if(HAS_TRAIT(user, TRAIT_INCAPACITATED))
+ return
+ if(src == target)
+ return
+ if(!is_equipment_controller(user))
+ balloon_alert(user, "wrong seat for equipment!")
+ return COMSIG_MOB_CLICK_CANCELED
+ if(LAZYACCESS(modifiers, MIDDLE_CLICK))
+ set_safety(user)
+ return COMSIG_MOB_CLICK_CANCELED
+ var/dir_to_target = get_cardinal_dir(src, target)
+ var/obj/item/armored_weapon/selected
+ if(modifiers[BUTTON] == RIGHT_CLICK)
+ selected = secondary_weapon
+ else
+ if(!turret_overlay)
+ return COMSIG_MOB_CLICK_CANCELED
+ if(turret_overlay.dir != dir_to_target)
+ swivel_turret(target)
+ return COMSIG_MOB_CLICK_CANCELED
+ selected = primary_weapon
+ if(!selected)
+ return
+ if(weapons_safety || zoom_mode)
+ return
+ INVOKE_ASYNC(selected, TYPE_PROC_REF(/obj/item/armored_weapon, begin_fire), user, target, modifiers)
+
+/atom/movable/vis_obj/turret_overlay
+ name = "Tank gun turret"
+ desc = "The shooty bit on a tank."
+ icon = 'icons/obj/armored/3x3/tank_gun.dmi' //set by owner
+ icon_state = "turret"
+ layer = ABOVE_ALL_MOB_LAYER
+ ///overlay for the attached gun
+ var/image/gun_overlay
+ ///overlay for the shooting version of that gun
+ var/image/flash_overlay
+ ///currently using the flashing overlay
+ var/flashing = FALSE
+ ///icon state for the secondary
+ var/image/secondary_overlay
+
+/atom/movable/vis_obj/turret_overlay/proc/update_gun_overlay(gun_icon_state)
+ cut_overlays()
+ if(!gun_icon_state)
+ flash_overlay = null
+ gun_overlay = null
+ return
+ flashing = FALSE
+ flash_overlay = image(icon, gun_icon_state + "_fire", pixel_x = -70, pixel_y = -69)
+ gun_overlay = image(icon, gun_icon_state, pixel_x = -40, pixel_y = -48)
+ update_appearance(UPDATE_OVERLAYS)
+
+/atom/movable/vis_obj/turret_overlay/proc/set_flashing(new_flashing)
+ flashing = new_flashing
+ update_appearance(UPDATE_OVERLAYS)
+
+/atom/movable/vis_obj/turret_overlay/update_overlays()
+ . = ..()
+ . += (flashing ? flash_overlay : gun_overlay)
+
+/atom/movable/vis_obj/turret_overlay/setDir(newdir)
+ . = ..()
+ if(secondary_overlay)
+ cut_overlay(secondary_overlay)
+ secondary_overlay.icon_state = copytext(secondary_overlay.icon_state, 1, length(secondary_overlay.icon_state)) + "[dir]"
+ add_overlay(secondary_overlay)
+
+/atom/movable/vis_obj/tank_damage
+ name = "Tank damage overlay"
+ desc = "ow."
+ icon = 'icons/obj/armored/3x3/tank_damage.dmi' //set by owner
+ icon_state = "null" // set on demand
+ vis_flags = VIS_INHERIT_DIR
diff --git a/code/modules/vehicles/armored/_multitile.dm b/code/modules/vehicles/armored/_multitile.dm
new file mode 100644
index 0000000000000..15130efacd889
--- /dev/null
+++ b/code/modules/vehicles/armored/_multitile.dm
@@ -0,0 +1,41 @@
+/obj/vehicle/sealed/armored/multitile
+ name = "\improper MT - Ares"
+ desc = "A gigantic wall of metal designed for maximum Xeno destruction. Drag yourself onto it at an entrance to get inside."
+ icon = 'icons/obj/armored/3x3/tank.dmi'
+ turret_icon = 'icons/obj/armored/3x3/tank_gun.dmi'
+ secondary_turret_icon = 'icons/obj/armored/3x3/tank_secondary_gun.dmi'
+ damage_icon_path = 'icons/obj/armored/3x3/tank_damage.dmi'
+ icon_state = "tank"
+ hitbox = /obj/hitbox
+ interior = /datum/interior/armored
+ minimap_icon_state = "tank"
+ required_entry_skill = SKILL_LARGE_VEHICLE_TRAINED
+ atom_flags = DIRLOCK|BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION
+ armored_flags = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_SECONDARY_WEAPON|ARMORED_HAS_UNDERLAY|ARMORED_HAS_MAP_VARIANTS|ARMORED_HAS_HEADLIGHTS
+ pixel_x = -48
+ pixel_y = -48
+ max_integrity = 900
+ soft_armor = list(MELEE = 50, BULLET = 100 , LASER = 90, ENERGY = 60, BOMB = 60, BIO = 60, FIRE = 50, ACID = 50)
+ hard_armor = list(MELEE = 0, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0)
+ max_occupants = 4
+ move_delay = 0.9 SECONDS
+ ram_damage = 100
+
+///returns a list of possible locations that this vehicle may be entered from
+/obj/vehicle/sealed/armored/multitile/proc/enter_locations(mob/M)
+ return list(get_step_away(get_step(src, REVERSE_DIR(dir)), src, 2))
+
+/obj/vehicle/sealed/armored/multitile/exit_location(mob/M)
+ return pick(enter_locations(M))
+
+/obj/vehicle/sealed/armored/multitile/mob_try_enter(mob/M)
+ if(!isobserver(M) && !(M.loc in enter_locations(M)))
+ balloon_alert(M, "Not at entrance")
+ return FALSE
+ return ..()
+
+/obj/vehicle/sealed/armored/multitile/enter_checks(mob/M)
+ . = ..()
+ if(!.)
+ return
+ return (M.loc in enter_locations(M))
diff --git a/code/modules/vehicles/armored/ammo_magazine.dm b/code/modules/vehicles/armored/ammo_magazine.dm
new file mode 100644
index 0000000000000..b8037f3112763
--- /dev/null
+++ b/code/modules/vehicles/armored/ammo_magazine.dm
@@ -0,0 +1,84 @@
+//FEB 2024 NOTE: some of these are missing loading_sounds, fix it before using these ingame
+//Special ammo magazines for hardpoint modules. Some may not be here since you can use normal magazines on them
+/obj/item/ammo_magazine/tank
+ magazine_flags = NONE
+ ///loading sound to play when
+ var/loading_sound
+
+/obj/item/ammo_magazine/tank/ltb_cannon
+ name = "high explosive LTB round"
+ desc = "A primary armament cannon magazine"
+ caliber = CALIBER_84MM
+ icon_state = "ltbammo"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/rocket/ltb
+ max_rounds = 1
+ loading_sound = 'sound/vehicles/weapons/ltb_reload.ogg'
+
+/obj/item/ammo_magazine/tank/ltaap_chaingun
+ name = "\improper LTA-AP chaingun Magazine"
+ desc = "A primary armament chaingun magazine."
+ caliber = CALIBER_762X51
+ icon_state = "ltaap"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/bullet/minigun/ltaap
+ max_rounds = 150
+ loading_sound = 'sound/weapons/guns/interact/working_the_bolt.ogg'
+
+
+/obj/item/ammo_magazine/tank/flamer
+ name = "Flamer Magazine"
+ desc = "A secondary armament flamethrower magazine"
+ caliber = CALIBER_FUEL_THICK
+ icon_state = "flametank_large"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/flamethrower/tank_flamer
+ max_rounds = 120
+
+/obj/item/ammo_magazine/tank/towlauncher
+ name = "TOW Launcher Magazine"
+ desc = "A secondary armament rocket magazine"
+ caliber = CALIBER_68MM
+ icon_state = "quad_rocket"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/rocket/ap //Fun fact, AP rockets seem to be a straight downgrade from normal rockets. Maybe I'm missing something...
+ max_rounds = 5
+
+/obj/item/ammo_magazine/tank/secondary_cupola
+ name = "HSG-102 Cupola Magazine"
+ desc = "A secondary armament MG magazine"
+ caliber = CALIBER_10X28
+ icon_state = "cupolaammo"
+ loading_sound = 'sound/weapons/guns/interact/working_the_bolt.ogg'
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/bullet/cupola
+ max_rounds = 75
+
+/obj/item/ammo_magazine/tank/tank_glauncher
+ name = "Grenade Launcher Magazine"
+ desc = "A secondary armament grenade magazine"
+ caliber = CALIBER_40MM
+ icon_state = "glauncher_2"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/grenade_container
+ max_rounds = 10
+
+/obj/item/ammo_magazine/tank/tank_glauncher/update_icon_state()
+ if(current_rounds >= max_rounds)
+ icon_state = "glauncher_2"
+ else if(current_rounds <= 0)
+ icon_state = "glauncher_0"
+ else
+ icon_state = "glauncher_1"
+
+/obj/item/ammo_magazine/tank/tank_slauncher
+ name = "Smoke Launcher Magazine"
+ desc = "A support armament grenade magazine"
+ caliber = CALIBER_40MM
+ icon_state = "slauncher_1"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ default_ammo = /datum/ammo/grenade_container/smoke
+ max_rounds = 6
+
+/obj/item/ammo_magazine/tank/tank_slauncher/update_icon_state()
+ icon_state = "slauncher_[current_rounds <= 0 ? "0" : "1"]"
diff --git a/code/modules/vehicles/armored/apc.dm b/code/modules/vehicles/armored/apc.dm
new file mode 100644
index 0000000000000..2400c6db6fd87
--- /dev/null
+++ b/code/modules/vehicles/armored/apc.dm
@@ -0,0 +1,21 @@
+/obj/vehicle/sealed/armored/multitile/apc
+ name = "\improper APC - Athena"
+ desc = "An unarmed command APC designed to command and transport troops in the battlefield."
+ icon = 'icons/obj/armored/3x3/apc.dmi'
+ icon_state = "apc"
+ damage_icon_path = 'icons/obj/armored/3x3/apc_damage_overlay.dmi'
+ armored_flags = ARMORED_HAS_HEADLIGHTS
+ required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT
+ minimap_icon_state = null
+ turret_icon = null
+ interior = null
+ secondary_turret_icon = null
+ primary_weapon_type = null
+ secondary_weapon_type = null
+ armored_flags = NONE
+ pixel_x = -48
+ pixel_y = -40
+ obj_integrity = 2000
+ max_integrity = 2000
+ max_occupants = 10 //Clown car? Clown car.
+ move_delay = 0.5 SECONDS
diff --git a/code/modules/vehicles/armored/armored_actions.dm b/code/modules/vehicles/armored/armored_actions.dm
new file mode 100644
index 0000000000000..d369b442f3006
--- /dev/null
+++ b/code/modules/vehicles/armored/armored_actions.dm
@@ -0,0 +1,134 @@
+/obj/vehicle/sealed/armored/generate_action_type()
+ . = ..()
+ if(istype(., /datum/action/vehicle/sealed/armored))
+ var/datum/action/vehicle/sealed/armored/armor = .
+ armor.chassis = src
+
+///yes this is a blatant mech copypaste
+/datum/action/vehicle/sealed/armored
+ action_icon = 'icons/mob/actions/actions_mecha.dmi'
+ ///mech owner of this action
+ var/obj/vehicle/sealed/armored/chassis
+
+/datum/action/vehicle/sealed/armored/Destroy()
+ chassis = null
+ return ..()
+
+/datum/action/vehicle/sealed/armored/eject
+ name = "Eject From Mech"
+ action_icon_state = "mech_eject"
+
+/datum/action/vehicle/sealed/armored/eject/action_activate(trigger_flags)
+ if(!owner)
+ return
+ if(!chassis || !(owner in chassis.occupants))
+ return
+ chassis.resisted_against(owner)
+
+/datum/action/vehicle/sealed/armored/swap_seat
+ name = "Switch Seats"
+ action_icon_state = "mech_seat_swap"
+
+#define ARMOR_DRIVER "Driver"
+#define ARMOR_GUNNER "Gunner"
+#define ARMOR_PASSENGER "Passenger"
+
+/datum/action/vehicle/sealed/armored/swap_seat/action_activate(trigger_flags)
+ if(!transfer_checks())
+ return
+ var/list/choices = list()
+ if(!chassis.is_driver(owner))
+ choices += ARMOR_DRIVER
+ if(!chassis.is_equipment_controller(owner))
+ choices += ARMOR_GUNNER
+ choices += ARMOR_PASSENGER
+ var/choice = tgui_input_list(owner, "Select a seat", chassis.name, choices)
+ if(!choice)
+ return
+ if(!transfer_checks(choice))
+ return
+ chassis.balloon_alert(owner, "moving to other seat...")
+ if(!do_after(owner, chassis.enter_delay, target = chassis, extra_checks=CALLBACK(src, PROC_REF(transfer_checks), choice)))
+ chassis.balloon_alert(owner, "interrupted!")
+ return
+ chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT|VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ switch(choice)
+ if(ARMOR_GUNNER)
+ chassis.balloon_alert(owner, "controlling gunner seat")
+ chassis.add_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+ if(ARMOR_DRIVER)
+ chassis.balloon_alert(owner, "controlling pilot seat")
+ chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ if(ARMOR_PASSENGER)
+ chassis.balloon_alert(owner, "entered passenger seat")
+
+///checks if owner can still transfer
+/datum/action/vehicle/sealed/armored/swap_seat/proc/transfer_checks(choice)
+ if(!owner || !chassis || !(owner in chassis.occupants))
+ return FALSE
+ if(length(chassis.occupants) >= chassis.max_occupants)
+ chassis.balloon_alert(owner, "other seats occupied!")
+ return FALSE
+ switch(choice)
+ if(ARMOR_GUNNER)
+ if(length(chassis.return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)) >= 1)
+ chassis.balloon_alert(owner, "gunner occupied!")
+ return FALSE
+ if(ARMOR_DRIVER)
+ if(chassis.driver_amount() >= chassis.max_drivers)
+ chassis.balloon_alert(owner, "driver occupied!")
+ return FALSE
+ return TRUE
+
+#undef ARMOR_DRIVER
+#undef ARMOR_GUNNER
+#undef ARMOR_PASSENGER
+
+/datum/action/vehicle/sealed/armored/toggle_lights
+ name = "Toggle Lights"
+ action_icon_state = "mech_lights_off"
+
+/datum/action/vehicle/sealed/armored/toggle_lights/action_activate(trigger_flags)
+ if(!owner || !chassis || !(owner in chassis.occupants))
+ return
+
+ if(!(chassis.armored_flags & ARMORED_HAS_HEADLIGHTS))
+ chassis.balloon_alert(owner, "the vehicle's lights are broken!")
+ return
+ chassis.armored_flags ^= ARMORED_LIGHTS_ON
+ if(chassis.armored_flags & ARMORED_LIGHTS_ON)
+ action_icon_state = "mech_lights_on"
+ else
+ action_icon_state = "mech_lights_off"
+ chassis.set_light_on(chassis.armored_flags & ARMORED_LIGHTS_ON)
+ chassis.balloon_alert(owner, "toggled lights [chassis.armored_flags & ARMORED_LIGHTS_ON ? "on":"off"]")
+ playsound(chassis,'sound/mecha/brass_skewer.ogg', 40, TRUE)
+ chassis.log_message("Toggled lights [(chassis.armored_flags & ARMORED_LIGHTS_ON)?"on":"off"].", LOG_MECHA)
+ update_button_icon()
+
+/datum/action/vehicle/sealed/armored/zoom
+ name = "Zoom"
+ action_icon_state = "mech_zoom_off"
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_MECHABILITY_TOGGLE_ZOOM,
+ )
+
+/datum/action/vehicle/sealed/armored/zoom/action_activate(trigger_flags)
+ if(!owner?.client || !chassis || !(owner in chassis.occupants))
+ return
+ chassis.zoom_mode = !chassis.zoom_mode
+ action_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]"
+ chassis.log_message("Toggled zoom mode.", LOG_MECHA)
+ to_chat(owner, "Zoom mode [chassis.zoom_mode?"en":"dis"]abled.")
+ if(chassis.zoom_mode)
+ owner.client.view_size.set_view_radius_to(4.5)
+ SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg', volume=50))
+ else
+ owner.client.view_size.reset_to_default()
+ update_button_icon()
+
+/datum/action/vehicle/sealed/armored/zoom/remove_action(mob/M)
+ if(chassis.zoom_mode)
+ M.client.view_size.reset_to_default()
+ chassis.zoom_mode = FALSE
+ return ..()
diff --git a/code/modules/vehicles/armored/armored_modules.dm b/code/modules/vehicles/armored/armored_modules.dm
new file mode 100644
index 0000000000000..79209699cc326
--- /dev/null
+++ b/code/modules/vehicles/armored/armored_modules.dm
@@ -0,0 +1,127 @@
+/**
+ *TANK MODULES
+ *
+ * Attached to the tank and provide abilities/ passive upgrades
+ */
+/obj/item/tank_module
+ name = "Tank Module"
+ desc = "Yell at the admin that spawned this in please."
+ icon = 'icons/obj/armored/hardpoint_modules.dmi'
+ icon_state = "ltb_cannon"
+ ///reference to current overlay added to owner
+ var/image/overlay
+ ///vehicle this overlay is attached to
+ var/obj/vehicle/sealed/armored/owner
+ ///Bool whether this module is a driver module or not
+ var/is_driver_module = TRUE
+
+///Called to apply modules to a vehicle
+/obj/item/tank_module/proc/on_equip(obj/vehicle/sealed/armored/vehicle, mob/living/user)
+ SHOULD_CALL_PARENT(TRUE)
+ if(!istype(vehicle))
+ return FALSE
+ var/slot = is_driver_module ? vehicle.driver_utility_module : vehicle.gunner_utility_module
+ if(slot)
+ user?.balloon_alert(user, "module slot full")
+ return FALSE
+ user?.temporarilyRemoveItemFromInventory(src)
+ forceMove(vehicle)
+ if(is_driver_module)
+ vehicle.driver_utility_module = src
+ else
+ vehicle.gunner_utility_module = src
+ if(!vehicle.turret_overlay)
+ overlay = image(vehicle.icon, null, icon_state)
+ vehicle.add_overlay(overlay)
+ else
+ overlay = image(vehicle.turret_overlay.icon, null, icon_state)
+ vehicle.turret_overlay.add_overlay(overlay)
+ owner = vehicle
+ return TRUE
+
+///called to remove this module from its vehicle
+/obj/item/tank_module/proc/on_unequip(mob/user)
+ SHOULD_CALL_PARENT(TRUE)
+ if(owner.driver_utility_module == src)
+ owner.driver_utility_module = null
+ else
+ owner.gunner_utility_module = null
+ forceMove(owner.drop_location())
+ owner.cut_overlay(overlay)
+ owner.turret_overlay?.cut_overlay(overlay)
+ owner = null
+ overlay = null
+ user?.put_in_hands(src)
+ return TRUE
+
+/obj/item/tank_module/Destroy()
+ if(owner)
+ on_unequip()
+ return ..()
+
+
+/obj/item/tank_module/overdrive
+ name = "overdrive module"
+ desc = "A module that enhances the speed of armored combat vehicles by increasing fuel efficiency."
+ icon_state = "overdrive"
+
+/obj/item/tank_module/overdrive/on_equip(target)
+ . = ..()
+ if(!.)
+ return
+ var/obj/vehicle/sealed/armored/vehicle = target
+ vehicle.move_delay -= 0.15 SECONDS
+
+/obj/item/tank_module/overdrive/on_unequip()
+ owner.move_delay += 0.15 SECONDS
+ return ..()
+
+/obj/item/tank_module/passenger
+ name = "passenger module"
+ desc = "A module that increases the carrying capacity of a vehicle with extra seats."
+ icon_state = "uninstalled APC frieght carriage"
+
+/obj/item/tank_module/passenger/on_equip(target)
+ . = ..()
+ if(!.)
+ return
+ var/obj/vehicle/sealed/armored/vehicle = target
+ vehicle.max_occupants += 4
+
+/obj/item/tank_module/passenger/on_unequip(target)
+ owner.max_occupants -= 4
+ return ..()
+
+
+/obj/item/tank_module/ability
+ name = "Ability Module"
+ desc = "You shouldnt be seeing this."
+ icon_state = "overdrive"
+ ///typepaths for the ability we want to grant
+ var/ability_to_grant
+ ///if given, a single flag of who we want this ability to be granted to
+ var/flag_controller = NONE
+
+/obj/item/tank_module/ability/on_equip(obj/vehicle/sealed/armored/vehicle, attach_right)
+ . = ..()
+ if(!.)
+ return
+ if(flag_controller)
+ vehicle.initialize_controller_action_type(ability_to_grant, flag_controller)
+ else
+ vehicle.initialize_passenger_action_type(ability_to_grant)
+
+/obj/item/tank_module/ability/on_unequip(atom/moveto)
+ if(flag_controller)
+ owner.destroy_controller_action_type(ability_to_grant, flag_controller)
+ else
+ owner.destroy_passenger_action_type(ability_to_grant)
+ return ..()
+
+/obj/item/tank_module/ability/zoom
+ name = "zoom module"
+ desc = "Allows gunners to see further while looking through it. Weapons cannot be used while looking through it."
+ icon_state = "zoom"
+ is_driver_module = FALSE
+ flag_controller = VEHICLE_CONTROL_EQUIPMENT
+ ability_to_grant = /datum/action/vehicle/sealed/armored/zoom
diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm
new file mode 100644
index 0000000000000..f64f3886855d0
--- /dev/null
+++ b/code/modules/vehicles/armored/armored_weapons.dm
@@ -0,0 +1,341 @@
+/obj/item/armored_weapon
+ name = "\improper LTB main battle tank cannon"
+ desc = "A TGMC vehicle's main turret cannon. It fires 86mm rocket propelled shells"
+ icon = 'icons/obj/armored/hardpoint_modules.dmi'
+ icon_state = "ltb_cannon"
+ ///owner this is attached to
+ var/obj/vehicle/sealed/armored/chassis
+ ///The turret icon if we equip the weapon in a secondary slot, you should null this if its unequippable as such
+ var/secondary_equipped_icon
+ ///Weapon slot this weapon fits in
+ var/weapon_slot = MODULE_PRIMARY
+
+ ///currently loaded ammo. initial value is ammo we start with
+ var/obj/item/ammo_magazine/ammo = /obj/item/ammo_magazine/tank/ltb_cannon
+ ///Current loaded magazines: top one empties into ammo
+ var/list/obj/item/ammo_magazine/ammo_magazine = list()
+ ///maximum magazines ammo_magazine can hold
+ var/maximum_magazines = 5
+ ///ammo types we'll be able to accept
+ var/list/accepted_ammo = list(
+ /obj/item/ammo_magazine/tank/tank_glauncher,
+ /obj/item/ammo_magazine/tank/ltb_cannon,
+ )
+ ///current tracked target for fire(), updated when user drags
+ var/atom/current_target
+ ///current mob firing this weapon. used for tracking for iff and etc in fire()
+ var/mob/current_firer
+
+ ///sound file to play when this weapon you know, fires
+ var/fire_sound = list('sound/weapons/guns/fire/tank_cannon1.ogg', 'sound/weapons/guns/fire/tank_cannon2.ogg')
+ ///Tracks windups
+ var/windup_checked = WEAPON_WINDUP_NOT_CHECKED
+ ///windup sound played during windup
+ var/windup_sound
+ ///windup delay for this object
+ var/windup_delay = 0
+ ///scatter of this weapon. in degrees and modified by arm this is attached to
+ var/variance = 0
+ /// since mech guns only get one firemode this is for all types of shots
+ var/projectile_delay = 5 SECONDS
+ /// time between shots in a burst
+ var/projectile_burst_delay = 2
+ ///bullets per burst if firemode is set to burst
+ var/burst_amount = 0
+ ///fire mode to use for autofire
+ var/fire_mode = GUN_FIREMODE_SEMIAUTO
+ ///how many seconds automatic, and manual, reloading takes
+ var/rearm_time = 4 SECONDS
+ ///ammo hud icon to display when no ammo is loaded
+ var/hud_state_empty = "shell_empty"
+
+/obj/item/armored_weapon/Initialize(mapload)
+ . = ..()
+ if(ammo)
+ ammo = new ammo(src)
+ AddComponent(/datum/component/automatedfire/autofire, projectile_delay, projectile_delay, projectile_burst_delay, burst_amount, fire_mode, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire)))
+
+/obj/item/armored_weapon/Destroy()
+ if(chassis)
+ detach(get_turf(chassis))
+ QDEL_NULL(ammo)
+ QDEL_LIST(ammo_magazine)
+ return ..()
+
+///called by the chassis: begins firing, yes this is stolen from mech but I made both so bite me
+/obj/item/armored_weapon/proc/begin_fire(mob/source, atom/target, list/modifiers)
+ if(!ammo || ammo.current_rounds < 0)
+ playsound(source, 'sound/weapons/guns/fire/empty.ogg', 15, 1)
+ return
+ if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT(type)))
+ return
+ TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT(type), projectile_delay)
+
+ set_target(get_turf_on_clickcatcher(target, source, list2params(modifiers)))
+ if(!current_target)
+ return
+ RegisterSignal(source, COMSIG_MOB_MOUSEUP, PROC_REF(stop_fire))
+ RegisterSignal(source, COMSIG_MOB_MOUSEDRAG, PROC_REF(change_target))
+ if(windup_delay && windup_checked == WEAPON_WINDUP_NOT_CHECKED)
+ windup_checked = WEAPON_WINDUP_CHECKING
+ playsound(chassis.loc, windup_sound, 30, TRUE)
+ if(!do_after(source, windup_delay, IGNORE_TARGET_LOC_CHANGE, chassis, BUSY_ICON_DANGER, BUSY_ICON_DANGER, extra_checks = CALLBACK(src, PROC_REF(do_after_checks), current_target)))
+ windup_checked = WEAPON_WINDUP_NOT_CHECKED
+ return
+ windup_checked = WEAPON_WINDUP_CHECKED
+ if(QDELETED(current_target))
+ windup_checked = WEAPON_WINDUP_NOT_CHECKED
+ return
+ current_firer = source
+ if(fire_mode == GUN_FIREMODE_SEMIAUTO)
+ var/fire_return // todo fix: code expecting return values from async
+ ASYNC
+ fire_return = fire()
+ if(!fire_return || windup_checked == WEAPON_WINDUP_CHECKING)
+ return
+ reset_fire()
+ return
+ SEND_SIGNAL(src, COMSIG_ARMORED_FIRE)
+ source?.client?.mouse_pointer_icon = 'icons/effects/supplypod_target.dmi'
+
+/// do after checks for the mecha equipment do afters
+/obj/item/armored_weapon/proc/do_after_checks(atom/target)
+ if(!chassis)
+ return FALSE
+ if(QDELETED(current_target))
+ return FALSE
+ if(chassis.primary_weapon == src)
+ var/dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir))
+ if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2))
+ if(!chassis.swivel_turret(current_target))
+ return FALSE
+ dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir))
+ if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2))
+ return FALSE
+ return TRUE
+
+///callback wrapper for adding/removing trait
+/obj/item/armored_weapon/proc/set_bursting(bursting)
+ if(bursting)
+ ADD_TRAIT(src, TRAIT_GUN_BURST_FIRING, VEHICLE_TRAIT)
+ return
+ REMOVE_TRAIT(src, TRAIT_GUN_BURST_FIRING, VEHICLE_TRAIT)
+
+///Changes the current target.
+/obj/item/armored_weapon/proc/change_target(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params)
+ SIGNAL_HANDLER
+ set_target(get_turf_on_clickcatcher(over_object, source, params))
+
+///Sets the current target and registers for qdel to prevent hardels
+/obj/item/armored_weapon/proc/set_target(atom/object)
+ if(object == current_target || object == chassis)
+ return
+ if(current_target)
+ UnregisterSignal(current_target, COMSIG_QDELETING)
+ current_target = object
+ if(current_target)
+ RegisterSignal(current_target, COMSIG_QDELETING, PROC_REF(clean_target))
+
+///Stops the Autofire component and resets the current cursor.
+/obj/item/armored_weapon/proc/stop_fire(mob/living/source, atom/object, location, control, params)
+ SIGNAL_HANDLER
+ var/list/modifiers = params2list(params)
+ if(!((modifiers[BUTTON] == RIGHT_CLICK) && chassis.secondary_weapon == src) && !((modifiers[BUTTON] == LEFT_CLICK) && chassis.primary_weapon == src))
+ return
+ SEND_SIGNAL(src, COMSIG_ARMORED_STOP_FIRE)
+ if(!HAS_TRAIT(src, TRAIT_GUN_BURST_FIRING))
+ reset_fire()
+ UnregisterSignal(source, list(COMSIG_MOB_MOUSEDRAG, COMSIG_MOB_MOUSEUP))
+
+///Cleans the current target in case of Hardel
+/obj/item/armored_weapon/proc/clean_target()
+ SIGNAL_HANDLER
+ current_target = get_turf(current_target)
+
+///Resets the autofire component.
+/obj/item/armored_weapon/proc/reset_fire()
+ windup_checked = WEAPON_WINDUP_NOT_CHECKED
+ current_firer?.client?.mouse_pointer_icon = chassis.mouse_pointer
+ set_target(null)
+ current_firer = null
+
+///does any effects and changes to the projectile when it is fired
+/obj/item/armored_weapon/proc/apply_weapon_modifiers(obj/projectile/projectile_to_fire, mob/firer)
+ projectile_to_fire.shot_from = src
+ projectile_to_fire.projectile_speed = projectile_to_fire.ammo.shell_speed
+ if(chassis.hitbox?.tank_desants)
+ projectile_to_fire.hit_atoms += chassis.hitbox.tank_desants
+ if((projectile_to_fire.ammo.ammo_behavior_flags & AMMO_IFF) && ishuman(firer))
+ var/mob/living/carbon/human/human_firer = firer
+ var/obj/item/card/id/id = human_firer.get_idcard()
+ projectile_to_fire.iff_signal = id?.iff_signal
+ if(firer)
+ projectile_to_fire.def_zone = firer.zone_selected
+
+///actually executes firing when autofire asks for it, returns TRUE to keep firing FALSE to stop
+/obj/item/armored_weapon/proc/fire()
+ if(chassis.primary_weapon == src)
+ var/dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir))
+ if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2))
+ chassis.swivel_turret(current_target)
+ return AUTOFIRE_CONTINUE
+ else if(chassis.turret_overlay)
+ chassis.turret_overlay.cut_overlay(chassis.turret_overlay.secondary_overlay)
+ chassis.turret_overlay.secondary_overlay.dir = get_cardinal_dir(chassis, current_target)
+ chassis.turret_overlay.add_overlay(chassis.turret_overlay.secondary_overlay)
+ else
+ chassis.cut_overlay(chassis.secondary_weapon_overlay)
+ chassis.secondary_weapon_overlay.dir = get_cardinal_dir(chassis, current_target)
+ chassis.add_overlay(chassis.secondary_weapon_overlay)
+
+
+ var/type_to_spawn = CHECK_BITFIELD(initial(ammo.default_ammo.ammo_behavior_flags), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile
+ var/obj/projectile/projectile_to_fire = new type_to_spawn(get_turf(src), initial(ammo.default_ammo.hitscan_effect_icon))
+ projectile_to_fire.generate_bullet(GLOB.ammo_list[ammo.default_ammo])
+
+ apply_weapon_modifiers(projectile_to_fire, current_firer)
+ var/firing_angle = get_angle_with_scatter(chassis, current_target, variance, projectile_to_fire.p_x, projectile_to_fire.p_y)
+
+ playsound(chassis, islist(fire_sound) ? pick(fire_sound):fire_sound, 20, TRUE)
+ projectile_to_fire.fire_at(current_target, current_firer, chassis, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED))
+
+ chassis.log_message("Fired from [name], targeting [current_target] at [AREACOORD(current_target)].", LOG_ATTACK)
+
+ if(chassis.primary_weapon == src && !chassis.turret_overlay.flashing)
+ chassis.turret_overlay.set_flashing(TRUE)
+ addtimer(CALLBACK(chassis.turret_overlay, TYPE_PROC_REF(/atom/movable/vis_obj/turret_overlay, set_flashing), FALSE), 7, TIMER_CLIENT_TIME)
+ chassis.interior?.breech.on_main_fire(ammo)
+
+ ammo.current_rounds--
+ for(var/mob/occupant AS in chassis.occupants)
+ occupant.hud_used.update_ammo_hud(src, list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty), ammo.current_rounds)
+ if(ammo.current_rounds > 0)
+ return AUTOFIRE_CONTINUE|AUTOFIRE_SUCCESS
+ playsound(src, 'sound/weapons/guns/misc/empty_alarm.ogg', 25, 1)
+ eject_ammo()
+ if(LAZYACCESS(current_firer.do_actions, src) || length(ammo_magazine) < 1)
+ return AUTOFIRE_SUCCESS
+ var/obj/item/ammo_magazine/tank/new_mag = ammo_magazine[1]
+ if(istype(new_mag) && new_mag.loading_sound)
+ // .5 sec delay to let other sounds play out
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), src, new_mag.loading_sound, 40), 5)
+ if(!do_after(current_firer, rearm_time, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, chassis, BUSY_ICON_GENERIC))
+ return AUTOFIRE_SUCCESS
+ reload()
+ return AUTOFIRE_CONTINUE|AUTOFIRE_SUCCESS
+
+///eject current ammo from tank
+/obj/item/armored_weapon/proc/eject_ammo()
+ for(var/mob/occupant AS in chassis.occupants)
+ occupant.hud_used.update_ammo_hud(src, list(hud_state_empty, hud_state_empty), 0)
+ ammo.update_appearance()
+ var/obj/item/ammo_magazine/old_ammo = ammo
+ ammo = null
+ if(chassis.interior)
+ if(chassis.primary_weapon == src)
+ chassis.interior.breech.do_eject_ammo(old_ammo)
+ else
+ chassis.interior.secondary_breech.do_eject_ammo(old_ammo)
+ return
+ old_ammo.forceMove(chassis.exit_location())
+
+///load topmost ammo magazine, if there is any
+/obj/item/armored_weapon/proc/reload()
+ if(ammo)
+ eject_ammo()
+ ammo = popleft(ammo_magazine)
+ for(var/mob/occupant AS in chassis.occupants)
+ occupant.hud_used.update_ammo_hud(src, list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty), ammo.current_rounds)
+
+///attach this weapon to a chassis
+/obj/item/armored_weapon/proc/attach(obj/vehicle/sealed/armored/tank, attach_primary)
+ if(attach_primary)
+ tank.primary_weapon?.detach(tank.exit_location())
+ tank.primary_weapon = src
+ tank.turret_overlay.update_gun_overlay(icon_state)
+ else
+ tank.secondary_weapon?.detach(tank.exit_location())
+ tank.secondary_weapon = src
+ if(tank.turret_overlay)
+ // do not remove the dir = SOUTH becuase otherwise byond flips an internal flag so the dir is inherited from the turret
+ tank.turret_overlay.secondary_overlay = image(tank.turret_icon, icon_state = icon_state + "_" + "[tank.turret_overlay.dir]", dir = SOUTH)
+ tank.turret_overlay.add_overlay(tank.turret_overlay.secondary_overlay)
+ else
+ tank.secondary_weapon_overlay = image(tank.turret_icon, icon_state = icon_state + "_" + "[tank.dir]")
+ tank.update_appearance(UPDATE_OVERLAYS)
+ chassis = tank
+ forceMove(tank)
+ var/icon_list
+ if(ammo?.default_ammo)
+ icon_list = list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty)
+ else
+ icon_list = list(hud_state_empty, hud_state_empty)
+ for(var/mob/occupant AS in chassis.occupants)
+ occupant.hud_used.add_ammo_hud(src, icon_list, ammo ? ammo.current_rounds : 0)
+
+///detach this weapon to a chassis
+/obj/item/armored_weapon/proc/detach(atom/moveto)
+ if(chassis.primary_weapon == src)
+ chassis.primary_weapon = null
+ chassis.turret_overlay.update_gun_overlay()
+ else
+ chassis.secondary_weapon = null
+ if(chassis.turret_overlay)
+ chassis.turret_overlay.cut_overlay(chassis.turret_overlay.secondary_overlay)
+ chassis.turret_overlay.secondary_overlay = null
+ else
+ chassis.secondary_weapon_overlay = null
+ chassis.update_appearance(UPDATE_OVERLAYS)
+ for(var/mob/occupant AS in chassis.occupants)
+ occupant.hud_used.remove_ammo_hud(src)
+ chassis = null
+ forceMove(moveto)
+
+/obj/item/armored_weapon/secondary_weapon
+ name = "secondary cupola minigun"
+ desc = "A robotically controlled minigun that spews lead."
+ icon_state = "cupola"
+ fire_sound = 'sound/weapons/guns/fire/tank_minigun_loop.ogg'
+ windup_delay = 5
+ windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg'
+ weapon_slot = MODULE_SECONDARY
+ secondary_equipped_icon = 'icons/obj/armored/3x3/tank_secondary_gun.dmi'
+ ammo = /obj/item/ammo_magazine/tank/secondary_cupola
+ accepted_ammo = list(/obj/item/ammo_magazine/tank/secondary_cupola)
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ projectile_delay = 2
+ variance = 5
+ rearm_time = 1 SECONDS
+ maximum_magazines = 5
+ hud_state_empty = "rifle_empty"
+
+/obj/item/armored_weapon/ltaap
+ name = "\improper LTA-AP chaingun"
+ desc = "A hefty, large caliber chaingun"
+ icon_state = "ltaap_chaingun"
+ fire_sound = 'sound/weapons/guns/fire/tank_minigun_loop.ogg'
+ windup_delay = 5
+ windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg'
+ weapon_slot = MODULE_PRIMARY
+ secondary_equipped_icon = 'icons/obj/armored/3x3/tank_secondary_gun.dmi'
+ ammo = /obj/item/ammo_magazine/tank/ltaap_chaingun
+ accepted_ammo = list(/obj/item/ammo_magazine/tank/ltaap_chaingun)
+ fire_mode = GUN_FIREMODE_AUTOMATIC
+ variance = 15
+ projectile_delay = 0.1 SECONDS
+ rearm_time = 3 SECONDS
+ maximum_magazines = 5
+ hud_state_empty = "rifle_empty"
+
+/obj/item/armored_weapon/apc_cannon
+ name = "MKV-7 utility payload launcher"
+ desc = "A double barrelled cannon which can rapidly deploy utility packages to the battlefield."
+ icon_state = "APC uninstalled dualcannon"
+ fire_sound = 'sound/weapons/guns/fire/tank_smokelauncher.ogg'
+ ammo = /obj/item/ammo_magazine/tank/tank_slauncher
+ accepted_ammo = list(
+ /obj/item/ammo_magazine/tank/tank_slauncher,
+ /obj/item/ammo_magazine/tank/tank_glauncher,
+ )
+ projectile_delay = 0.7 SECONDS
+ hud_state_empty = "grenade_empty"
diff --git a/code/modules/vehicles/armored/interiors/ammo_rack.dm b/code/modules/vehicles/armored/interiors/ammo_rack.dm
new file mode 100644
index 0000000000000..2a00fd06db84a
--- /dev/null
+++ b/code/modules/vehicles/armored/interiors/ammo_rack.dm
@@ -0,0 +1,76 @@
+
+/obj/structure/ammo_rack
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ ///ref to the actual internal storage
+ var/obj/item/storage/internal/storage = /obj/item/storage/internal
+
+/obj/structure/ammo_rack/Initialize(mapload)
+ . = ..()
+ storage = new storage(src)
+ update_appearance(UPDATE_OVERLAYS)
+
+/obj/structure/ammo_rack/examine(mob/user)
+ . = ..()
+ . += "Right click to remove the topmost object."
+
+/obj/structure/ammo_rack/attack_hand(mob/living/user)
+ return storage.open(user)
+
+/obj/structure/ammo_rack/MouseDrop(obj/over_object)
+ if(storage.handle_mousedrop(usr, over_object))
+ return ..()
+
+/obj/structure/ammo_rack/attackby(obj/item/I, mob/user, params)
+ ..()
+ return storage.attackby(I, user, params)
+
+/obj/structure/ammo_rack/attack_hand_alternate(mob/user)
+ ..()
+ return storage.attack_hand_alternate(user)
+
+/obj/structure/ammo_rack/update_overlays()
+ . = ..()
+ if(length(storage.contents))
+ var/atom/bottommost = storage.contents[1]
+ var/total_w = 0
+ for(var/obj/item/I AS in storage)
+ total_w += I.w_class
+ var/thirds = clamp(round(3 * (total_w / storage.max_storage_space)), 1, 3)
+ . += image(icon, src, bottommost.icon_state + "_" + "[thirds]") // "ltb_3"/"ltb_2"/"ltb_1"
+
+/obj/structure/ammo_rack/on_pocket_insertion()
+ update_appearance()
+
+/obj/structure/ammo_rack/on_pocket_removal()
+ update_appearance()
+
+/obj/structure/ammo_rack/primary
+ name = "primary ammo rack"
+ icon_state = "primaryrack"
+ storage = /obj/item/storage/internal/ammorack_primary
+
+/obj/structure/ammo_rack/primary/update_overlays()
+ . = ..()
+ . += image(icon, src, "primaryrack_overlay")
+
+/obj/structure/ammo_rack/secondary
+ name = "secondary ammo rack"
+ icon_state = "secondaryrack"
+ storage = /obj/item/storage/internal/ammorack_secondary
+
+/obj/item/storage/internal/ammorack_primary
+ max_storage_space = 120 //they're all WEIGHT_CLASS_GIGANTIC which is 6
+ storage_slots = 20
+ max_w_class = WEIGHT_CLASS_GIGANTIC
+ can_hold = list(
+ /obj/item/ammo_magazine/tank/ltb_cannon,
+ /obj/item/ammo_magazine/tank/ltaap_chaingun,
+ )
+
+/obj/item/storage/internal/ammorack_secondary
+ max_storage_space = 120
+ storage_slots = 20
+ max_w_class = WEIGHT_CLASS_GIGANTIC
+ can_hold = list(
+ /obj/item/ammo_magazine/tank/secondary_cupola,
+ )
diff --git a/code/modules/vehicles/armored/interiors/breech.dm b/code/modules/vehicles/armored/interiors/breech.dm
new file mode 100644
index 0000000000000..8bf620e31dd1f
--- /dev/null
+++ b/code/modules/vehicles/armored/interiors/breech.dm
@@ -0,0 +1,157 @@
+
+/obj/structure/gun_breech
+ name = "gun breech"
+ desc = "A gun breech used for loading large caliber rounds into the main gun."
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ icon_state = "breech"
+ resistance_flags = RESIST_ALL
+ ///bool if this laods the secondary gun
+ var/is_secondary = FALSE
+ ///owner of this object, assigned during interior linkage
+ var/obj/vehicle/sealed/armored/owner
+
+/obj/structure/gun_breech/Destroy()
+ owner = null
+ return ..()
+
+/obj/structure/gun_breech/link_interior(datum/interior/link)
+ if(!istype(link, /datum/interior/armored))
+ CRASH("invalid interior [link.type] passed to [name]")
+ var/datum/interior/armored/inside = link
+ if(!is_secondary)
+ inside.breech = src
+ else
+ inside.secondary_breech = src
+ owner = inside.container
+
+/obj/structure/gun_breech/attack_hand(mob/living/user)
+ . = ..()
+ var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon
+ if(!weapon)
+ balloon_alert(user, "no weapon")
+ return
+ if(!weapon.ammo)
+ balloon_alert(user, "breech empty")
+ return
+ if(user.do_actions)
+ balloon_alert(user, "busy")
+ return
+ if(!do_after(user, 1 SECONDS, NONE, src))
+ return
+ owner.balloon_alert(user, "breech unloaded")
+ user.put_in_hands(weapon.ammo)
+ weapon.ammo.update_appearance()
+ weapon.ammo = null
+
+/obj/structure/gun_breech/attackby(obj/item/I, mob/user, params)
+ . = ..()
+ if(!istype(I, /obj/item/ammo_magazine))
+ return
+ var/obj/item/ammo_magazine/mag = I
+ var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon
+ if(!reload_checks(user))
+ return
+ if(!(mag.type in weapon.accepted_ammo))
+ balloon_alert(user, "not accepted ammo")
+ return
+ if(user.do_actions)
+ balloon_alert(user, "busy")
+ return
+ var/channel = SSsounds.random_available_channel()
+ var/sound = 'sound/weapons/guns/interact/working_the_bolt.ogg'
+ if(istype(mag, /obj/item/ammo_magazine/tank))
+ var/obj/item/ammo_magazine/tank/t_mag = mag
+ sound = islist(t_mag.loading_sound)? pick(t_mag.loading_sound):t_mag.loading_sound
+ playsound(src, sound, 20, channel = channel)
+ if(!do_after(user, weapon.rearm_time, NONE, src, extra_checks=CALLBACK(src, PROC_REF(reload_checks), user)))
+ for(var/mob/crew AS in owner.interior.occupants)
+ crew.stop_sound_channel(channel)
+ return
+ user.temporarilyRemoveItemFromInventory(mag)
+ mag.forceMove(weapon)
+ weapon.ammo = mag
+ user.say(is_secondary ? "Loaded!" : "Up!")
+ for(var/mob/occupant AS in owner.interior.occupants)
+ occupant.hud_used.update_ammo_hud(weapon, list(
+ mag.default_ammo.hud_state,
+ mag.default_ammo.hud_state_empty),
+ mag.current_rounds
+ )
+
+///checks to perform while reloading
+/obj/structure/gun_breech/proc/reload_checks(mob/user)
+ var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon
+ if(!weapon)
+ balloon_alert(user, "no weapon")
+ return FALSE
+ if(weapon.ammo)
+ balloon_alert(user, "already loaded")
+ return FALSE
+ return TRUE
+
+///called every time the firing animation is refreshed, not every actual fire
+/obj/structure/gun_breech/proc/on_main_fire(obj/item/ammo_magazine/owner_ammo)
+ if(owner_ammo.default_ammo.ammo_behavior_flags & AMMO_ENERGY) // todo add puffs of smoke that fly out
+ return
+ if(owner_ammo.max_rounds == 1)
+ return
+ //todo get an animation for bullets flying out
+ var/turf/eject_loc = get_step(src, WEST)
+ var/obj/item/ammo_casing/cartridge/pile = locate(/obj/item/ammo_casing/cartridge) in eject_loc
+ if(!pile)
+ pile = new(eject_loc)
+ return
+ pile.current_casings += 1
+ pile.update_appearance()
+
+///when we run out of ammo; how do we eject the magazine?
+/obj/structure/gun_breech/proc/do_eject_ammo(obj/item/ammo_magazine/old_ammo)
+ old_ammo.forceMove(get_step(src, WEST))
+ if(old_ammo.max_rounds != 1)
+ //todo make non shell and energy ejection anim?
+ return
+ old_ammo.pixel_x = 20
+ old_ammo.pixel_y = 4
+ var/matrix/hit_back_transform = matrix()
+ var/rand_spin = rand(-90, 90)
+ hit_back_transform.Turn(rand_spin)
+ var/hit_back_x = 6 + rand(-1, 1)
+ var/hit_back_y = -4 + rand(-1, 1)
+
+ var/matrix/rest_transform = matrix()
+ rest_transform.Turn(rand_spin + rand(-45, 45))
+ var/rest_x = 3 + rand(0, 10)
+ var/rest_y = -17 + rand(-2, 2)
+
+ animate(old_ammo, time=3, easing=CUBIC_EASING|EASE_OUT, transform = hit_back_transform, pixel_x = hit_back_x, pixel_y = hit_back_y)
+ animate(time=3, easing=CUBIC_EASING|EASE_IN, transform = rest_transform, pixel_x = rest_x, pixel_y = rest_y)
+ var/obj/effect/abstract/particle_holder/smoke_visuals = new(src, /particles/breech_smoke)
+ QDEL_IN(smoke_visuals, 0.7 SECONDS)
+
+/particles/breech_smoke
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "smoke"
+ width = 300
+ height = 300
+ count = 20
+ spawning = 20
+ lifespan = 1 SECONDS
+ fade = 8 SECONDS
+ grow = 0.1
+ scale = 0.2
+ spin = generator(GEN_NUM, -20, 20)
+ velocity = list(-4, 0)
+ position = list(-2, 2)
+ gravity = list(0, 2)
+ friction = generator(GEN_NUM, 0.1, 0.5)
+
+/obj/structure/gun_breech/secondary
+ name = "secondary loading mechanism"
+ desc = "A feeding mechanism for loading ammo into the secondary weapon."
+ icon_state = "secondary_breech"
+ is_secondary = TRUE
+
+/obj/structure/gun_breech/secondary/do_eject_ammo(obj/item/ammo_magazine/old_ammo)
+ old_ammo.forceMove(get_turf(src))
+ old_ammo.pixel_x = rand(-10, 10)
+ old_ammo.pixel_y = rand(-10, 10)
diff --git a/code/modules/vehicles/armored/interiors/chairs.dm b/code/modules/vehicles/armored/interiors/chairs.dm
new file mode 100644
index 0000000000000..61fb317dbcb0f
--- /dev/null
+++ b/code/modules/vehicles/armored/interiors/chairs.dm
@@ -0,0 +1,89 @@
+
+/obj/structure/bed/chair/loader_seat
+ name = "loader seat"
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ icon_state = "vehicle_chair"
+ resistance_flags = RESIST_ALL
+ dir = EAST
+
+
+/obj/structure/bed/chair/vehicle_driver_seat
+ name = "driver seat"
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ icon_state = "vehicle_chair"
+ resistance_flags = RESIST_ALL
+ dir = EAST
+ ///owner of this object, assigned during interior linkage
+ var/obj/vehicle/sealed/armored/owner
+
+/obj/structure/bed/chair/vehicle_driver_seat/Destroy()
+ owner = null
+ return ..()
+
+/obj/structure/bed/chair/vehicle_driver_seat/link_interior(datum/interior/link)
+ if(!istype(link, /datum/interior/armored))
+ CRASH("invalid interior [link.type] passed to [name]")
+ var/datum/interior/armored/inside = link
+ inside.drive_seat = src
+ owner = inside.container
+
+/obj/structure/bed/chair/vehicle_driver_seat/buckle_mob(mob/living/buckling_mob, force, check_loc, lying_buckle, hands_needed, target_hands_needed, silent)
+ if(buckling_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN)
+ return FALSE
+ return ..()
+
+/obj/structure/bed/chair/vehicle_driver_seat/post_buckle_mob(mob/buckling_mob)
+ . = ..()
+ owner.add_control_flags(buckling_mob, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ buckling_mob.reset_perspective(owner)
+ buckling_mob.pixel_x = pixel_x
+ buckling_mob.pixel_y = pixel_y
+
+/obj/structure/bed/chair/vehicle_driver_seat/post_unbuckle_mob(mob/buckled_mob)
+ . = ..()
+ owner.remove_control_flags(buckled_mob, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ buckled_mob.reset_perspective()
+ buckled_mob.pixel_x = initial(buckled_mob.pixel_x)
+ buckled_mob.pixel_y = initial(buckled_mob.pixel_y)
+
+/obj/structure/bed/chair/vehicle_driver_seat/relaymove(mob/living/user, direct)
+ return owner.relaymove(arglist(args))
+
+
+/obj/structure/bed/chair/vehicle_gunner_seat
+ name = "gunner seat"
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ icon_state = "vehicle_chair"
+ resistance_flags = RESIST_ALL
+ dir = EAST
+ ///owner of this object, assigned during interior linkage
+ var/obj/vehicle/sealed/armored/owner
+
+/obj/structure/bed/chair/vehicle_gunner_seat/link_interior(datum/interior/link)
+ if(!istype(link, /datum/interior/armored))
+ CRASH("invalid interior [link.type] passed to [name]")
+ var/datum/interior/armored/inside = link
+ inside.gun_seat = src
+ owner = inside.container
+
+/obj/structure/bed/chair/vehicle_gunner_seat/buckle_mob(mob/living/buckling_mob, force, check_loc, lying_buckle, hands_needed, target_hands_needed, silent)
+ if(buckling_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN)
+ return FALSE
+ return ..()
+
+/obj/structure/bed/chair/vehicle_gunner_seat/post_buckle_mob(mob/buckling_mob)
+ . = ..()
+ owner.add_control_flags(buckling_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+ buckling_mob.reset_perspective(owner)
+ buckling_mob.pixel_x = pixel_x
+ buckling_mob.pixel_y = pixel_y
+
+/obj/structure/bed/chair/vehicle_gunner_seat/post_unbuckle_mob(mob/buckled_mob)
+ . = ..()
+ owner.remove_control_flags(buckled_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+ buckled_mob.reset_perspective()
+ buckled_mob.pixel_x = initial(buckled_mob.pixel_x)
+ buckled_mob.pixel_y = initial(buckled_mob.pixel_y)
+
+/obj/structure/bed/chair/vehicle_gunner_seat/relaymove(mob/living/user, direct)
+ return owner.relaymove(arglist(args))
diff --git a/code/modules/vehicles/armored/interiors/periscope.dm b/code/modules/vehicles/armored/interiors/periscope.dm
new file mode 100644
index 0000000000000..169c8e3befd24
--- /dev/null
+++ b/code/modules/vehicles/armored/interiors/periscope.dm
@@ -0,0 +1,34 @@
+
+/obj/structure/periscope
+ name = "tank periscope"
+ desc = "A periscope for viewing the outside of the vehicle. Resist or move to stop looking through it."
+ icon = 'icons/obj/armored/3x3/tank_interior.dmi'
+ icon_state = "periscope"
+ density = FALSE
+ resistance_flags = RESIST_ALL
+ ///owner of this object, assigned during interior linkage
+ var/obj/vehicle/sealed/armored/owner
+
+/obj/structure/periscope/Destroy()
+ owner = null
+ return ..()
+
+/obj/structure/periscope/link_interior(datum/interior/link)
+ owner = link.container
+
+/obj/structure/periscope/attack_hand(mob/living/user)
+ . = ..()
+ user.reset_perspective(owner)
+ ADD_TRAIT(user, TRAIT_SEE_IN_DARK, VEHICLE_TRAIT)
+ user.update_sight()
+ user.client.view_size.set_view_radius_to(4.5)
+ RegisterSignals(user, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DO_RESIST, COMSIG_MOB_LOGOUT), PROC_REF(stop_looking))
+
+///signal handler for canceling the looking
+/obj/structure/periscope/proc/stop_looking(mob/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DO_RESIST, COMSIG_MOB_LOGOUT))
+ source.reset_perspective()
+ REMOVE_TRAIT(source, TRAIT_SEE_IN_DARK, VEHICLE_TRAIT)
+ source.client.view_size.reset_to_default()
+ source.update_sight()
diff --git a/code/modules/vehicles/armored/medium_apc.dm b/code/modules/vehicles/armored/medium_apc.dm
new file mode 100644
index 0000000000000..ec0996a2b5279
--- /dev/null
+++ b/code/modules/vehicles/armored/medium_apc.dm
@@ -0,0 +1,16 @@
+/obj/vehicle/sealed/armored/multitile/medium/apc
+ name = "TAV - Nike"
+ desc = "A heavily armoured vehicle with light armaments designed to ferry troops around the battlefield, or assist with search and rescue (SAR) operations."
+ icon = 'icons/obj/armored/2x2/medium_vehicles.dmi'
+ turret_icon = 'icons/obj/armored/2x2/medium_vehicles.dmi'
+ turret_icon_state = "apc_turret"
+ damage_icon_path = null
+ interior = null
+ required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT
+ minimap_icon_state = null
+ armored_flags = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_SECONDARY_WEAPON|ARMORED_HAS_UNDERLAY
+ icon_state = "apc"
+ move_delay = 0.25 SECONDS
+ max_occupants = 5
+ primary_weapon_type = /obj/item/armored_weapon/apc_cannon //Only has a utility launcher, no offense as standard.
+ secondary_weapon_type = null
diff --git a/code/modules/vehicles/armored/medium_tank.dm b/code/modules/vehicles/armored/medium_tank.dm
new file mode 100644
index 0000000000000..d6e8b85ddf5d1
--- /dev/null
+++ b/code/modules/vehicles/armored/medium_tank.dm
@@ -0,0 +1,20 @@
+/obj/vehicle/sealed/armored/multitile/medium //Its a smaller tank, we had sprites for it so whoo
+ name = "THV - Hades"
+ desc = "A metal behemoth which is designed to cleave through enemy lines. It comes pre installed with a main tank cannon capable of deploying heavy payloads, as well as a minigun which can tear through multiple targets in quick succession."
+ icon = 'icons/obj/armored/2x2/medium_vehicles.dmi'
+ turret_icon = 'icons/obj/armored/2x2/medium_vehicles.dmi'
+ turret_icon_state = "tank_turret"
+ hitbox = /obj/hitbox/medium
+ secondary_turret_icon = null
+ damage_icon_path = null
+ interior = null
+ icon_state = "tank"
+ armored_flags = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_UNDERLAY
+ pixel_x = -16
+ pixel_y = -32
+ obj_integrity = 1300
+ max_integrity = 1300
+ max_occupants = 3
+
+/obj/vehicle/sealed/armored/multitile/medium/enter_locations(mob/M)
+ return list(get_step(src, REVERSE_DIR(dir)))
diff --git a/code/modules/vehicles/armored/small_apc.dm b/code/modules/vehicles/armored/small_apc.dm
new file mode 100644
index 0000000000000..27c8c1bc17756
--- /dev/null
+++ b/code/modules/vehicles/armored/small_apc.dm
@@ -0,0 +1,15 @@
+/obj/vehicle/sealed/armored/apc
+ name = "TAV - Nike"
+ desc = "A miniaturized replica of a popular personnel carrier. For ages 5 and up."
+ icon = 'icons/obj/armored/1x1/tinytank.dmi'
+ turret_icon = 'icons/obj/armored/1x1/tinytank_gun.dmi'
+ turret_icon_state = "apc_turret"
+ icon_state = "apc"
+ armored_flags = NONE
+ move_delay = 0.3 SECONDS
+ armored_flags = NONE
+ pixel_x = -16
+ pixel_y = -8
+ max_occupants = 3
+ primary_weapon_type = null
+ secondary_weapon_type = null
diff --git a/code/modules/vehicles/armored/tank_fabricator.dm b/code/modules/vehicles/armored/tank_fabricator.dm
new file mode 100644
index 0000000000000..d15bec0c721a7
--- /dev/null
+++ b/code/modules/vehicles/armored/tank_fabricator.dm
@@ -0,0 +1,9 @@
+/obj/machinery/tank_part_fabricator
+ name = "vehicle part fabricator"
+ desc = "A large automated 3D printer for producing new vehicle parts and maintaining old ones."
+ density = TRUE
+ anchored = TRUE
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 20
+ icon = 'icons/obj/machines/drone_fab.dmi'
+ icon_state = "drone_fab_idle"
diff --git a/code/modules/vehicles/armored/vehicle_collision.dm b/code/modules/vehicles/armored/vehicle_collision.dm
new file mode 100644
index 0000000000000..37692e63868fb
--- /dev/null
+++ b/code/modules/vehicles/armored/vehicle_collision.dm
@@ -0,0 +1,64 @@
+/**
+ *This proc is called when a atom is crashed into by a [armored vehicle][/obj/vehicle/sealed/armored]. Damage is then dealt to both the vehicle and atom
+ *
+ * * Arguments:
+ * * veh is the vehicle that is ramming
+ * * facing is the direction the vehicle is facing for when we ram it
+ * * T is the turf where the vehicle is used with-
+ * * temp to check whether a mob is squished
+ */
+/atom/proc/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ var/damage = veh.ram_damage // Each vehicle gets its own damage, you can modify it with snowplows and such ideally
+
+ if(!TIMER_COOLDOWN_CHECK(veh, COOLDOWN_VEHICLE_CRUSHSOUND))
+ visible_message(span_danger("[veh] rams [src]!"))
+ playsound(src, 'sound/effects/metal_crash.ogg', 45)
+ TIMER_COOLDOWN_START(veh, COOLDOWN_VEHICLE_CRUSHSOUND, 1 SECONDS)
+ return damage
+
+/obj/structure/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ . = ..()
+ take_damage(., BRUTE, MELEE, TRUE, facing, 0)
+
+/obj/structure/barricade/plasteel/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ . = ..()
+ toggle_open(FALSE)
+
+/obj/vehicle/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) //MONSTER TRUCKS
+ . = ..()
+ take_damage(., BRUTE, MELEE, TRUE, facing, 0)
+
+/obj/machinery/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ . = ..()
+ take_damage(., BRUTE, MELEE, TRUE, facing, 0)
+
+/turf/closed/wall/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ . = ..()
+ take_damage(., BRUTE, MELEE, TRUE, facing, 0)
+
+/mob/living/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp, mob/pilot)
+ . = ..()
+ if(stat == DEAD)
+ return 0
+ if(lying_angle)
+ return 0
+ log_attack("[key_name(pilot)] drove into [key_name(src)] with [veh]")
+ temp = get_step(veh.loc, facing)
+ T = temp
+ T = get_step(T, facing)
+ T = get_step(T, facing)
+ T = get_step(T, facing)
+ face_atom(T)
+ throw_at(T, 3, 2, veh, 1)
+ return take_overall_damage(., BRUTE, MELEE, FALSE, FALSE, TRUE, 0, 4)
+
+
+/mob/living/carbon/xenomorph/larva/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ gib() //fuck you
+
+/obj/effect/alien/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ . = ..()
+ take_damage(., BRUTE, MELEE, TRUE, facing, 0)
+
+/obj/effect/alien/weeds/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp)
+ return
diff --git a/code/modules/vehicles/atv.dm b/code/modules/vehicles/atv.dm
index a697f30646575..5328827da2f79 100644
--- a/code/modules/vehicles/atv.dm
+++ b/code/modules/vehicles/atv.dm
@@ -47,7 +47,7 @@
buckled_mob.bullet_act(P)
return TRUE
-/obj/vehicle/ridden/atv/obj_destruction()
+/obj/vehicle/ridden/atv/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
explosion(src, devastation_range = -1, light_impact_range = 2, flame_range = 3, flash_range = 4)
return ..()
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
index 4997d33549848..cb9a009bdd437 100644
--- a/code/modules/vehicles/cargo_train.dm
+++ b/code/modules/vehicles/cargo_train.dm
@@ -55,6 +55,8 @@
/obj/vehicle/train/cargo/engine/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/key/cargo_train))
if(key)
@@ -65,7 +67,8 @@
verbs += /obj/vehicle/train/cargo/engine/verb/remove_key
-/obj/vehicle/train/cargo/update_icon()
+/obj/vehicle/train/cargo/update_icon_state()
+ . = ..()
if(open)
icon_state = initial(icon_state) + "_open"
else
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index 42efcee22e8e2..52460f0fa2222 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -1,6 +1,7 @@
/obj/vehicle/sealed/car
layer = ABOVE_MOB_LAYER
move_resist = MOVE_FORCE_VERY_STRONG
+ move_delay = 1
///Bitflags for special behavior such as kidnapping
var/car_traits = NONE
///Sound file(s) to play when we drive around
@@ -9,8 +10,6 @@
var/engine_sound_length = 2 SECONDS
///Time it takes to break out of the car.
var/escape_time = 6 SECONDS
- /// How long it takes to move, cars don't use the riding component similar to mechs so we handle it ourselves
- var/vehicle_move_delay = 1
/// How long it takes to rev (vrrm vrrm!)
COOLDOWN_DECLARE(enginesound_cooldown)
@@ -72,20 +71,20 @@
kidnapped.forceMove(src)
add_occupant(kidnapped, VEHICLE_CONTROL_KIDNAPPED)
-/obj/vehicle/sealed/car/obj_destruction(damage_flag)
+/obj/vehicle/sealed/car/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 3, adminlog = FALSE)
log_message("[src] exploded due to destruction", LOG_ATTACK)
return ..()
/obj/vehicle/sealed/car/relaymove(mob/living/user, direction)
if(is_driver(user) && canmove && (!key_type || istype(inserted_key, key_type)))
- vehicle_move(direction)
+ vehicle_move(user, direction)
return TRUE
-/obj/vehicle/sealed/car/vehicle_move(direction)
- if(!COOLDOWN_CHECK(src, cooldown_vehicle_move))
- return FALSE
- COOLDOWN_START(src, cooldown_vehicle_move, vehicle_move_delay)
+/obj/vehicle/sealed/car/vehicle_move(mob/living/user, direction)
+ . = ..()
+ if(!.)
+ return
if(COOLDOWN_CHECK(src, enginesound_cooldown))
COOLDOWN_START(src, enginesound_cooldown, engine_sound_length)
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index 0883f6de7c386..b398ab8d1ac87 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -22,9 +22,9 @@
desc = "Exosuit"
icon = 'icons/mecha/mecha.dmi'
move_force = MOVE_FORCE_VERY_STRONG
- move_resist = MOVE_FORCE_OVERPOWERING
+ move_resist = MOVE_FORCE_EXCEPTIONALLY_STRONG
resistance_flags = UNACIDABLE|XENO_DAMAGEABLE|PORTAL_IMMUNE|PLASMACUTTER_IMMUNE
- flags_atom = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION
+ atom_flags = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION
max_integrity = 300
soft_armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, FIRE = 100, ACID = 100)
force = 5
@@ -190,13 +190,15 @@
var/ui_y = 600
/// ref to screen object that displays in the middle of the UI
var/atom/movable/screen/mech_view/ui_view
+ ///Current owning faction
+ var/faction
/obj/item/radio/mech //this has to go somewhere
subspace_transmission = TRUE
/obj/vehicle/sealed/mecha/Initialize(mapload)
. = ..()
- ui_view = new(null, src)
+ ui_view = new(null, null, src)
if(enclosed)
internal_tank = new (src)
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(play_stepsound))
@@ -266,7 +268,16 @@
mech_status_hud.remove_from_hud(src)
return ..()
-/obj/vehicle/sealed/mecha/obj_destruction(damage_amount, damage_type, damage_flag)
+/obj/vehicle/sealed/mecha/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
+ if(istype(blame_mob) && blame_mob.ckey)
+ var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[blame_mob.ckey]
+ if(faction == blame_mob.faction)
+ personal_statistics.mechs_destroyed -- //bruh
+ personal_statistics.mission_mechs_destroyed --
+ else
+ personal_statistics.mechs_destroyed ++
+ personal_statistics.mission_mechs_destroyed ++
+
spark_system?.start()
var/mob/living/silicon/ai/unlucky_ais
@@ -368,6 +379,7 @@
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_toggle_lights, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/mech_view_stats, VEHICLE_CONTROL_SETTINGS)
initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/strafe, VEHICLE_CONTROL_DRIVE)
+ initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/reload, VEHICLE_CONTROL_EQUIPMENT)
/obj/vehicle/sealed/mecha/proc/get_mecha_occupancy_state()
if((mecha_flags & SILICON_PILOT) && silicon_icon_state)
@@ -532,7 +544,7 @@
if(internal_damage & MECHA_INT_CONTROL_LOST)
target = pick(view(3,target))
var/mob/living/livinguser = user
- if(!(livinguser in return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)))
+ if(!is_equipment_controller(user))
balloon_alert(user, "wrong seat for equipment!")
return
var/obj/item/mecha_parts/mecha_equipment/selected
diff --git a/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm b/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm
index 1d2a6d4aac35a..c94d6c6d5c8ea 100644
--- a/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm
+++ b/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm
@@ -66,7 +66,7 @@
/obj/vehicle/sealed/mecha/combat/greyscale/mob_try_enter(mob/M)
- if((mecha_flags & MECHA_SKILL_LOCKED) && M.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED)
+ if((mecha_flags & MECHA_SKILL_LOCKED) && M.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN)
balloon_alert(M, "You don't know how to pilot this")
return FALSE
return ..()
diff --git a/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm b/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm
index cb8067cda5551..f1d1f76b3608f 100644
--- a/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm
+++ b/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm
@@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(greyscale_weapons_data, generate_greyscale_weapons_data())
///list of plane masters to apply to owners
var/list/plane_masters = list()
-/atom/movable/screen/mech_builder_view/Initialize(mapload)
+/atom/movable/screen/mech_builder_view/Initialize(mapload, datum/hud/hud_owner)
. = ..()
assigned_map = "mech_preview_[REF(src)]"
set_position(1, 1)
@@ -89,6 +89,7 @@ GLOBAL_LIST_INIT(greyscale_weapons_data, generate_greyscale_weapons_data())
screen_overlay = "mech_computer"
dir = EAST // determines where the mech will pop out, NOT where the computer faces
interaction_flags = INTERACT_OBJ_UI
+ req_access = list(ACCESS_MARINE_MECH)
///current selected name for the mech
var/selected_name = "TGMC Combat Mech"
@@ -175,7 +176,7 @@ GLOBAL_LIST_INIT(greyscale_weapons_data, generate_greyscale_weapons_data())
. = ..()
if(!.)
return
- if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED)
+ if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN)
return FALSE
/obj/machinery/computer/mech_builder/ui_interact(mob/user, datum/tgui/ui)
diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm
index e3599e6ba811e..0cf17b017e182 100644
--- a/code/modules/vehicles/mecha/combat/gygax.dm
+++ b/code/modules/vehicles/mecha/combat/gygax.dm
@@ -27,6 +27,9 @@
/datum/action/vehicle/sealed/mecha/mech_overload_mode
name = "Toggle leg actuators overload"
action_icon_state = "mech_overload_off"
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_MECHABILITY_TOGGLE_ACTUATORS,
+ )
/datum/action/vehicle/sealed/mecha/mech_overload_mode/action_activate(trigger_flags, forced_state = null)
if(!owner || !chassis || !(owner in chassis.occupants))
diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
index 9335569769c4a..282ab096fa4f4 100644
--- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
+++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
@@ -193,13 +193,14 @@
/obj/item/mecha_parts/mecha_equipment/proc/get_snowflake_data()
return list()
-/**
- * Proc for reloading weapons from HTML UI or by AI
- * note that this is old and likely broken code
- */
+///Tries to rearm the module
+/obj/item/mecha_parts/mecha_equipment/proc/attempt_rearm()
+ return FALSE
+
+///Rearms the module
/obj/item/mecha_parts/mecha_equipment/proc/rearm()
return FALSE
-/// AI mech pilot: returns TRUE if the Ai should try to reload the mecha
+///Checks if the module actually need rearming
/obj/item/mecha_parts/mecha_equipment/proc/needs_rearm()
return FALSE
diff --git a/code/modules/vehicles/mecha/equipment/tools/greyscale_tools.dm b/code/modules/vehicles/mecha/equipment/tools/greyscale_tools.dm
index 3fb57b3eefcf8..fe3e1de6ecf83 100644
--- a/code/modules/vehicles/mecha/equipment/tools/greyscale_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/greyscale_tools.dm
@@ -20,13 +20,13 @@
/obj/item/mecha_parts/mecha_equipment/armor/explosive
name = "explosive armor booster"
- desc = "Increases armor against explosions by 50%."
+ desc = "Increases armor against explosions by 25%."
icon_state = "armor_explosive"
iconstate_name = "armor_explosive"
protect_name = "Explosive Armor"
mech_flags = EXOSUIT_MODULE_GREYSCALE
slowdown = 0.3
- armor_mod = list(BOMB = 50)
+ armor_mod = list(BOMB = 25)
/obj/item/mecha_parts/mecha_equipment/generator/greyscale
diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
index 81e2d39142bf9..209c9cadea4e4 100644
--- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
@@ -168,6 +168,8 @@
/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon, mob/user, params)
. = ..()
+ if(.)
+ return
load_fuel(weapon, user)
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(obj/item/stack/sheet/P, mob/user)
diff --git a/code/modules/vehicles/mecha/equipment/weapons/greyscale_weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/greyscale_weapons.dm
index 30de54780b408..ff3981a506622 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/greyscale_weapons.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/greyscale_weapons.dm
@@ -473,7 +473,7 @@
new /obj/effect/temp_visual/xenomorph/afterimage(chassis.loc, chassis)
RegisterSignal(chassis, COMSIG_MOVABLE_POST_THROW, PROC_REF(end_dash))
cutter = source
- chassis.flags_atom |= DIRLOCK
+ chassis.atom_flags |= DIRLOCK
RegisterSignal(chassis, COMSIG_MOVABLE_MOVED, PROC_REF(drop_afterimage))
chassis.throw_at(target, laser_dash_range, 1, flying = TRUE)
return ..()
@@ -492,7 +492,7 @@
chassis.update_icon()
execute_melee(cutter)
cutter = null
- chassis.flags_atom &= ~DIRLOCK
+ chassis.atom_flags &= ~DIRLOCK
///executes a melee attack in the direction that the mech is facing
/obj/item/mecha_parts/mecha_equipment/laser_sword/proc/execute_melee(mob/source, list/modifiers)
diff --git a/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm b/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm
index 10bbd2b5b4d6e..713df84d38521 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/mecha_ammo.dm
@@ -97,7 +97,7 @@
//greyscale mech stuff
/obj/item/mecha_ammo/vendable
w_class = WEIGHT_CLASS_BULKY
- flags_equip_slot = ITEM_SLOT_BACK
+ equip_slot_flags = ITEM_SLOT_BACK
/obj/item/mecha_ammo/vendable/lmg
name = "box of LMG bullets"
diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
index 7e9f9a41c528e..f551f511acbc3 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
@@ -143,21 +143,14 @@
var/obj/vehicle/sealed/mecha/combat/greyscale/grey = chassis
var/datum/mech_limb/head/head = grey.limbs[MECH_GREY_HEAD]
if(head)
- projectile_to_fire.accuracy *= head.accuracy_mod
- var/datum/mech_limb/arm/holding
- if(grey.equip_by_category[MECHA_R_ARM] == src)
- holding = grey.limbs[MECH_GREY_R_ARM]
- else
- holding = grey.limbs[MECH_GREY_L_ARM]
- projectile_to_fire.scatter = max(variance + holding?.scatter_mod, 0)
+ projectile_to_fire.accuracy *= head.accuracy_mod //todo: we can probably just make the accuracy_mod apply directly to the gun like attachments do
projectile_to_fire.projectile_speed = projectile_to_fire.ammo.shell_speed
- if(projectile_to_fire.ammo.flags_ammo_behavior & AMMO_IFF)
- var/iff_signal
- if(ishuman(firer))
- var/mob/living/carbon/human/human_firer = firer
- var/obj/item/card/id/id = human_firer.get_idcard()
- iff_signal = id?.iff_signal
- projectile_to_fire.iff_signal = iff_signal
+ if((projectile_to_fire.ammo.ammo_behavior_flags & AMMO_IFF) && ishuman(firer))
+ var/mob/living/carbon/human/human_firer = firer
+ var/obj/item/card/id/id = human_firer.get_idcard()
+ projectile_to_fire.iff_signal = id?.iff_signal
+ if(firer)
+ projectile_to_fire.def_zone = firer.zone_selected
///actually executes firing when autofire asks for it, returns TRUE to keep firing FALSE to stop
/obj/item/mecha_parts/mecha_equipment/weapon/proc/fire()
@@ -167,15 +160,24 @@
if(dir_target_diff > (MECH_FIRE_CONE_ALLOWED / 2))
return AUTOFIRE_CONTINUE
- var/type_to_spawn = CHECK_BITFIELD(initial(ammotype.flags_ammo_behavior), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile
+ var/type_to_spawn = CHECK_BITFIELD(initial(ammotype.ammo_behavior_flags), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile
var/obj/projectile/projectile_to_fire = new type_to_spawn(get_turf(src), initial(ammotype.hitscan_effect_icon))
projectile_to_fire.generate_bullet(GLOB.ammo_list[ammotype])
apply_weapon_modifiers(projectile_to_fire, current_firer)
- var/firing_angle = get_angle_with_scatter(chassis, current_target, projectile_to_fire.scatter, projectile_to_fire.p_x, projectile_to_fire.p_y)
+ var/proj_scatter = variance
+ if(istype(chassis, /obj/vehicle/sealed/mecha/combat/greyscale))
+ var/obj/vehicle/sealed/mecha/combat/greyscale/grey = chassis
+ var/datum/mech_limb/arm/holding
+ if(grey.equip_by_category[MECHA_R_ARM] == src)
+ holding = grey.limbs[MECH_GREY_R_ARM]
+ else
+ holding = grey.limbs[MECH_GREY_L_ARM]
+ proj_scatter += holding.scatter_mod //todo: we can probably just make the scatter_modmod apply directly to the gun like attachments do
+ var/firing_angle = get_angle_with_scatter(chassis, current_target, max(proj_scatter, 0), projectile_to_fire.p_x, projectile_to_fire.p_y)
playsound(chassis, fire_sound, 25, TRUE)
- projectile_to_fire.fire_at(current_target, chassis, null, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED))
+ projectile_to_fire.fire_at(current_target, current_firer, chassis, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED))
chassis.use_power(energy_drain)
chassis.log_message("Fired from [name], targeting [current_target] at [AREACOORD(current_target)].", LOG_ATTACK)
@@ -270,11 +272,16 @@
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(action == "reload")
- var/mob/occupant = usr
- if(occupant && !do_after(occupant, rearm_time, IGNORE_HELD_ITEM, chassis, BUSY_ICON_GENERIC))
- return FALSE
- rearm()
- return TRUE
+ return attempt_rearm(usr)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/attempt_rearm(mob/living/user)
+ if(!needs_rearm())
+ return FALSE
+ if(!projectiles_cache)
+ return FALSE
+ if(user && !do_after(user, rearm_time, IGNORE_HELD_ITEM, chassis, BUSY_ICON_GENERIC))
+ return FALSE
+ return rearm()
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm()
if(projectiles >= initial(projectiles))
@@ -294,7 +301,7 @@
return TRUE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/needs_rearm()
- return projectiles <= 0
+ return projectiles < initial(projectiles)
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/fire()
. = ..()
@@ -306,11 +313,7 @@
if(projectiles > 0)
return
playsound(src, 'sound/weapons/guns/misc/empty_alarm.ogg', 25, 1)
- if(LAZYACCESS(current_firer.do_actions, src) || projectiles_cache < 1)
- return
- if(!do_after(current_firer, rearm_time, IGNORE_HELD_ITEM, chassis, BUSY_ICON_GENERIC))
- return
- rearm()
+ attempt_rearm(current_firer)
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine
name = "\improper FNX-99 \"Hades\" Carbine"
diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm
index de5f7577e829d..c96fc83b39e5c 100644
--- a/code/modules/vehicles/mecha/mech_bay.dm
+++ b/code/modules/vehicles/mecha/mech_bay.dm
@@ -117,7 +117,7 @@
if(!recharging_mech)
return data
- data["recharge_port"]["mech"] = list("health" = recharging_mech.obj_integrity, "maxhealth" = recharging_mech.max_integrity, "cell" = null, "name" = recharging_mech.name,)
+ data["recharge_port"]["mech"] = list("health" = recharging_mech.obj_integrity, "maxhealth" = recharging_mech.max_integrity, "cell" = null, "name" = recharging_mech.name)
if(QDELETED(recharging_mech.cell))
return data
diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm
index 8b791b96f0d8c..0799ec056b739 100644
--- a/code/modules/vehicles/mecha/mecha_actions.dm
+++ b/code/modules/vehicles/mecha/mecha_actions.dm
@@ -83,7 +83,6 @@
chassis.ui_interact(owner)
-
/datum/action/vehicle/sealed/mecha/strafe
name = "Toggle Strafing. Disabled when Alt is held."
action_icon_state = "strafe"
@@ -147,4 +146,20 @@
chassis.balloon_alert(owner, "controlling pilot seat")
chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
- chassis.update_icon_state()
+ chassis.update_appearance()
+
+/datum/action/vehicle/sealed/mecha/reload
+ name = "Reload equipped weapons"
+ action_icon_state = "reload"
+ keybinding_signals = list(
+ KEYBINDING_NORMAL = COMSIG_MECHABILITY_RELOAD,
+ )
+
+/datum/action/vehicle/sealed/mecha/reload/action_activate(trigger_flags)
+ if(!owner || !chassis || !(owner in chassis.occupants))
+ return
+
+ for(var/i in chassis.equip_by_category)
+ if(!istype(chassis.equip_by_category[i], /obj/item/mecha_parts/mecha_equipment))
+ continue
+ INVOKE_ASYNC(chassis.equip_by_category[i], TYPE_PROC_REF(/obj/item/mecha_parts/mecha_equipment, attempt_rearm), owner)
diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm
index eb551fe667ddc..bb534774dff39 100644
--- a/code/modules/vehicles/mecha/mecha_defense.dm
+++ b/code/modules/vehicles/mecha/mecha_defense.dm
@@ -36,7 +36,7 @@
to_chat(occupants, "[icon2html(src, occupants)][span_danger("[gear] is critically damaged!")]")
playsound(src, gear.destroy_sound, 50)
-/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration)
+/obj/vehicle/sealed/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = TRUE, attack_dir, armour_penetration, mob/living/blame_mob)
var/damage_taken = ..()
if(damage_taken <= 0 || obj_integrity < 0)
return damage_taken
@@ -81,20 +81,29 @@
log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red")
if(CHECK_BITFIELD(resistance_flags, INDESTRUCTIBLE))
return
- if(!(flags_atom & PREVENT_CONTENTS_EXPLOSION))
+ if(!(atom_flags & PREVENT_CONTENTS_EXPLOSION))
contents_explosion(severity)
if(QDELETED(src))
return
+ var/stagger_duration
switch(severity)
if(EXPLODE_DEVASTATE)
take_damage(rand(1200, 1800), BRUTE, BOMB, 0)
+ stagger_duration = 7 SECONDS
if(EXPLODE_HEAVY)
take_damage(rand(400, 600), BRUTE, BOMB, 0)
+ stagger_duration = 5 SECONDS
if(EXPLODE_LIGHT)
take_damage(rand(150, 300), BRUTE, BOMB, 0)
+ stagger_duration = 2 SECONDS
if(EXPLODE_WEAK)
take_damage(rand(50, 100), BRUTE, BOMB, 0)
+ if(!stagger_duration)
+ return
+ for(var/mob/living/living_occupant AS in occupants)
+ living_occupant.Stagger(stagger_duration)
+
/* RUTGMC DELETION, moved to modular
/obj/vehicle/sealed/mecha/contents_explosion(severity)
severity--
@@ -150,6 +159,12 @@
cookedalive.adjust_fire_stacks(1)
cookedalive.IgniteMob()
+/obj/vehicle/sealed/mecha/lava_act()
+ if(resistance_flags & INDESTRUCTIBLE)
+ return FALSE
+ take_damage(80, BURN, FIRE, armour_penetration = 30)
+ return TRUE
+
/obj/vehicle/sealed/mecha/attackby_alternate(obj/item/weapon, mob/user, params)
if(istype(weapon, /obj/item/mecha_parts))
var/obj/item/mecha_parts/parts = weapon
@@ -224,7 +239,7 @@
if(!attacking_item.force)
return
- var/damage_taken = take_damage(attacking_item.force, attacking_item.damtype, MELEE, 1)
+ var/damage_taken = take_damage(attacking_item.force, attacking_item.damtype, MELEE, attack_dir = get_dir(src, attacking_item), blame_mob = user)
try_damage_component(damage_taken, user.zone_selected)
var/hit_verb = length(attacking_item.attack_verb) ? "[pick(attacking_item.attack_verb)]" : "hit"
@@ -238,7 +253,7 @@
log_combat(user, src, "attacked", attacking_item)
log_message("Attacked by [user]. Item - [attacking_item], Damage - [damage_taken]", LOG_MECHA)
-/obj/vehicle/sealed/mecha/attack_generic(mob/user, damage_amount, damage_type, damage_flag, effects, armor_penetration)
+/obj/vehicle/sealed/mecha/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = 0)
. = ..()
if(.)
try_damage_component(., user.zone_selected)
diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm
index 513217edafad3..1daff10bd295b 100644
--- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm
+++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm
@@ -56,6 +56,7 @@
hud_type.add_to_hud(src)
else
hud_type.remove_from_hud(src)
+ faction = newoccupant.faction //we do not unset when exiting, last occupant is the owner
if(!internal_damage)
SEND_SOUND(newoccupant, sound('sound/mecha/nominal.ogg',volume=50))
diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm
index d2f2e03730cd4..928323d6ac0e6 100644
--- a/code/modules/vehicles/mecha/mecha_movement.dm
+++ b/code/modules/vehicles/mecha/mecha_movement.dm
@@ -22,12 +22,12 @@
. = TRUE
if(!canmove || !(user in return_drivers()))
return
- vehicle_move(direction)
+ vehicle_move(user, direction)
-/obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE)
- if(!COOLDOWN_CHECK(src, cooldown_vehicle_move))
- return FALSE
- COOLDOWN_START(src, cooldown_vehicle_move, move_delay)
+/obj/vehicle/sealed/mecha/vehicle_move(mob/living/user, direction, forcerotate = FALSE)
+ . = ..()
+ if(!.)
+ return
if(completely_disabled)
return FALSE
if(!direction)
diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm
index c3b44719b8311..5091dbc93f09b 100644
--- a/code/modules/vehicles/mecha/mecha_ui.dm
+++ b/code/modules/vehicles/mecha/mecha_ui.dm
@@ -10,7 +10,7 @@
///list of plane masters to apply to owners
var/list/plane_masters = list()
-/atom/movable/screen/mech_view/Initialize(mapload, obj/vehicle/sealed/mecha/newowner)
+/atom/movable/screen/mech_view/Initialize(mapload, datum/hud/hud_owner, obj/vehicle/sealed/mecha/newowner)
. = ..()
owner = newowner
assigned_map = "mech_view_[REF(owner)]"
diff --git a/code/modules/vehicles/motorbike.dm b/code/modules/vehicles/motorbike.dm
index e95fbd25887a5..614312a406afe 100644
--- a/code/modules/vehicles/motorbike.dm
+++ b/code/modules/vehicles/motorbike.dm
@@ -8,7 +8,7 @@
max_integrity = 300
soft_armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 30, FIRE = 60, ACID = 60)
resistance_flags = XENO_DAMAGEABLE
- flags_atom = PREVENT_CONTENTS_EXPLOSION
+ atom_flags = PREVENT_CONTENTS_EXPLOSION
key_type = null
integrity_failure = 0.5
allow_pass_flags = PASSABLE
@@ -82,6 +82,8 @@
/obj/vehicle/ridden/motorbike/attackby(obj/item/I, mob/user, params)
. = ..()
+ if(.)
+ return
if(istype(I, /obj/item/reagent_containers/jerrycan))
var/obj/item/reagent_containers/jerrycan/gascan = I
if(gascan.reagents.total_volume == 0)
@@ -176,7 +178,7 @@
smoke.set_up(0, src)
smoke.start()
-/obj/vehicle/ridden/motorbike/obj_destruction()
+/obj/vehicle/ridden/motorbike/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
explosion(src, light_impact_range = 2, flash_range = 0)
return ..()
@@ -197,9 +199,6 @@
if(user.lying_angle || user.incapacitated()) //Can't use your inventory when lying
return FALSE
- if(istype(user.loc, /obj/vehicle/multitile/root/cm_armored)) //Stops inventory actions in a mech/tank
- return FALSE
-
if(over_object == user && Adjacent(user)) //This must come before the screen objects only block
open(user)
return FALSE
diff --git a/code/modules/vehicles/multitile/cm_armored.dm b/code/modules/vehicles/multitile/cm_armored.dm
deleted file mode 100644
index ded3f67384960..0000000000000
--- a/code/modules/vehicles/multitile/cm_armored.dm
+++ /dev/null
@@ -1,809 +0,0 @@
-
-//NOT bitflags, just global constant values
-#define HDPT_PRIMARY "primary"
-#define HDPT_SECDGUN "secondary"
-#define HDPT_SUPPORT "support"
-#define HDPT_ARMOR "armor"
-#define HDPT_TREADS "treads"
-
-//Percentages of what hardpoints take what damage, e.g. armor takes 37.5% of the damage
-GLOBAL_LIST_INIT(armorvic_dmg_distributions, list(
- HDPT_PRIMARY = 0.15,
- HDPT_SECDGUN = 0.125,
- HDPT_SUPPORT = 0.075,
- HDPT_ARMOR = 0.5,
- HDPT_TREADS = 0.15))
-
-//The main object, should be an abstract class // todo delete me
-/obj/vehicle/multitile/root/cm_armored
- name = "Armored Vehicle"
- desc = "Get inside to operate the vehicle."
- hitbox_type = /obj/vehicle/multitile/hitbox/cm_armored //Used for emergencies and respawning hitboxes
-
- //What slots the vehicle can have
- var/list/hardpoints = list(HDPT_ARMOR, HDPT_TREADS, HDPT_SECDGUN, HDPT_SUPPORT, HDPT_PRIMARY)
-
- //The next world.time when the tank can move
- var/next_move = 0
-
- //Below are vars that can be affected by hardpoints, generally used as ratios or decisecond timers
-
- move_delay = 30 //default 3 seconds per tile
-
- var/active_hp
-
- var/list/dmg_distribs = list()
-
- //Changes cooldowns and accuracies
- var/list/misc_ratios = list(
- "move" = 1.0,
- "prim_acc" = 1.0,
- "secd_acc" = 1.0,
- "supp_acc" = 1.0,
- "prim_cool" = 1.0,
- "secd_cool" = 1.0,
- "supp_cool" = 1.0)
-
- //Changes how much damage the tank takes
- var/list/dmg_multipliers = list(
- "all" = 1.0, //for when you want to make it invincible
- "acid" = 1.0,
- "slash" = 1.0,
- "bullet" = 1.0,
- "explosive" = 1.0,
- "blunt" = 1.0,
- "abstract" = 1.0) //abstract for when you just want to hurt it
-
- //Decisecond cooldowns for the slots
- var/list/internal_cooldowns = list(
- "primary" = 300,
- "secondary" = 200,
- "support" = 150)
-
- //Percentage accuracies for slot
- var/list/accuracies = list(
- "primary" = 0.97,
- "secondary" = 0.67,
- "support" = 0.5)
-
- //Placeholders
- icon = 'icons/obj/vehicles.dmi'
- icon_state = "cargo_engine"
-
-
-/obj/vehicle/multitile/root/cm_armored/Initialize(mapload)
- . = ..()
- GLOB.tank_list += src
- set_light(0.01)
-
-
-/obj/vehicle/multitile/root/cm_armored/Destroy()
- for(var/i in linked_objs)
- var/obj/O = linked_objs[i]
- if(O == src)
- continue
- qdel(O, TRUE) //Delete all of the hitboxes etc
- GLOB.tank_list -= src
- return ..()
-
-//What to do if all ofthe installed modules have been broken
-/obj/vehicle/multitile/root/cm_armored/proc/handle_all_modules_broken()
- return
-
-/obj/vehicle/multitile/root/cm_armored/proc/deactivate_all_hardpoints()
- var/list/slots = get_activatable_hardpoints()
- for(var/slot in slots)
- var/obj/item/hardpoint/HP = hardpoints[slot]
- HP?.deactivate()
-
-/obj/vehicle/multitile/root/cm_armored/proc/remove_all_players()
- return
-
-//The basic vehicle code that moves the tank, with movement delay implemented
-/obj/vehicle/multitile/root/cm_armored/relaymove(mob/user, direction)
- if(world.time < next_move)
- return
- next_move = world.time + move_delay * misc_ratios["move"]
-
- return ..()
-
-//Same thing but for rotations
-/obj/vehicle/multitile/root/cm_armored/try_rotate(deg, mob/user, force = FALSE)
- if(world.time < next_move && !force)
- return
- next_move = world.time + move_delay * misc_ratios["move"] * (force ? 2 : 3) //3 for a 3 point turn, idk
- return ..()
-
-/obj/vehicle/multitile/root/cm_armored/proc/can_use_hp(mob/M)
- return TRUE
-
-//Used by the gunner to swap which module they are using
-//e.g. from the minigun to the smoke launcher
-//Only the active hardpoint module can be used
-/obj/vehicle/multitile/root/cm_armored/verb/switch_active_hp()
- set name = "Change Active Weapon"
- set category = "Vehicle"
- set src in view(0)
-
- if(!can_use_hp(usr))
- return
-
- var/list/slots = get_activatable_hardpoints()
-
- if(!length(slots))
- to_chat(usr, span_warning("All of the modules can't be activated or are broken."))
- return
-
- var/slot = tgui_input_list(usr, "Select a slot.", null, slots)
-
- var/obj/item/hardpoint/HP = hardpoints[slot]
- if(!(HP?.obj_integrity))
- to_chat(usr, span_warning("That module is either missing or broken."))
- return
-
- active_hp = slot
- to_chat(usr, span_notice("You select the [slot] slot."))
- if(isliving(usr))
- var/mob/living/M = usr
- M.set_interaction(src)
-
-/obj/vehicle/multitile/root/cm_armored/verb/reload_hp()
- set name = "Reload Active Weapon"
- set category = "Vehicle"
- set src in view(0)
-
- if(!can_use_hp(usr))
- return
-
- //TODO: make this a proc so I don't keep repeating this code
- var/list/slots = get_activatable_hardpoints()
-
- if(!length(slots))
- to_chat(usr, span_warning("All of the modules can't be reloaded or are broken."))
- return
-
- var/slot = tgui_input_list(usr, "Select a slot.", null, slots)
-
- var/obj/item/hardpoint/HP = hardpoints[slot]
- if(!length(HP?.backup_clips))
- to_chat(usr, span_warning("That module is either missing or has no remaining backup clips."))
- return
-
- var/obj/item/ammo_magazine/A = HP.backup_clips[1] //LISTS START AT 1 REEEEEEEEEEEE
- if(!A)
- to_chat(usr, span_danger("Something went wrong! PM a staff member! Code: T_RHPN"))
- return
-
- to_chat(usr, span_notice("You begin reloading the [slot] module."))
-
- addtimer(CALLBACK(src, PROC_REF(finish_reloading_hp), usr, HP, A, slot), 2 SECONDS)
-
-/obj/vehicle/multitile/root/cm_armored/proc/finish_reloading_hp(mob/living/user, obj/item/hardpoint/HP, obj/item/ammo_magazine/A, slot)
- if(!can_use_hp(usr))
- return
-
- HP.ammo.forceMove(get_turf(entrance))
- HP.ammo.update_icon()
- HP.ammo = A
- HP.backup_clips.Remove(A)
-
- to_chat(usr, span_notice("You reload the [slot] module."))
-
-
-/obj/vehicle/multitile/root/cm_armored/proc/get_activatable_hardpoints()
- var/list/slots = list()
- for(var/slot in hardpoints)
- var/obj/item/hardpoint/HP = hardpoints[slot]
- if(!(HP?.obj_integrity))
- continue
- if(!HP.is_activatable)
- continue
- slots += slot
-
- return slots
-
-
-
-//Special armored vic healthcheck that mainly updates the hardpoint states
-/obj/vehicle/multitile/root/cm_armored/proc/healthcheck()
- repair_damage(max_integrity) //The tank itself doesn't take damage
- var/i
- var/remove_person = TRUE //Whether or not to call handle_all_modules_broken()
- for(i in hardpoints)
- var/obj/item/hardpoint/H = hardpoints[i]
- if(!H)
- continue
- if(!H.obj_integrity)
- H.remove_buff()
- else
- remove_person = FALSE //if something exists but isnt broken
-
- if(remove_person)
- handle_all_modules_broken()
-
- update_icon()
-
-//Since the vics are 3x4 we need to swap between the two files with different dimensions
-//Also need to offset to center the tank about the root object
-/obj/vehicle/multitile/root/cm_armored/update_icon()
-
- overlays.Cut()
-
- //Assuming 3x3 with half block overlaps in the tank's direction
- if(dir in list(NORTH, SOUTH))
- pixel_x = -32
- pixel_y = -48
- icon = 'icons/obj/vehicles/tank_NS.dmi'
-
- else if(dir in list(EAST, WEST))
- pixel_x = -48
- pixel_y = -32
- icon = 'icons/obj/vehicles/tank_EW.dmi'
-
- //Basic iteration that snags the overlay from the hardpoint module object
- for(var/i in hardpoints)
- var/obj/item/hardpoint/H = hardpoints[i]
-
- if((i == HDPT_TREADS && !H) || (H && !H.obj_integrity)) //Treads not installed or broken
- var/image/I = image(icon, icon_state = "damaged_hardpt_[i]")
- overlays += I
-
- if(H)
- var/image/I = H.get_icon_image(0, 0, dir)
- overlays += I
-
-//Hitboxes but with new names
-/obj/vehicle/multitile/hitbox/cm_armored
- name = "Armored Vehicle"
- desc = "Get inside to operate the vehicle."
- allow_pass_flags = PASSABLE
- var/lastsound = 0
-
-//If something want to delete this, it's probably either an admin or the shuttle
-//If it's an admin, they want to disable this
-//If it's the shuttle, it should do damage
-//If fully repaired and moves at least once, the broken hitboxes will respawn according to multitile.dm
-/obj/vehicle/multitile/hitbox/cm_armored/Destroy()
- var/obj/vehicle/multitile/root/cm_armored/C = root
- C?.take_damage_type(1000000, "abstract")
- return ..()
-
-//Tramplin' time, but other than that identical
-/obj/vehicle/multitile/hitbox/cm_armored/Bump(atom/A)
- . = ..()
- var/facing = get_dir(src, A)
- var/turf/temp = loc
- var/turf/T = loc
- A.tank_collision(src, facing, T, temp)
- if(isliving(A))
- log_attack("[get_driver()] drove over [A] with [root]")
-
-
-/obj/vehicle/multitile/hitbox/cm_armored/proc/get_driver()
- return "Someone"
-
-/atom/proc/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- return
-
-/mob/living/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- if(stat == DEAD) //We don't care about the dead
- return
- if(loc == C.loc) // treaded over.
- ParalyzeNoChain(2 SECONDS)
- var/target_dir = REVERSE_DIR(C.dir)
- temp = get_step(C.loc, target_dir)
- T = temp
- target_dir = REVERSE_DIR(C.dir)
- T = get_step(T, target_dir)
- face_atom(T)
- throw_at(T, 3, 2, C, 1)
- apply_damage(randfloat(5, 7.5), BRUTE, blocked = MELEE)
- return
- if(!lying_angle)
- temp = get_step(T, facing)
- T = temp
- T = get_step(T, pick(GLOB.cardinals))
- if(mob_size == MOB_SIZE_BIG)
- throw_at(T, 3, 2, C, 0)
- else
- throw_at(T, 3, 2, C, 1)
- ParalyzeNoChain(2 SECONDS)
- apply_damage(rand(10, 15), BRUTE, blocked = MELEE)
- visible_message(span_danger("[C] bumps into [src], throwing [p_them()] away!"), span_danger("[C] violently bumps into you!"))
- var/obj/vehicle/multitile/root/cm_armored/CA = C.root
- var/list/slots = CA.get_activatable_hardpoints()
- for(var/slot in slots)
- var/obj/item/hardpoint/H = CA.hardpoints[slot]
- H?.livingmob_interact(src)
-
-/mob/living/carbon/xenomorph/queen/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- if(lying_angle || loc == C.loc)
- return ..()
- temp = get_step(T, facing)
- T = temp
- T = get_step(T, pick(GLOB.cardinals))
- throw_at(T, 2, 2, C, 0)
- visible_message(span_danger("[C] bumps into [src], pushing [p_them()] away!"), span_danger("[C] bumps into you!"))
-
-/mob/living/carbon/xenomorph/crusher/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- if(lying_angle || loc == C.loc)
- return ..()
- temp = get_step(T, facing)
- T = temp
- T = get_step(T, pick(GLOB.cardinals))
- throw_at(T, 2, 2, C, 0)
- visible_message(span_danger("[C] bumps into [src], pushing [p_them()] away!"), span_danger("[C] bumps into you!"))
-
-/mob/living/carbon/xenomorph/larva/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- if(loc == C.loc) // treaded over.
- ParalyzeNoChain(2 SECONDS)
- apply_damage(randfloat(5, 7.5), BRUTE, blocked = MELEE)
- return
- var/obj/vehicle/multitile/root/cm_armored/CA = C.root
- var/list/slots = CA.get_activatable_hardpoints()
- for(var/slot in slots)
- var/obj/item/hardpoint/H = CA.hardpoints[slot]
- H?.livingmob_interact(src)
-
-/turf/closed/wall/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root
- var/damage = 30
- var/tank_damage = 2
-
- if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing
- var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR]
- if(SP.obj_integrity)
- damage = 45
- tank_damage = 1
-
- take_damage(damage)
- CA.take_damage_type(tank_damage, "blunt", src)
- if(world.time > C.lastsound + 1 SECONDS)
- playsound(src, 'sound/effects/metal_crash.ogg', 35)
- C.lastsound = world.time
-
-/obj/machinery/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root
- var/damage = 30
- var/tank_damage = 2
-
- if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing
- var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR]
- if(SP.obj_integrity)
- damage = 60
- tank_damage = 0
-
- take_damage(damage)
- CA.take_damage_type(tank_damage, "blunt", src)
- if(world.time > C.lastsound + 1 SECONDS)
- visible_message(span_danger("[CA] rams into \the [src]!"))
- playsound(src, 'sound/effects/metal_crash.ogg', 35)
- C.lastsound = world.time
-
-/obj/structure/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root
- var/damage = 30
- var/tank_damage = 2
-
- if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing
- var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR]
- if(SP.obj_integrity)
- damage = 60
- tank_damage = 0
-
- take_damage(damage)
- CA.take_damage_type(tank_damage, "blunt", src)
- if(world.time > C.lastsound + 1 SECONDS)
- visible_message(span_danger("[CA] crushes \the [src]!"))
- playsound(src, 'sound/effects/metal_crash.ogg', 35)
- C.lastsound = world.time
-
-/obj/alien/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- take_damage(40)
-
-/obj/alien/weeds/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp)
- return
-
-/obj/vehicle/multitile/hitbox/cm_armored/Move(atom/A, direction)
-
- for(var/mob/living/M in get_turf(src))
- M.tank_collision(src)
-
- . = ..()
-
- if(.)
- for(var/mob/living/M in get_turf(A))
- M.tank_collision(src)
-
-//Can't hit yourself with your own bullet
-/obj/vehicle/multitile/hitbox/cm_armored/projectile_hit(obj/projectile/proj)
- if(proj.firer == root) //Don't hit our own hitboxes
- return FALSE
-
- return ..()
-
-/obj/vehicle/multitile/hitbox/cm_armored/ex_act(severity)
- return root.ex_act(severity)
-
-/obj/vehicle/multitile/hitbox/cm_armored/attackby(obj/item/I, mob/user, params)
- return root.attackby(I, user, params)
-
-/obj/vehicle/multitile/hitbox/cm_armored/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
- return root.attack_alien(X, damage_amount)
-
-/obj/vehicle/multitile/hitbox/cm_armored/effect_smoke(obj/effect/particle_effect/smoke/S)
- . = ..()
- if(!.)
- return
- if(CHECK_BITFIELD(S.smoke_traits, SMOKE_XENO_ACID))
- var/obj/vehicle/multitile/root/cm_armored/T = root
- T.take_damage_type(30, "acid")
-
-//A bit icky, but basically if you're adjacent to the tank hitbox, you are then adjacent to the root object
-/obj/vehicle/multitile/root/cm_armored/Adjacent(atom/A)
- for(var/i in linked_objs)
- var/obj/vehicle/multitile/hitbox/cm_armored/H = linked_objs[i]
- if(!H)
- continue
- if(get_dist(H, A) <= 1)
- return TRUE //Using get_dist() to avoid hidden code that recurs infinitely here
- return ..()
-
-//Returns the ratio of damage to take, just a housekeeping thing
-/obj/vehicle/multitile/root/cm_armored/proc/get_dmg_multi(type)
- if(!dmg_multipliers.Find(type))
- return 0
- return dmg_multipliers[type] * dmg_multipliers["all"]
-
-//Generic proc for taking damage
-//ALWAYS USE THIS WHEN INFLICTING DAMAGE TO THE VEHICLES
-/obj/vehicle/multitile/root/cm_armored/proc/take_damage_type(damage, type, atom/attacker)
- for(var/i in hardpoints)
- var/obj/item/hardpoint/HP = hardpoints[i]
- if(HP)
- HP.take_damage(HP.obj_integrity - damage * dmg_distribs[i] * get_dmg_multi(type))
-
- healthcheck()
-
- if(istype(attacker, /mob))
- var/mob/M = attacker
- log_attack("[src] took [damage] [type] damage from [M] ([M.client ? M.client.ckey : "disconnected"]).")
- else
- log_attack("[src] took [damage] [type] damage from [attacker].")
-
-/obj/vehicle/multitile/root/cm_armored/projectile_hit(obj/projectile/proj)
- if(proj.firer == src) //Don't hit ourself.
- return FALSE
-
- return ..()
-
-
-//severity 1.0 explosions never really happen so we're gonna follow everyone else's example
-/obj/vehicle/multitile/root/cm_armored/ex_act(severity)
-
- switch(severity)
- if(EXPLODE_DEVASTATE)
- take_damage(rand(250, 350)) //Devastation level explosives are anti-tank and do real damage.
-
- if(EXPLODE_HEAVY)
- take_damage(rand(30, 40)) //Heavy explosions do some damage, but are largely deferred by the armour/bulk.
-
-//Honestly copies some code from the Xeno files, just handling some special cases
-/obj/vehicle/multitile/root/cm_armored/attack_alien(mob/living/carbon/xenomorph/M, damage_amount = M.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
-
- if(M.loc == entrance.loc && M.a_intent == INTENT_HELP)
- handle_player_entrance(M) //will call the get out of tank proc on its own
- return
-
- var/damage = damage_amount
-
- //Somehow we will deal no damage on this attack
- if(!damage)
- playsound(M.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
- M.do_attack_animation(src)
- M.visible_message(span_danger("\The [M] lunges at [src]!"), \
- span_danger("We lunge at [src]!"))
- return FALSE
-
- M.do_attack_animation(src, ATTACK_EFFECT_CLAW)
- playsound(loc, "alien_claw_metal", 25, 1)
-
- M.visible_message(span_danger("\The [M] slashes [src]!"), \
- span_danger("We slash [src]!"))
-
- take_damage_type(damage * ( (isxenoravager(M)) ? 2 : 1 ), "slash", M) //Ravs do a bitchin double damage
- return ..()
-
-//Special case for entering the vehicle without using the verb
-/obj/vehicle/multitile/root/cm_armored/attack_hand(mob/living/user)
- . = ..()
- if(.)
- return
- if(user.loc == entrance.loc)
- handle_player_entrance(user)
- return
-
-
-/obj/vehicle/multitile/root/cm_armored/Entered(atom/movable/A)
- if(istype(A, /obj) && !istype(A, /obj/item/ammo_magazine/tank) && !istype(A, /obj/item/hardpoint))
- A.forceMove(loc)
- return
-
- return ..()
-
-
-//Redistributes damage ratios based off of what things are attached (no armor means the armor doesn't mitigate any damage)
-/obj/vehicle/multitile/root/cm_armored/proc/update_damage_distribs()
- dmg_distribs = GLOB.armorvic_dmg_distributions.Copy() //Assume full installs
- for(var/slot in hardpoints)
- var/obj/item/hardpoint/HP = hardpoints[slot]
- if(!HP)
- dmg_distribs[slot] = 0.0 //Remove empty slots' damage mitigation
- var/acc = 0
- for(var/slot in dmg_distribs)
- var/ratio = dmg_distribs[slot]
- acc += ratio //Get total current ratio applications
- if(acc == 0)
- return
- for(var/slot in dmg_distribs)
- var/ratio = dmg_distribs[slot]
- dmg_distribs[slot] = ratio/acc //Redistribute according to previous ratios for full damage taking, but ignoring empty slots
-
-//Special cases abound, handled below or in subclasses
-/obj/vehicle/multitile/root/cm_armored/attackby(obj/item/O, mob/user)
-
- if(istype(O, /obj/item/hardpoint)) //Are we trying to install stuff?
- var/obj/item/hardpoint/HP = O
- install_hardpoint(HP, user)
-
- else if(istype(O, /obj/item/ammo_magazine)) //Are we trying to reload?
- var/obj/item/ammo_magazine/AM = O
- handle_ammomag_attackby(AM, user)
-
- else if(iswelder(O) || iswrench(O)) //Are we trying to repair stuff?
- handle_hardpoint_repair(O, user)
- update_damage_distribs()
-
- else if(iscrowbar(O)) //Are we trying to remove stuff?
- uninstall_hardpoint(O, user)
-
- else
- . = ..()
- if(!(O.flags_item & NOBLUDGEON))
- take_damage_type(O.force * 0.05, "blunt", user) //Melee weapons from people do very little damage
-
-
-/obj/vehicle/multitile/root/cm_armored/proc/handle_hardpoint_repair(obj/item/O, mob/user)
-
- //Need to the what the hell you're doing
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER)
- user.visible_message(span_notice("[user] fumbles around figuring out what to do with [O] on the [src]."),
- span_notice("You fumble around figuring out what to do with [O] on the [src]."))
- var/fumbling_time = 5 SECONDS * (SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER))
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
- return
-
- //Pick what to repair
- var/slot = tgui_input_list(user, "Select a slot to try and repair", null, hardpoints) //maybe tgui alert ?
- var/obj/item/I = user.get_active_held_item()
- if(!Adjacent(user) || (!iswelder(I) && !iswrench(I)))
- return
-
- var/obj/item/hardpoint/old = hardpoints[slot] //Is there something there already?
-
- if(!old)
- to_chat(user, span_warning("There is nothing installed on that slot."))
- return
-
- if(old.obj_integrity >= old.max_integrity)
- to_chat(user, span_notice("\the [old] is already in perfect conditions."))
- return
-
- //Determine how many 3 second intervals to wait and if you have the right tool
- var/num_delays = 6
- switch(slot)
- if(HDPT_PRIMARY)
- num_delays = 5
- if(!iswelder(I))
- to_chat(user, span_warning("That's the wrong tool. Use a welder."))
- return
- var/obj/item/tool/weldingtool/WT = I
- if(!WT.isOn())
- to_chat(user, span_warning("You need to light your [WT] first."))
- return
-
- if(HDPT_SECDGUN)
- num_delays = 3
- if(!iswrench(I))
- to_chat(user, span_warning("That's the wrong tool. Use a wrench."))
- return
-
- if(HDPT_SUPPORT)
- num_delays = 2
- if(!iswrench(I))
- to_chat(user, span_warning("That's the wrong tool. Use a wrench."))
- return
-
- if(HDPT_ARMOR)
- num_delays = 10
- if(!iswelder(I))
- to_chat(user, span_warning("That's the wrong tool. Use a welder."))
- return
- var/obj/item/tool/weldingtool/WT = I
- if(!WT.isOn())
- to_chat(user, span_warning("You need to light your [WT] first."))
- return
-
- if(HDPT_TREADS)
- if(!iswelder(I))
- to_chat(user, span_warning("That's the wrong tool. Use a welder."))
- return
- var/obj/item/tool/weldingtool/WT = I
- if(!WT.isOn())
- to_chat(user, span_warning("You need to light your [WT] first."))
- return
- WT.remove_fuel(num_delays, user)
-
- user.visible_message(span_notice("[user] starts repairing the [slot] slot on [src]."),
- span_notice("You start repairing the [slot] slot on the [src]."))
-
- if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD, extra_checks = iswelder(O) ? CALLBACK(O, /obj/item/tool/weldingtool/proc/isOn) : null))
- user.visible_message(span_notice("[user] stops repairing the [slot] slot on [src]."),
- span_notice("You stop repairing the [slot] slot on the [src]."))
- return
-
- if(iswelder(O))
- var/obj/item/tool/weldingtool/WT = O
- WT.remove_fuel(num_delays, user)
-
- user.visible_message(span_notice("[user] repairs the [slot] slot on the [src]."),
- span_notice("You repair the [slot] slot on [src]."))
-
- old.repair_damage(old.max_integrity) //We repaired it, good job
- old.apply_buff()
-
- update_icon()
-
-//Relaoding stuff, pretty bare-bones and basic
-/obj/vehicle/multitile/root/cm_armored/proc/handle_ammomag_attackby(obj/item/ammo_magazine/AM, mob/user)
-
- //No skill checks for reloading
- //Maybe I should delineate levels of skill for reloading, installation, and repairs?
- //That would make it easier to differentiate between the two for skills
- //Instead of using MT skills for these procs and TC skills for operation
- //Oh but wait then the MTs would be able to drive fuck that
- var/slot = tgui_input_list(user, "Select a slot to try and refill", null, hardpoints)
- if(!Adjacent(user) || user.get_active_held_item() != AM)
- return
- var/obj/item/hardpoint/HP = hardpoints[slot]
-
- if(!HP)
- to_chat(user, span_warning("There is nothing installed on that slot."))
- return
-
- HP.try_add_clip(AM, user)
-
-//Putting on hardpoints
-//Similar to repairing stuff, down to the time delay
-/obj/vehicle/multitile/root/cm_armored/proc/install_hardpoint(obj/item/hardpoint/HP, mob/user)
-
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER)
- user.visible_message(span_notice("[user] fumbles around figuring out what to do with [HP] on the [src]."),
- span_notice("You fumble around figuring out what to do with [HP] on the [src]."))
- var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER) )
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
- return
-
- var/obj/item/hardpoint/occupied = hardpoints[HP.slot]
-
- if(occupied)
- to_chat(user, span_warning("Remove the previous hardpoint module first."))
- return
-
- user.visible_message(span_notice("[user] begins installing [HP] on the [HP.slot] hardpoint slot on the [src]."),
- span_notice("You begin installing [HP] on the [HP.slot] hardpoint slot on the [src]."))
-
- var/num_delays = 1
-
- switch(HP.slot)
- if(HDPT_PRIMARY)
- num_delays = 5
- if(HDPT_SECDGUN)
- num_delays = 3
- if(HDPT_SUPPORT)
- num_delays = 2
- if(HDPT_ARMOR)
- num_delays = 10
- if(HDPT_TREADS)
- num_delays = 7
-
- if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD))
- user.visible_message(span_warning("[user] stops installing \the [HP] on [src]."), span_warning("You stop installing \the [HP] on [src]."))
- return
-
- if(occupied)
- return
-
- user.visible_message(span_notice("[user] installs \the [HP] on [src]."), span_notice("You install \the [HP] on [src]."))
-
- user.temporarilyRemoveItemFromInventory(HP, 0)
-
- add_hardpoint(HP, user)
-
-//User-orientated proc for taking of hardpoints
-//Again, similar to the above ones
-/obj/vehicle/multitile/root/cm_armored/proc/uninstall_hardpoint(obj/item/O, mob/user)
-
- if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER)
- user.visible_message(span_notice("[user] fumbles around figuring out what to do with [O] on the [src]."),
- span_notice("You fumble around figuring out what to do with [O] on the [src]."))
- var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER) )
- if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED))
- return
-
- var/slot = tgui_input_list(user, "Select a slot to try and remove", null, hardpoints)
- if(!Adjacent(user) || !iscrowbar(user.get_active_held_item()))
- return
-
- var/obj/item/hardpoint/old = hardpoints[slot]
-
- if(!old)
- to_chat(user, span_warning("There is nothing installed there."))
- return
-
- user.visible_message(span_notice("[user] begins removing [old] on the [old.slot] hardpoint slot on [src]."),
- span_notice("You begin removing [old] on the [old.slot] hardpoint slot on [src]."))
-
- var/num_delays = 1
-
- switch(old.slot)
- if(HDPT_PRIMARY)
- num_delays = 5
- if(HDPT_SECDGUN)
- num_delays = 3
- if(HDPT_SUPPORT)
- num_delays = 2
- if(HDPT_ARMOR)
- num_delays = 10
- if(HDPT_TREADS)
- num_delays = 7
-
- if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD))
- user.visible_message(span_warning("[user] stops removing \the [old] on [src]."), span_warning("You stop removing \the [old] on [src]."))
- return
- if(QDELETED(old) || old != hardpoints[slot])
- return
-
- user.visible_message(span_notice("[user] removes \the [old] on [src]."), span_notice("You remove \the [old] on [src]."))
-
- remove_hardpoint(old, user)
-
-//General proc for putting on hardpoints
-//ALWAYS CALL THIS WHEN ATTACHING HARDPOINTS
-/obj/vehicle/multitile/root/cm_armored/proc/add_hardpoint(obj/item/hardpoint/HP, mob/user)
- if(!istype(HP))
- return
- HP.owner = src
- if(HP.obj_integrity)
- HP.apply_buff()
- HP.forceMove(src)
-
- hardpoints[HP.slot] = HP
- update_damage_distribs()
- update_icon()
-
-//General proc for taking off hardpoints
-//ALWAYS CALL THIS WHEN REMOVING HARDPOINTS
-/obj/vehicle/multitile/root/cm_armored/proc/remove_hardpoint(obj/item/hardpoint/old, mob/user)
- old.forceMove(user ? user.loc : entrance.loc)
- old.remove_buff()
- old.owner = null
-
- hardpoints[old.slot] = null
- update_damage_distribs()
- update_icon()
-
-
-
-/obj/vehicle/multitile/root/cm_armored/contents_explosion(severity)
- return
diff --git a/code/modules/vehicles/multitile/hardpoints.dm b/code/modules/vehicles/multitile/hardpoints.dm
deleted file mode 100644
index a238093cc6d4c..0000000000000
--- a/code/modules/vehicles/multitile/hardpoints.dm
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
-All of the hardpoints, for the tank or other
-Currently only has the tank hardpoints
-*/
-
-/obj/item/hardpoint
-
- var/slot //What slot do we attach to?
- var/obj/vehicle/multitile/root/cm_armored/owner //Who do we work for?
-
- icon = 'icons/obj/vehicles/hardpoint_modules.dmi'
- icon_state = "tires" //Placeholder
-
- max_integrity = 100
- w_class = WEIGHT_CLASS_GIGANTIC
-
- var/obj/item/ammo_magazine/tank/ammo
- //If we use ammo, put it here
- var/obj/item/ammo_magazine/tank/starter_ammo
-
- //Strings, used to get the overlay for the armored vic
- var/disp_icon //This also differentiates tank vs apc vs other
- var/disp_icon_state
-
- var/next_use = 0
- var/is_activatable = FALSE
- var/max_angle = 180
- var/point_cost = 0
-
- var/list/backup_clips = list()
- var/max_clips = 1 //1 so they can reload their backups and actually reload once
- var/buyable = TRUE
-
-/obj/item/hardpoint/Initialize(mapload)
- . = ..()
- if(starter_ammo)
- ammo = new starter_ammo
-
-/obj/item/hardpoint/examine(mob/user)
- . = ..()
- var/status = obj_integrity <= 0.1 ? "broken" : "functional"
- var/span_class = obj_integrity <= 0.1 ? "" : ""
- if((user.skills.getRating(SKILL_ENGINEER) >= SKILL_ENGINEER_METAL) || isobserver(user))
- switch(PERCENT(obj_integrity / max_integrity))
- if(0.1 to 33)
- status = "heavily damaged"
- span_class = ""
- if(33.1 to 66)
- status = "damaged"
- span_class = ""
- if(66.1 to 90)
- status = "slighty damaged"
- if(90.1 to 100)
- status = "intact"
- to_chat(user, "[span_class]It's [status].")
-
-/obj/item/hardpoint/attackby(obj/item/W, mob/user)
- if(istype(W, /obj/item/ammo_magazine/tank))
- try_add_clip(W, user)
- return
- if(!iswelder(W) && !iswrench(W))
- return ..()
- if(obj_integrity >= max_integrity)
- to_chat(user, span_notice("[src] is already in perfect conditions."))
- return
- var/repair_delays = 6
- var/obj/item/tool/repair_tool = /obj/item/tool/weldingtool
- switch(slot)
- if(HDPT_PRIMARY)
- repair_delays = 5
- if(HDPT_SECDGUN)
- repair_tool = /obj/item/tool/wrench
- repair_delays = 3
- if(HDPT_SUPPORT)
- repair_tool = /obj/item/tool/wrench
- repair_delays = 2
- if(HDPT_ARMOR)
- repair_delays = 10
- var/obj/item/tool/weldingtool/WT = iswelder(W) ? W : null
- if(!istype(W, repair_tool))
- to_chat(user, span_warning("That's the wrong tool. Use a [WT ? "wrench" : "welder"]."))
- return
- if(WT && !WT.isOn())
- to_chat(user, span_warning("You need to light your [WT] first."))
- return
- user.visible_message(span_notice("[user] starts repairing [src]."),
- span_notice("You start repairing [src]."))
- if(!do_after(user, 3 SECONDS * repair_delays, NONE, src, BUSY_ICON_BUILD))
- user.visible_message(span_notice("[user] stops repairing [src]."),
- span_notice("You stop repairing [src]."))
- return
- if(WT)
- if(!WT.isOn())
- return
- WT.remove_fuel(repair_delays, user)
- user.visible_message(span_notice("[user] finishes repairing [src]."),
- span_notice("You finish repairing [src]."))
- repair_damage(max_integrity)
-
-//Called on attaching, for weapons sets the actual cooldowns
-/obj/item/hardpoint/proc/apply_buff()
- return
-
-//Called when removing, resets cooldown lengths, move delay, etc
-/obj/item/hardpoint/proc/remove_buff()
- return
-
-//Called when you want to activate the hardpoint, such as a gun
-//This can also be used for some type of temporary buff, up to you
-/obj/item/hardpoint/proc/active_effect(atom/A)
- return
-
-/obj/item/hardpoint/proc/deactivate()
- return
-
-/obj/item/hardpoint/proc/livingmob_interact(mob/living/M)
- return
-
-//If our cooldown has elapsed
-/obj/item/hardpoint/proc/is_ready()
- if(world.time < next_use)
- to_chat(usr, span_warning("This module is not ready to be used yet."))
- return FALSE
- if(!obj_integrity)
- to_chat(usr, span_warning("This module is too broken to be used."))
- return FALSE
- return TRUE
-
-/obj/item/hardpoint/proc/try_add_clip(obj/item/ammo_magazine/tank/A, mob/user)
-
- if(!max_clips)
- to_chat(user, span_warning("This module does not have room for additional ammo."))
- return FALSE
- else if(length(backup_clips) >= max_clips)
- to_chat(user, span_warning("The reloader is full."))
- return FALSE
- else if(!istype(A, starter_ammo))
- to_chat(user, span_warning("That is the wrong ammo type."))
- return FALSE
-
- to_chat(user, span_notice("You start loading [A] in [src]."))
-
- var/atom/target = owner ? owner : src
-
- if(!do_after(user, 10, NONE, target) || QDELETED(src))
- to_chat(user, span_warning("Something interrupted you while loading [src]."))
- return FALSE
-
- user.temporarilyRemoveItemFromInventory(A, FALSE)
- user.visible_message(span_notice("[user] loads [A] in [src]"),
- span_notice("You finish loading [A] in \the [src]."), null, 3)
- backup_clips += A
- playsound(user.loc, 'sound/weapons/guns/interact/minigun_cocked.ogg', 25)
- return TRUE
-
-//Returns the image object to overlay onto the root object
-/obj/item/hardpoint/proc/get_icon_image(x_offset, y_offset, new_dir)
-
- var/icon_suffix = "NS"
- var/icon_state_suffix = "0"
-
- if(new_dir in list(NORTH, SOUTH))
- icon_suffix = "NS"
- else if(new_dir in list(EAST, WEST))
- icon_suffix = "EW"
-
- if(!obj_integrity)
- icon_state_suffix = "1"
-
- return image(icon = "[disp_icon]_[icon_suffix]", icon_state = "[disp_icon_state]_[icon_state_suffix]", pixel_x = x_offset, pixel_y = y_offset)
-
-/obj/item/hardpoint/proc/firing_arc(atom/A)
- var/turf/T = get_turf(A)
- if(!T || !owner)
- return FALSE
- var/dx = T.x - owner.x
- var/dy = T.y - owner.y
- var/deg = 0
- switch(owner.dir)
- if(EAST) deg = 0
- if(NORTH) deg = -90
- if(WEST) deg = -180
- if(SOUTH) deg = -270
-
- var/nx = dx * cos(deg) - dy * sin(deg)
- var/ny = dx * sin(deg) + dy * cos(deg)
- if(nx == 0)
- return max_angle >= 90
- var/angle = arctan(ny/nx)
- if(nx < 0)
- angle += 180
- return abs(angle) <= max_angle
-
-//Delineating between slots
-/obj/item/hardpoint/primary
- slot = HDPT_PRIMARY
- is_activatable = TRUE
-
-/obj/item/hardpoint/secondary
- slot = HDPT_SECDGUN
- is_activatable = TRUE
-
-/obj/item/hardpoint/support
- slot = HDPT_SUPPORT
-
-/obj/item/hardpoint/armor
- slot = HDPT_ARMOR
- max_clips = 0
-
-/obj/item/hardpoint/treads
- slot = HDPT_TREADS
- max_clips = 0
- gender = PLURAL
-
-////////////////////
-// PRIMARY SLOTS // START
-////////////////////
-
-/obj/item/hardpoint/primary/cannon
- name = "LTB Cannon"
- desc = "A primary cannon for tanks that shoots explosive rounds"
-
- max_integrity = 500
- point_cost = 100
-
- icon_state = "ltb_cannon"
-
- disp_icon = "tank"
- disp_icon_state = "ltb_cannon"
-
- starter_ammo = /obj/item/ammo_magazine/tank/ltb_cannon
- max_clips = 3
- max_angle = 45
-
-/obj/item/hardpoint/primary/cannon/broken
- obj_integrity = 0
- buyable = FALSE
-
-/obj/item/hardpoint/primary/cannon/apply_buff()
- owner.internal_cooldowns["primary"] = 200
- owner.accuracies["primary"] = 0.97
-
-/obj/item/hardpoint/primary/cannon/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- next_use = world.time + owner.internal_cooldowns["primary"] * owner.misc_ratios["prim_cool"]
- var/obj/item/hardpoint/secondary/towlauncher/HP = owner.hardpoints[HDPT_SECDGUN]
- if(istype(HP))
- HP.next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"]
-
- var/delay = 5
- var/turf/T = get_turf(A)
- if(!T)
- return
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- var/obj/effect/overlay/temp/tank_laser/TL
- if(C.is_zoomed)
- delay = 20
- TL = new /obj/effect/overlay/temp/tank_laser (T)
-
- to_chat(usr, span_warning("Preparing to fire... keep the tank still for [delay * 0.1] seconds."))
-
- if(!do_after(usr, delay, IGNORE_HELD_ITEM, src) || QDELETED(owner))
- to_chat(usr, span_warning("The [name]'s firing was interrupted."))
- qdel(TL)
-
- return
-
- qdel(TL)
-
- if(!prob(owner.accuracies["primary"] * 100 * owner.misc_ratios["prim_acc"]))
- T = get_step(T, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- log_bomber(usr, "fired", src)
- P.fire_at(T, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- playsound(get_turf(src), pick('sound/weapons/guns/fire/tank_cannon1.ogg', 'sound/weapons/guns/fire/tank_cannon2.ogg'), 60, 1)
- ammo.current_rounds--
-
-/obj/item/hardpoint/primary/minigun
- name = "LTAA-AP Minigun"
- desc = "A primary weapon for tanks that spews bullets"
-
- max_integrity = 350
- point_cost = 100
-
- icon_state = "ltaaap_minigun"
-
- disp_icon = "tank"
- disp_icon_state = "ltaaap_minigun"
-
- starter_ammo = /obj/item/ammo_magazine/tank/ltaaap_minigun
- max_angle = 45
-
- //Miniguns don't use a conventional cooldown
- //If you fire quickly enough, the cooldown decreases according to chain_delays
- //If you fire too slowly, you slowly slow back down
- //Also, different sounds play and it sounds sick, thanks Rahlzel
- var/chained = 0 //how many quick succession shots we've fired
- var/list/chain_delays = list(4, 4, 3, 3, 2, 2, 2, 1, 1) //the different cooldowns in deciseconds, sequentially
-
- //MAIN PROBLEM WITH THIS IMPLEMENTATION OF DELAYS:
- //If you spin all the way up and then stop firing, your chained shots will only decrease by 1
- //TODO: Implement a rolling average for seconds per shot that determines chain length without being slow or buggy
- //You'd probably have to normalize it between the length of the list and the actual ROF
- //But you don't want to map it below a certain point probably since seconds per shot would go to infinity
-
- //So, I came back to this and changed it by adding a fixed reset at 1.5 seconds or later, which seems reasonable
- //Now the cutoff is a little abrupt, but at least it exists. --MadSnailDisease
-
-/obj/item/hardpoint/primary/minigun/apply_buff()
- owner.internal_cooldowns["primary"] = 2 //will be overridden, please ignore
- owner.accuracies["primary"] = 0.33
-
-/obj/item/hardpoint/primary/minigun/active_effect(atom/A)
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
- var/S = 'sound/weapons/guns/fire/tank_minigun_start.ogg'
- if(world.time - next_use <= 5)
- chained++ //minigun spins up, minigun spins down
- S = 'sound/weapons/guns/fire/tank_minigun_loop.ogg'
- else if(world.time - next_use >= 15) //Too long of a delay, they restart the chain
- chained = 1
- else //In between 5 and 15 it slows down but doesn't stop
- chained--
- S = 'sound/weapons/guns/fire/tank_minigun_stop.ogg'
- if(chained <= 0)
- chained = 1
-
- next_use = world.time + (chained > length(chain_delays) ? 0.5 : chain_delays[chained]) * owner.misc_ratios["prim_cool"]
- if(!prob(owner.accuracies["primary"] * 100 * owner.misc_ratios["prim_acc"]))
- A = get_step(A, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed)
-
- playsound(get_turf(src), S, 60)
- ammo.current_rounds--
-
-////////////////////
-// PRIMARY SLOTS // END
-////////////////////
-
-/////////////////////
-// SECONDARY SLOTS // START
-/////////////////////
-
-/obj/item/hardpoint/secondary/flamer
- name = "Secondary Flamer Unit"
- desc = "A secondary weapon for tanks that shoots flames"
-
- max_integrity = 300
- point_cost = 100
-
- icon_state = "flamer"
-
- disp_icon = "tank"
- disp_icon_state = "flamer"
-
- starter_ammo = /obj/item/ammo_magazine/tank/flamer
- max_angle = 90
-
-/obj/item/hardpoint/secondary/flamer/apply_buff()
- owner.internal_cooldowns["secondary"] = 20
- owner.accuracies["secondary"] = 0.5
-
-/obj/item/hardpoint/secondary/flamer/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"]
- if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"]))
- A = get_step(A, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- playsound(get_turf(src), 'sound/weapons/guns/fire/tank_flamethrower.ogg', 60, 1)
- ammo.current_rounds--
-
-/obj/item/hardpoint/secondary/towlauncher
- name = "TOW Launcher"
- desc = "A secondary weapon for tanks that shoots rockets"
-
- max_integrity = 500
- point_cost = 100
-
- icon_state = "tow_launcher"
-
- disp_icon = "tank"
- disp_icon_state = "towlauncher"
-
- starter_ammo = /obj/item/ammo_magazine/tank/towlauncher
- max_clips = 1
- max_angle = 90
-
-/obj/item/hardpoint/secondary/towlauncher/apply_buff()
- owner.internal_cooldowns["secondary"] = 150
- owner.accuracies["secondary"] = 0.8
-
-/obj/item/hardpoint/secondary/towlauncher/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- var/delay = 3
- var/turf/T = get_turf(A)
- if(!T)
- return
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- var/obj/effect/overlay/temp/tank_laser/TL
- if(C.is_zoomed)
- delay = 15
- TL = new /obj/effect/overlay/temp/tank_laser (T)
-
- to_chat(usr, span_warning("Preparing to fire... keep the tank still for [delay * 0.1] seconds."))
-
- if(!do_after(usr, delay, IGNORE_HELD_ITEM, src) || QDELETED(owner))
- to_chat(usr, span_warning("The [name]'s firing was interrupted."))
- qdel(TL)
- return
-
- qdel(TL)
-
- next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"]
- var/obj/item/hardpoint/primary/cannon/HP = owner.hardpoints[HDPT_PRIMARY]
- if(istype(HP))
- HP.next_use = world.time + owner.internal_cooldowns["primary"] * owner.misc_ratios["prim_cool"]
-
- if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"]))
- T = get_step(T, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- log_bomber(usr, "fired", src)
- P.fire_at(T, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- ammo.current_rounds--
-
-/obj/item/hardpoint/secondary/m56cupola/broken
- obj_integrity = 0
- buyable = FALSE
-
-/obj/item/hardpoint/secondary/m56cupola/apply_buff()
- owner.internal_cooldowns["secondary"] = 3
- owner.accuracies["secondary"] = 0.7
-
-/obj/item/hardpoint/secondary/m56cupola/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"]
- if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"]))
- A = get_step(A, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- playsound(get_turf(src), pick(list('sound/weapons/guns/fire/smartgun1.ogg', 'sound/weapons/guns/fire/smartgun2.ogg', 'sound/weapons/guns/fire/smartgun3.ogg')), 60, 1)
- ammo.current_rounds--
-
-/obj/item/hardpoint/secondary/grenade_launcher
- name = "Grenade Launcher"
- desc = "A secondary weapon for tanks that shoots grenades"
-
- max_integrity = 500
- point_cost = 25
-
- icon_state = "glauncher"
-
- disp_icon = "tank"
- disp_icon_state = "glauncher"
-
- starter_ammo = /obj/item/ammo_magazine/tank/tank_glauncher
- max_clips = 3
- max_angle = 90
-
-/obj/item/hardpoint/secondary/grenade_launcher/apply_buff()
- owner.internal_cooldowns["secondary"] = 30
- owner.accuracies["secondary"] = 0.4
-
-/obj/item/hardpoint/secondary/grenade_launcher/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"]
- if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"]))
- A = get_step(A, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- log_bomber(usr, "fired", src)
- P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- playsound(get_turf(src), 'sound/weapons/guns/fire/grenadelauncher.ogg', 60, 1)
- ammo.current_rounds--
-/////////////////////
-// SECONDARY SLOTS // END
-/////////////////////
-
-///////////////////
-// SUPPORT SLOTS // START
-///////////////////
-
-/obj/item/hardpoint/support/smoke_launcher
- name = "Smoke Launcher"
- desc = "Launches smoke forward to obscure vision"
-
- max_integrity = 300
- point_cost = 10
-
- icon_state = "slauncher_0"
-
- disp_icon = "tank"
- disp_icon_state = "slauncher"
-
- starter_ammo = /obj/item/ammo_magazine/tank/tank_slauncher
- max_clips = 4
- is_activatable = TRUE
-
-/obj/item/hardpoint/support/smoke_launcher/broken
- obj_integrity = 0
- buyable = FALSE
-
-/obj/item/hardpoint/support/smoke_launcher/apply_buff()
- owner.internal_cooldowns["support"] = 30
- owner.accuracies["support"] = 0.8
-
-/obj/item/hardpoint/support/smoke_launcher/active_effect(atom/A)
-
- if(!(ammo?.current_rounds > 0))
- to_chat(usr, span_warning("This module does not have any ammo."))
- return
-
- next_use = world.time + owner.internal_cooldowns["support"] * owner.misc_ratios["supp_cool"]
- if(!prob(owner.accuracies["support"] * 100 * owner.misc_ratios["supp_acc"]))
- A = get_step(A, pick(GLOB.cardinals))
- var/obj/projectile/P = new
- P.generate_bullet(new ammo.default_ammo)
- P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed)
- playsound(get_turf(src), 'sound/weapons/guns/fire/tank_smokelauncher.ogg', 60, 1)
- ammo.current_rounds--
-
-/obj/item/hardpoint/support/smoke_launcher/get_icon_image(x_offset, y_offset, new_dir)
-
- var/icon_suffix = "NS"
- var/icon_state_suffix = "0"
-
- if(new_dir in list(NORTH, SOUTH))
- icon_suffix = "NS"
- else if(new_dir in list(EAST, WEST))
- icon_suffix = "EW"
-
- if(!obj_integrity)
- icon_state_suffix = "1"
- else if(!(ammo?.current_rounds > 0))
- icon_state_suffix = "2"
-
- return image(icon = "[disp_icon]_[icon_suffix]", icon_state = "[disp_icon_state]_[icon_state_suffix]", pixel_x = x_offset, pixel_y = y_offset)
-
-/obj/item/hardpoint/support/weapons_sensor
- name = "Integrated Weapons Sensor Array"
- desc = "Improves the accuracy and fire rate of all onboard weapons"
-
- max_integrity = 250
- point_cost = 100
- max_clips = 0
-
- icon_state = "warray"
-
- disp_icon = "tank"
- disp_icon_state = "warray"
-
-/obj/item/hardpoint/support/weapons_sensor/apply_buff()
- owner.misc_ratios["prim_cool"] = 0.67
- owner.misc_ratios["secd_cool"] = 0.67
- owner.misc_ratios["supp_cool"] = 0.67
-
- owner.misc_ratios["prim_acc"] = 1.67
- owner.misc_ratios["secd_acc"] = 1.67
- owner.misc_ratios["supp_acc"] = 1.67
-
-/obj/item/hardpoint/support/weapons_sensor/remove_buff()
- owner.misc_ratios["prim_cool"] = 1
- owner.misc_ratios["secd_cool"] = 1
- owner.misc_ratios["supp_cool"] = 1
-
- owner.misc_ratios["prim_acc"] = 1
- owner.misc_ratios["secd_acc"] = 1
- owner.misc_ratios["supp_acc"] = 1
-
-/obj/item/hardpoint/support/overdrive_enhancer
- name = "Overdrive Enhancer"
- desc = "Increases the movement speed of the vehicle it's atached to"
-
- max_integrity = 250
- point_cost = 100
- max_clips = 0
-
- icon_state = "odrive_enhancer"
- is_activatable = TRUE
-
- disp_icon = "tank"
- disp_icon_state = "odrive_enhancer"
-
- var/last_boost
-
-/obj/item/hardpoint/support/overdrive_enhancer/proc/nitros_on(mob/M)
- owner.misc_ratios["move"] = 0.2
- if(M)
- to_chat(M, span_danger("You hit the nitros! RRRRRRRMMMM!!"))
- playsound(M, 'sound/mecha/hydraulic.ogg', 60, 1, vary = 0)
- addtimer(CALLBACK(src, PROC_REF(boost_off)), TANK_OVERDRIVE_BOOST_DURATION)
- addtimer(CALLBACK(src, PROC_REF(boost_ready_notice)), TANK_OVERDRIVE_BOOST_COOLDOWN)
-
-/obj/item/hardpoint/support/overdrive_enhancer/remove_buff()
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- C.verbs -= /obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile
- boost_off()
-
-/obj/item/hardpoint/support/overdrive_enhancer/apply_buff()
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- C.verbs += /obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile
-
-/obj/item/hardpoint/support/overdrive_enhancer/proc/boost_off()
- owner.misc_ratios["move"] = 1
-
-/obj/item/hardpoint/support/overdrive_enhancer/proc/boost_ready_notice()
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- if(C.driver)
- to_chat(C.driver, span_danger("The overdrive nitros are ready for use."))
-
-/obj/item/hardpoint/support/overdrive_enhancer/proc/activate_overdrive()
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- if(!C.driver)
- return
- if(world.time < last_boost + TANK_OVERDRIVE_BOOST_COOLDOWN)
- to_chat(C.driver, span_warning("Your nitro overdrive isn't yet ready. It will be available again in [(last_boost + TANK_OVERDRIVE_BOOST_COOLDOWN - world.time) * 0.1] seconds."))
- return
- last_boost = world.time
- nitros_on(C.driver)
-
-//How to get out, via verb
-/obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile()
- set category = "Vehicle"
- set name = "Activate Overdrive"
- set src in view(0)
-
- if(usr.incapacitated(TRUE))
- return
-
- if(usr != driver)
- to_chat(usr, span_warning("You need to be in the driver seat to use this!"))
- return
-
- var/obj/item/hardpoint/support/overdrive_enhancer/OE = hardpoints[HDPT_SUPPORT]
- if(!istype(OE, /obj/item/hardpoint/support/overdrive_enhancer) || OE.obj_integrity <= 0)
- to_chat(usr, span_warning("The overdrive engine is missing or too badly damaged!"))
- return
- OE.activate_overdrive(usr)
-
-/obj/item/hardpoint/support/artillery_module
- name = "Artillery Module"
- desc = "Allows the gunner to look far into the distance."
-
- max_integrity = 250
- point_cost = 100
- max_clips = 0
-
- is_activatable = TRUE
- var/is_active = FALSE
-
- var/view_buff = "25x25" //This way you can VV for more or less fun
- var/view_tile_offset = 5
-
- icon_state = "artillery"
-
- disp_icon = "tank"
- disp_icon_state = "artillerymod"
-
-/obj/item/hardpoint/support/artillery_module/active_effect(atom/A)
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- if(!C.gunner)
- return
- var/mob/M = C.gunner
- if(!M.client)
- return
- if(is_active)
- M.client.view_size.reset_to_default()
- M.client.pixel_x = 0
- M.client.pixel_y = 0
- is_active = FALSE
- C.is_zoomed = FALSE
- return
- M.client.view_size.reset_to_default()
- is_active = TRUE
- C.is_zoomed = TRUE
- switch(C.dir)
- if(NORTH)
- M.client.pixel_x = 0
- M.client.pixel_y = view_tile_offset * 32
- if(SOUTH)
- M.client.pixel_x = 0
- M.client.pixel_y = -1 * view_tile_offset * 32
- if(EAST)
- M.client.pixel_x = view_tile_offset * 32
- M.client.pixel_y = 0
- if(WEST)
- M.client.pixel_x = -1 * view_tile_offset * 32
- M.client.pixel_y = 0
-
-/obj/item/hardpoint/support/artillery_module/deactivate()
- var/obj/vehicle/multitile/root/cm_armored/tank/C = owner
- if(!ismob(C.gunner))
- return
- var/mob/M = C.gunner
- if(!M.client)
- return
- is_active = FALSE
- M.client.view_size.reset_to_default()
- M.client.pixel_x = 0
- M.client.pixel_y = 0
-
-/obj/item/hardpoint/support/artillery_module/remove_buff()
- deactivate()
-
-/obj/item/hardpoint/support/artillery_module/is_ready()
- if(!obj_integrity)
- to_chat(usr, span_warning("This module is too broken to be used."))
- return FALSE
- return TRUE
-
-///////////////////
-// SUPPORT SLOTS // END
-///////////////////
-
-/////////////////
-// ARMOR SLOTS // START
-/////////////////
-
-/obj/item/hardpoint/armor/ballistic
- name = "Ballistic Armor"
- desc = "Protects the vehicle from high-penetration weapons. Provides some protection against slashing and high impact attacks."
-
- max_integrity = 1000
- point_cost = 100
-
- icon_state = "ballistic_armor"
-
- disp_icon = "tank"
- disp_icon_state = "ballistic_armor"
-
-/obj/item/hardpoint/armor/ballistic/broken
- obj_integrity = 0
- buyable = FALSE
-
-/obj/item/hardpoint/armor/ballistic/apply_buff()
- owner.dmg_multipliers["bullet"] = 0.5
- owner.dmg_multipliers["slash"] = 0.75
- owner.dmg_multipliers["blunt"] = 0.75
- owner.dmg_multipliers["all"] = 0.9
-
-/obj/item/hardpoint/armor/ballistic/remove_buff()
- owner.dmg_multipliers["bullet"] = 1
- owner.dmg_multipliers["slash"] = 1
- owner.dmg_multipliers["blunt"] = 1
- owner.dmg_multipliers["all"] = 1
-
-/obj/item/hardpoint/armor/caustic
- name = "Caustic Armor"
- desc = "Protects vehicles from most types of acid. Provides some protection against slashing and high impact attacks."
-
- max_integrity = 1000
- point_cost = 100
-
- icon_state = "caustic_armor"
-
- disp_icon = "tank"
- disp_icon_state = "caustic_armor"
-
-/obj/item/hardpoint/armor/caustic/apply_buff()
- owner.dmg_multipliers["acid"] = 0.5
- owner.dmg_multipliers["slash"] = 0.75
- owner.dmg_multipliers["blunt"] = 0.75
- owner.dmg_multipliers["all"] = 0.9
-
-/obj/item/hardpoint/armor/caustic/remove_buff()
- owner.dmg_multipliers["acid"] = 1
- owner.dmg_multipliers["slash"] = 1
- owner.dmg_multipliers["blunt"] = 1
- owner.dmg_multipliers["all"] = 1
-
-/obj/item/hardpoint/armor/concussive
- name = "Concussive Armor"
- desc = "Protects the vehicle from high-impact weapons. Provides some protection against ballistic and explosive attacks."
-
- max_integrity = 1000
- point_cost = 100
-
- icon_state = "concussive_armor"
-
- disp_icon = "tank"
- disp_icon_state = "concussive_armor"
-
-/obj/item/hardpoint/armor/concussive/apply_buff()
- owner.dmg_multipliers["blunt"] = 0.5
- owner.dmg_multipliers["explosive"] = 0.75
- owner.dmg_multipliers["ballistic"] = 0.75
- owner.dmg_multipliers["all"] = 0.9
-
-/obj/item/hardpoint/armor/concussive/remove_buff()
- owner.dmg_multipliers["blunt"] = 1
- owner.dmg_multipliers["explosive"] = 1
- owner.dmg_multipliers["ballistic"] = 1
- owner.dmg_multipliers["all"] = 1
-
-/obj/item/hardpoint/armor/paladin
- name = "Paladin Armor"
- desc = "Protects the vehicle from large incoming explosive projectiles. Provides some protection against slashing and high impact attacks."
-
- max_integrity = 1000
- point_cost = 100
-
- icon_state = "paladin_armor"
-
- disp_icon = "tank"
- disp_icon_state = "paladin_armor"
-
-/obj/item/hardpoint/armor/paladin/apply_buff()
- owner.dmg_multipliers["explosive"] = 0.5
- owner.dmg_multipliers["blunt"] = 0.75
- owner.dmg_multipliers["slash"] = 0.75
- owner.dmg_multipliers["all"] = 0.9
-
-/obj/item/hardpoint/armor/paladin/remove_buff()
- owner.dmg_multipliers["explosive"] = 1
- owner.dmg_multipliers["blunt"] = 1
- owner.dmg_multipliers["slash"] = 1
- owner.dmg_multipliers["all"] = 1
-
-/obj/item/hardpoint/armor/snowplow
- name = "Snowplow"
- desc = "Clears a path in the snow for friendlies"
-
- max_integrity = 700
- is_activatable = TRUE
- point_cost = 50
-
- icon_state = "snowplow"
-
- disp_icon = "tank"
- disp_icon_state = "snowplow"
-
-/obj/item/hardpoint/armor/snowplow/livingmob_interact(mob/living/M)
- var/turf/targ = get_step(M, owner.dir)
- targ = get_step(M, owner.dir)
- targ = get_step(M, owner.dir)
- M.throw_at(targ, 4, 2, src, 1)
- M.apply_damage(7 + rand(0, 3), BRUTE, blocked = MELEE)
-
-/////////////////
-// ARMOR SLOTS // END
-/////////////////
-
-/////////////////
-// TREAD SLOTS // START
-/////////////////
-
-/obj/item/hardpoint/treads/standard
- name = "Treads"
- desc = "Integral to the movement of the vehicle"
-
- max_integrity = 500
- point_cost = 25
-
- icon_state = "treads"
-
- disp_icon = "tank"
- disp_icon_state = "treads"
-
-/obj/item/hardpoint/treads/standard/broken
- obj_integrity = 0
- buyable = FALSE
-
-/obj/item/hardpoint/treads/standard/get_icon_image(x_offset, y_offset, new_dir)
- return null //Handled in update_icon()
-
-/obj/item/hardpoint/treads/standard/apply_buff()
- owner.move_delay = 7
-
-/obj/item/hardpoint/treads/standard/remove_buff()
- owner.move_delay = 30
-
-/////////////////
-// TREAD SLOTS // END
-/////////////////
-
-
-///////////////
-// AMMO MAGS // START
-///////////////
-
-//Special ammo magazines for hardpoint modules. Some aren't here since you can use normal magazines on them
-/obj/item/ammo_magazine/tank
- flags_magazine = NONE //No refilling
- var/point_cost = 0
-
-/obj/item/ammo_magazine/tank/ltb_cannon
- name = "LTB Cannon Magazine"
- desc = "A primary armament cannon magazine"
- caliber = CALIBER_86 //Making this unique on purpose
- icon_state = "ltbcannon_4"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/rocket/ltb
- max_rounds = 4
- point_cost = 50
-
-/obj/item/ammo_magazine/tank/ltb_cannon/update_icon()
- icon_state = "ltbcannon_[current_rounds]"
-
-
-/obj/item/ammo_magazine/tank/ltaaap_minigun
- name = "LTAA-AP Minigun Magazine"
- desc = "A primary armament minigun magazine"
- caliber = CALIBER_762X51 //Correlates to miniguns
- icon_state = "painless"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/bullet/minigun
- max_rounds = 500
- point_cost = 25
-
-
-
-/obj/item/ammo_magazine/tank/flamer
- name = "Flamer Magazine"
- desc = "A secondary armament flamethrower magazine"
- caliber = CALIBER_FUEL_THICK //correlates to flamer mags
- icon_state = "flametank_large"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/flamethrower/tank_flamer
- max_rounds = 120
- point_cost = 50
-
-
-
-/obj/item/ammo_magazine/tank/towlauncher
- name = "TOW Launcher Magazine"
- desc = "A secondary armament rocket magazine"
- caliber = CALIBER_84MM //correlates to any rocket mags
- icon_state = "quad_rocket"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/rocket/ap //Fun fact, AP rockets seem to be a straight downgrade from normal rockets. Maybe I'm missing something...
- max_rounds = 5
- point_cost = 100
-
-/obj/item/ammo_magazine/tank/tank_glauncher
- name = "Grenade Launcher Magazine"
- desc = "A secondary armament grenade magazine"
- caliber = CALIBER_40MM
- icon_state = "glauncher_2"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/grenade_container
- max_rounds = 10
- point_cost = 25
-
-
-/obj/item/ammo_magazine/tank/tank_glauncher/update_icon()
- if(current_rounds >= max_rounds)
- icon_state = "glauncher_2"
- else if(current_rounds <= 0)
- icon_state = "glauncher_0"
- else
- icon_state = "glauncher_1"
-
-
-/obj/item/ammo_magazine/tank/tank_slauncher
- name = "Smoke Launcher Magazine"
- desc = "A support armament grenade magazine"
- caliber = CALIBER_40MM
- icon_state = "slauncher_1"
- w_class = WEIGHT_CLASS_GIGANTIC
- default_ammo = /datum/ammo/grenade_container/smoke
- max_rounds = 6
- point_cost = 5
-
-/obj/item/ammo_magazine/tank/tank_slauncher/update_icon()
- icon_state = "slauncher_[current_rounds <= 0 ? "0" : "1"]"
-
-///////////////
-// AMMO MAGS // END
-///////////////
diff --git a/code/modules/vehicles/multitile/multitile.dm b/code/modules/vehicles/multitile/multitile.dm
deleted file mode 100644
index 784a98157affb..0000000000000
--- a/code/modules/vehicles/multitile/multitile.dm
+++ /dev/null
@@ -1,246 +0,0 @@
-
-/*
-A multitile vehicle is made up of 2 types of objects, root and hitbox
-relaymove() only does something for root
-You can inherit and do special stuff for either, but only one will let you move
-Rotations treat root as x = 0, y = 0
-All of the backend for movement will be under root
-
-Vehicles are placed on the map by a spawner or admin verb
-*/
-
-//This was part of an old plan to have a dynamic number of vehicle interiors
-//Turns out that's incredibly fucking dificult, so a fixed number is gonna be the ideal choice
-/*
-/obj/effect/landmark/multitile_starter
- name = "Landmark"
- desc = "Where the interiors for multitiles start spawning"
-*/
-
-/obj/effect/multitile_spawner
-
- var/width = 2
- var/height = 3
- var/spawn_dir = SOUTH
-
-//A hidden marker for where you mount and dismount the vehicle
-//You could have multiple if you wanted
-/obj/effect/multitile_entrance
- name = "Entrance marker"
- desc = "Marker for the entrance of a multitile vehicle."
-
- var/obj/vehicle/multitile/root/master
- invisibility = INVISIBILITY_MAXIMUM
-
-/obj/effect/multitile_entrance/Destroy(force = FALSE)
- if(!force)
- return QDEL_HINT_LETMELIVE
- return ..()
-
-//Always moves where you want it to, no matter what
-/obj/effect/multitile_entrance/Move(atom/A)
- loc = get_turf(A)
- return TRUE
-
-//A basic handoff to the root object to actually deal with attempted player entrance
-/obj/effect/multitile_entrance/verb/enter_multitile()
- set category = "Vehicle"
- set name = "Enter Vehicle"
- set src in view(0)
-
- master.handle_player_entrance(usr)
-
-//Remnant of vehicle interiors
-/*
-/obj/effect/landmark/multitile_exit
- name = "Landmark"
- desc = "Marker for the exit of the interior"
-
- invisibility = INVISIBILITY_MAXIMUM
-
- var/obj/vehicle/multitile/root/master
-*/
-
-/*
-/obj/effect/landmark/multitile_exit/verb/exit_multitile(mob/M)
- set category = "Vehicle"
- set name = "Exit Vehicle"
- set src in master
-
- master.handle_player_exit(M)
-*/
-
-//Super super generic, doesn't really need to exist
-/obj/vehicle/multitile
- name = "multitile vehicle"
- desc = "You shouldn't see this"
-
-/obj/vehicle/multitile/relaymove(mob/user, direction)
- return
-
-//Hitboxes, do notthing but move with the root object and take up space
-//All interactions like bullets or whatever should be passed up to the root object
-/obj/vehicle/multitile/hitbox
- name = "hitbox"
- desc = "Generic multitile vehicle hitbox"
-
- var/obj/vehicle/multitile/root/root
- invisibility = INVISIBILITY_MAXIMUM
-
-/obj/vehicle/multitile/root
- name = "root"
- desc = "Root tile for multitile vehicles"
-
- var/old_dir
-
- var/obj/effect/multitile_entrance/entrance
- //var/obj/effect/landmark/multitile_exit/exit
-
- //Objects that move in accordance with this one
- //Objects indexed by /datum/coords
- //Does not include the root obj
- var/list/linked_objs = list()
-
- //list of turfs that the vehicle was in before
- var/list/old_locs = list()
-
- //list of idle passengers in the vehicle
- //used for any type of APC
- var/list/idle_passengers = list()
- var/max_idle_passengers = 0
-
- //Another remnant of vehicle interiors
- //var/list/interior_data = list()
-
- var/base_icon_type = "" //e.g. "tank" or "apc", used to assign icons to the hitboxes
-
- var/hitbox_type = /obj/vehicle/multitile/hitbox
-
-//How to get out, via verb
-/obj/vehicle/multitile/root/verb/exit_multitile()
- set category = "Vehicle"
- set name = "Exit Vehicle"
- set src in view(0)
-
- if(!usr.incapacitated(TRUE))
- handle_player_exit(usr)
-
-/obj/vehicle/multitile/root/proc/handle_player_exit(mob/M)
- return
-
-/obj/vehicle/multitile/root/proc/handle_player_entrance(mob/living/M)
- if(M.resting || M.buckled || M.incapacitated())
- return FALSE
- return TRUE
-
-/obj/vehicle/multitile/root/proc/handle_harm_attack(mob/living/M)
- if(M.resting || M.buckled || M.incapacitated())
- return FALSE
- return TRUE
-
-//Vebrs for rotations, set up a macro and get turnin
-/obj/vehicle/multitile/root/verb/clockwise_rotate_multitile()
- set category = "Vehicle"
- set name = "Rotate Vehicle Clockwise"
- set src in view(0)
-
- var/mob/M = usr
- try_rotate(-90, M)
-
-/obj/vehicle/multitile/root/verb/counterclockwise_rotate_multitile()
- set category = "Vehicle"
- set name = "Rotate Vehicle Counterclockwise"
- set src in view(0)
-
- var/mob/M = usr
- try_rotate(90, M)
-
-//A wrapper for try_move() that rotates
-/obj/vehicle/multitile/root/proc/try_rotate(deg, mob/user, force = FALSE)
- save_locs()
- rotate_coords(deg)
- if(!try_move(linked_objs, null, TRUE))
- rotate_coords(-1*deg)
- revert_locs()
- return FALSE
-
- update_icon()
- return TRUE
-
-//Called when players try to move from inside the vehicle
-//Another wrapper for try_move()
-/obj/vehicle/multitile/root/relaymove(mob/user, direction)
- if(dir in list(EAST, WEST))
- if(direction == SOUTH)
- return try_rotate( (dir == WEST ? 90 : -90), user, 1)
- else if(direction == NORTH)
- return try_rotate( (dir == EAST ? 90 : -90), user, 1)
-
- else if(dir in list(SOUTH, NORTH))
- if(direction == EAST)
- return try_rotate( (dir == SOUTH ? 90 : -90), user, 1)
- else if(direction == WEST)
- return try_rotate( (dir == NORTH ? 90 : -90), user, 1)
-
- old_dir = dir
- save_locs()
- if(!try_move(linked_objs, direction))
- revert_locs()
- setDir(old_dir)
- return FALSE //Failed movement
-
- setDir(old_dir) //Preserve the direction you're facing when moving backwards
- return TRUE
-
-
-/obj/vehicle/multitile/root/proc/load_hitboxes()
- return
-
-/obj/vehicle/multitile/root/proc/load_entrance_marker()
- return
-
-//Saves where everything is so we can revert
-/obj/vehicle/multitile/root/proc/save_locs()
-
-
-
-//We were unable to move, so revert everything we may have done so far
-/obj/vehicle/multitile/root/proc/revert_locs()
-
-
-//Forces the root object to move so everything can update relative to it
-/obj/vehicle/multitile/root/proc/move_root(direction)
-
- var/turf/T = get_step(loc, direction)
- loc = T
-
-//The REAL guts of multitile movement
-//Here's how this shit works:
-
-//Step 1: Iterate over every associated object and move what can be moved in the right dir
-//Step 2: Save everything that couldn't move in a list
-//Step 3: Recursively try to move those after everything else that can move has done so
-// This is so if one hitbox is blocking another, eventually they will both move
-//Step 4: If on this level of recursion, we couldn't move any more things, we've failed
-//Step 5: Continue steps 1 through 4 until we fail or succeed
-/obj/vehicle/multitile/root/proc/try_move(list/objs, direction, is_rotation = FALSE)
-
- var/list/blocked = list() //What couldn't move this time
-
-
- if(length(blocked) == length(objs))
- return FALSE //No more things can move, return false
-
- else if(length(blocked))
- return try_move(blocked, direction, is_rotation) //Some things moved, retry the others
-
- else if(!length(blocked))
- return TRUE //Everything finished moving, return true
-
- else
- return FALSE //Shouldn't even be possible, so say we failed anyways
-
-//Applies the 2D transformation matrix to the saved coords
-/obj/vehicle/multitile/root/proc/rotate_coords(deg)
-
-
diff --git a/code/modules/vehicles/multitile/tank.dm b/code/modules/vehicles/multitile/tank.dm
deleted file mode 100644
index d7ca9e8d39af2..0000000000000
--- a/code/modules/vehicles/multitile/tank.dm
+++ /dev/null
@@ -1,308 +0,0 @@
-
-//TANKS, HURRAY
-//Read the documentation in cm_armored.dm and multitile.dm before trying to decipher this stuff
-
-
-/obj/vehicle/multitile/root/cm_armored/tank
- name = "\improper M34A2 Longstreet Light Tank"
- desc = "A giant piece of armor with a big gun, you know what to do. Entrance in the back."
-
- icon = 'icons/obj/vehicles/tank_NS.dmi'
- icon_state = "tank_base"
- pixel_x = -32
- pixel_y = -32
-
- var/mob/gunner
- var/mob/driver
-
- var/mob/occupant_exiting
- var/next_sound_play = 0
-
- var/is_zoomed = FALSE
-
- req_access = list()
-
-/obj/effect/multitile_spawner/cm_armored/tank
-
- width = 3
- height = 3
- spawn_dir = EAST
- var/list/spawn_hardpoints = list()
-
-/obj/effect/multitile_spawner/cm_armored/tank/Initialize(mapload)
- . = ..()
- return INITIALIZE_HINT_QDEL
-
-//Spawns a tank that has a bunch of broken hardpoints
-/obj/effect/multitile_spawner/cm_armored/tank/decrepit
- spawn_hardpoints = list(HDPT_PRIMARY = /obj/item/hardpoint/primary/cannon/broken,
- HDPT_SECDGUN = /obj/item/hardpoint/secondary/m56cupola/broken,
- HDPT_SUPPORT = /obj/item/hardpoint/support/smoke_launcher/broken,
- HDPT_ARMOR = /obj/item/hardpoint/armor/ballistic/broken,
- HDPT_TREADS = /obj/item/hardpoint/treads/standard/broken)
-
-/obj/effect/multitile_spawner/cm_armored/tank/fixed
- spawn_hardpoints = list(HDPT_PRIMARY = /obj/item/hardpoint/primary/cannon,
- HDPT_SECDGUN = /obj/item/hardpoint/secondary/m56cupola,
- HDPT_SUPPORT = /obj/item/hardpoint/support/smoke_launcher,
- HDPT_ARMOR = /obj/item/hardpoint/armor/ballistic,
- HDPT_TREADS = /obj/item/hardpoint/treads/standard)
-
-//For the tank, start forcing people out if everything is broken
-/obj/vehicle/multitile/root/cm_armored/tank/handle_all_modules_broken()
- deactivate_all_hardpoints()
-
- if(driver)
- to_chat(driver, span_danger("You dismount to as the smoke and flames start to choke you!"))
- driver.Move(entrance.loc)
- driver.unset_interaction()
- driver = null
- else if(gunner)
- to_chat(gunner, span_danger("You dismount to as the smoke and flames start to choke you!"))
- gunner.Move(entrance.loc)
- gunner.unset_interaction()
- gunner = null
-
-/obj/vehicle/multitile/root/cm_armored/tank/remove_all_players()
- deactivate_all_hardpoints()
- for(var/mob/living/L in (contents + loc.contents))
- if(!entrance) //Something broke, uh oh
- forceMove(get_turf(src))
- else
- forceMove(get_turf(entrance))
- gunner = null
- driver = null
-
-//Let's you switch into the other seat, doesn't work if it's occupied
-/obj/vehicle/multitile/root/cm_armored/tank/verb/switch_seats()
- set name = "Swap Seats"
- set category = "Vehicle"
- set src in view(0)
-
- if(usr.incapacitated())
- return
-
- var/wannabe_trucker = (usr == gunner) ? TRUE : FALSE
- var/neighbour = wannabe_trucker ? driver : gunner
- if(neighbour)
- to_chat(usr, span_notice("There's already someone in the other seat."))
- return
-
- to_chat(usr, span_notice("You start getting into the other seat."))
- addtimer(CALLBACK(src, PROC_REF(seat_switched), wannabe_trucker, usr), 3 SECONDS)
-
-/obj/vehicle/multitile/root/cm_armored/tank/proc/seat_switched(wannabe_trucker, mob/living/user)
-
- var/player = wannabe_trucker ? gunner : driver
- var/challenger = wannabe_trucker ? driver : gunner
- if(QDELETED(user) || user.incapacitated() || player != user)
- return
-
- if(challenger)
- to_chat(usr, span_notice("Someone beat you to the other seat!"))
- return
-
- to_chat(usr, span_notice("You man up the [wannabe_trucker ? "driver" : "gunner"]'s seat."))
-
- if(wannabe_trucker)
- deactivate_all_hardpoints()
- driver = wannabe_trucker ? user : null
- gunner = wannabe_trucker ? null : user
-
-/obj/vehicle/multitile/root/cm_armored/tank/can_use_hp(mob/M)
- if(!M || M != gunner)
- return FALSE
- if(!M.dextrous)
- to_chat(M, span_warning("You don't have the dexterity to do this!"))
- return FALSE
- return !M.incapacitated()
-
-/obj/vehicle/multitile/root/cm_armored/tank/handle_harm_attack(mob/M, mob/occupant)
- . = ..()
- if(!.)
- return
- if(!occupant)
- to_chat(M, span_warning("There is no one on that seat."))
- return
- M.visible_message(span_warning("[M] starts pulling [occupant] out of \the [src]."),
- span_warning("You start pulling [occupant] out of \the [src]. (this will take a while...)"), null, 6)
- var/fumbling_time = 20 SECONDS - 2 SECONDS * M.skills.getRating(SKILL_POLICE) - 2 SECONDS * M.skills.getRating(SKILL_LARGE_VEHICLE)
- if(!do_after(M, fumbling_time, NONE, src, BUSY_ICON_HOSTILE))
- return
- exit_tank(occupant, TRUE, TRUE)
- M.visible_message(span_warning("[M] forcibly pulls [occupant] out of [src]."),
- span_notice("you forcibly pull [occupant] out of [src]."), null, 6)
- if(!isliving(occupant))
- return
- var/mob/living/L = occupant
- L.Paralyze(8 SECONDS)
-
-//Two seats, gunner and driver
-//Must have the skills to do so
-/obj/vehicle/multitile/root/cm_armored/tank/handle_player_entrance(mob/living/carbon/M)
- . = ..()
- if(!. || !istype(M) || M.do_actions)
- return
-
- var/slot = tgui_alert(M, "Select a seat", null, list("Driver", "Gunner"))
- if(!Adjacent(M))
- return
-
- var/occupant = (slot == "Driver") ? driver : gunner
- if((M.a_intent == INTENT_HARM || isxeno(M)) && occupant)
- handle_harm_attack(M, occupant)
- return
-
- if(!M.dextrous)
- to_chat(M, span_warning("You don't have the dexterity to drive [src]!"))
- return
- if(!allowed(M))
- to_chat(M, span_warning("Access denied."))
- return
- if(occupant)
- to_chat(M, span_warning("That seat is already taken."))
- return
- var/obj/item/offhand = M.get_inactive_held_item()
- if(offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & (DELONDROP|ITEM_ABSTRACT))))
- to_chat(M, span_warning("You need your hands free to climb on [src]."))
- return
-
- if(M.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED)
- M.visible_message(span_notice("[M] fumbles around figuring out how to get into the [src]."),
- span_notice("You fumble around figuring out how to get into [src]."))
- var/fumbling_time = 10 SECONDS - 2 SECONDS * M.skills.getRating(SKILL_LARGE_VEHICLE)
- if(!do_after(M, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED) || \
- (offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & DELONDROP))))
- return
-
- to_chat(M, span_notice("You start climbing into [src]."))
- if(!do_after(M, 10 SECONDS, NONE, src, BUSY_ICON_GENERIC) || \
- (offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & DELONDROP))))
- return
- if(occupant)
- to_chat(M, span_warning("Someone got into the [lowertext(slot)]'s seat before you could."))
- return
-
- if(slot == "Driver")
- driver = M
- else
- gunner = M
- M.forceMove(src)
- to_chat(M, span_notice("You enter into the [lowertext(slot)]'s seat."))
- M.set_interaction(src)
-
-//Deposits you onto the exit marker
-/obj/vehicle/multitile/root/cm_armored/tank/handle_player_exit(mob/M)
-
- if(!(M in list(gunner, driver))) //someone whom isn't supposed to be here to begin with.
- exit_tank(M, TRUE)
- return
-
- if(!M.do_actions)
- if(occupant_exiting)
- to_chat(M, span_notice("Someone is already getting out of [src]."))
- return
- occupant_exiting = M
-
- to_chat(M, span_notice("You start climbing out of [src]."))
-
- addtimer(CALLBACK(src, PROC_REF(exit_tank), M), 5 SECONDS)
-
-/obj/vehicle/multitile/root/cm_armored/tank/proc/exit_tank(mob/M, forced = FALSE, silent = FALSE)
- if(!forced)
- occupant_exiting = null
-
- if(!M || get_turf(M) != get_turf(src) || (M.incapacitated() && !forced))
- return
-
- var/turf/T = get_turf(entrance)
- if(!forced)
- if(!T.CanPass(M, T))
- if(!silent)
- to_chat(M, span_notice("Something is blocking you from exiting."))
- return
- for(var/atom/A in T)
- if(A.CanPass(M, T))
- continue
- if(!silent)
- to_chat(M, span_notice("Something is blocking you from exiting."))
- return
- M.forceMove(T)
-
- if(M == gunner)
- deactivate_all_hardpoints()
- gunner = null
- else if(M == driver)
- driver = null
- M.unset_interaction()
- if(!silent)
- to_chat(M, span_notice("You climb out of [src]."))
-
-//No one but the driver can drive
-/obj/vehicle/multitile/root/cm_armored/tank/relaymove(mob/user, direction)
- if(user != driver || user.incapacitated())
- return
-
- . = ..(user, direction)
-
-
-
- if(next_sound_play < world.time)
- playsound(src, 'sound/ambience/tank_driving.ogg', vol = 20, sound_range = 30)
- next_sound_play = world.time + 21
-
-//No one but the driver can turn
-/obj/vehicle/multitile/root/cm_armored/tank/try_rotate(deg, mob/user, force = FALSE)
-
- if(user != driver || user.incapacitated())
- return
-
- . = ..(deg, user, force)
-
- if(. && istype(hardpoints[HDPT_SUPPORT], /obj/item/hardpoint/support/artillery_module) && gunner?.client)
- var/client/C = gunner.client
- var/old_x = C.pixel_x
- var/old_y = C.pixel_y
- C.pixel_x = old_x*cos(deg) - old_y*sin(deg)
- C.pixel_y = old_x*sin(deg) + old_y*cos(deg)
-
-/obj/vehicle/multitile/hitbox/cm_armored/tank/get_driver()
- var/obj/vehicle/multitile/root/cm_armored/tank/T = root
- return T?.driver
-
-
-/obj/vehicle/multitile/root/cm_armored/tank/take_damage_type(damage, type, atom/attacker)
- . = ..()
-
- if(istype(attacker, /mob))
- var/mob/M = attacker
- log_combat(M, src, "damaged [src] with [damage] [type] damage.")
-
- if(gunner)
- log_combat(gunner, null, "[src] took [damage] [type] damage [ismob(attacker) ? "from [key_name(attacker)]" : ""].")
- if(driver)
- log_combat(driver, null, "[src] took [damage] [type] damage [ismob(attacker) ? "from [key_name(attacker)]" : ""].")
-
-
-/obj/vehicle/multitile/root/cm_armored/proc/click_action(A, mob/user, params)
- if(istype(A, /atom/movable/screen) || A == src)
- return FALSE
-
- if(!can_use_hp(user))
- return TRUE
-
- if(!hardpoints.Find(active_hp))
- to_chat(user, span_warning("Please select an active hardpoint first."))
- return TRUE
-
- var/obj/item/hardpoint/HP = hardpoints[active_hp]
-
- if(!HP?.is_ready())
- return TRUE
-
- if(!HP.firing_arc(A))
- to_chat(user, span_warning("The target is not within your firing arc."))
- return TRUE
-
- HP.active_effect(A)
- return TRUE
diff --git a/code/modules/vehicles/multitile/tankvendor.dm b/code/modules/vehicles/multitile/tankvendor.dm
deleted file mode 100644
index 2aee8558ff5ba..0000000000000
--- a/code/modules/vehicles/multitile/tankvendor.dm
+++ /dev/null
@@ -1,290 +0,0 @@
-#define TANKFAB_MAIN_MENU 0
-#define TANKFAB_MOD_MAINT 1
-#define TANKFAB_PRINTER 2
-#define TANKFAB_BUSY 3
-
-
-/obj/machinery/tank_part_fabricator
- name = "tank part fabricator"
- desc = "A large automated 3D printer for producing new tank parts and maintaining old ones."
- density = TRUE
- anchored = TRUE
- use_power = IDLE_POWER_USE
- idle_power_usage = 20
- icon = 'icons/obj/machines/drone_fab.dmi'
- icon_state = "drone_fab_idle"
- var/obj/item/loaded_mod
- var/tank_points = 625
- var/busy = FALSE
- var/screen = TANKFAB_MAIN_MENU
-
-/obj/machinery/tank_part_fabricator/proc/set_busy(business = TRUE, timer)
- busy = business
- if(timer)
- addtimer(CALLBACK(src, PROC_REF(set_busy), !business), timer)
- update_icon()
- updateUsrDialog()
-
-/obj/machinery/tank_part_fabricator/update_icon()
- if(machine_stat & NOPOWER)
- icon_state = "drone_fab_nopower"
- return
- if(busy)
- icon_state = "drone_fab_active"
- return
- else
- icon_state = "drone_fab_idle"
-
-/obj/machinery/tank_part_fabricator/interact(mob/user)
- . = ..()
- if(.)
- return
- var/dat
- if(screen == TANKFAB_BUSY)
- dat += "[src] is busy. Please wait for completion of the current operation..."
- else
- dat += "